OCEOSmp/directive reference
This section is under construction
Introduction
To be added
Directives
Initialisation directives
oceos_init()
Header File
initialisation.h
Description
Initialises OCEOS and must be the first directive used.Initialises the OCEOS system meta data using the information supplied in the application configuration and prepares for creation of tasks etc.
The values provided in the application configuration are checked as much as possible before being used.
The system log also is created here.
This function sets up sysMetaPtr and init_meta_ptr and must have completed successfully before tasks etc. can be created.
It disables interrupts and leaves them disabled, they will be re-enabled to the previous level after all tasks etc. have been created and oceos_init_finish() has completed successfully.
Prototype
/** * Initialises OCEOS and must be the first directive used. * * Initialises the OCEOS system meta data using the information supplied in * the application configuration and prepares for creation of tasks etc. * * The values provided in the application configuration are checked as much * as possible before being used. * * The system log also is created here. * * This function sets up sysMetaPtr and init_meta_ptr and must have completed * successfully before tasks etc. can be created. * * It disables interrupts and leaves them disabled, they will be re-enabled to * the previous level after all tasks etc. have been created and * oceos_init_finish() has completed successfully. * * @param app_config Pointer to configuration struct * @return SUCCESSFUL All OK * WARN_LOG_SIZE_DEFAULT Warning, log size is set to default value of 64 entries * WARN_NO_ERROR_FUNCTION Warning, user defined function for ERROR handling is not provided * ERR_CPU_FIRST_CORE_INVALID Start CPU not in a range of available cores for this target; or greater than end CPU * ERR_CPU_LAST_CORE_INVALID Last CPU not in a range of available cores for this target * ERR_NOT_START_CPU_CORE Executing oceos_init on wrong CPU * ERR_STACK_START_MISALIGNED Stack start address is not set by user misaligned * ERR_STACK_PER_CORE_INVALID Stack per CPU size is zero, or not 8byte aligned, or less then min require * ERR_LOG_ADDR_MISALIGNED Log start address is not 8 byte aligned * ERR_FIX_ADDR_MISALIGNED Fixed area start address is not 8 byte aligned * ERR_DYN_ADDR_MISALIGNED Dynamic area start address is not 8 byte aligned * ERR_CPU_CORE_RANGE_WRONG CPU cores in use exceed available CPUs on the SoC * ERR_STACK_SPACE_WRONG Current CPU SP is not within user provided stack range * ERR_LOG_SIZE_INVALID Log size outside expected range * ERR_CS_LOG_SIZE_INVALID Context switch log size invalid * ERR_TASK_NUMBER_INVALID Number of tasks invalid * ERR_MUTEX_NUMBER_INVALID Number of mutexes invalid * ERR_RWMUTEX_NUMBER_INVALID Number of rwmutexes invalid * ERR_SEM_NUMBER_INVALID Number of semaphores invalid * ERR_DATAQ_NUMBER_INVALID Number of datqs invalid * ERR_TIMED_ACTIONS_NUMBER_INVALID Number of timed actions invalid * ERR_OVERLAP_STACK Overlap stack end address with (two overlap areas are set) * ERR_OVERLAP_LOG Overlap log with (two overlap areas are set) * ERR_OVERLAP_FIXED Overlap fixed area with (two overlap areas are set) * ERR_OVERLAP_DYNAMIC Overlap dynamic area with (two overlap areas are set) * ERR_FIXED_MEMORY_FAILED Fixed area memory write fail * ERR_DYNAMIC_MEMORY_FAILED Dynamic area memory write fail * ERR_TIMER_ADDR_INVALID Timer address not provided by user (null). SPARC only * ERR_SYS_TIMER_INDEX_INVALID System timer index of subtimer invalid; SPARC only; Subtimers start from index 1; Need index of subtimer plus one in front * ERR_PERIPHERAL_CLOCK_INVALID System peripheral code invalid * */ S32_t oceos_init( const struct application_configuration app_config );Parameters
Parameter Description app_config Pointer to configuration struct. struct application_configuration defined in basic_structs.h Returns
This function returns S32_t with one of the status codes defined above.Example Usage
/* * Create the application configuration structure */ struct application_configuration app_config = {0}; /* * Fill in the application parameters */ app_config.log_address = (log_t)log_data; // required app_config.fixed_data_address = (adrs_t)fixed_data; // required app_config.dynamic_data_address = (adrs_t)dynamic_data; // required app_config.stack_start_address = start_stack_array[OCEOS_START_CPU_INDEX];// OCEOSMP_STACK_START_ADDRESS; app_config.stack_size_per_cpu = (U32_t)&__oceos_stack_size_per_cpu; // OCEOSMP_STACK_LOW_BOUND_ADDRESS; app_config.system_error_function = oceosmp_on_error; // NULL => ignore app_config.log_full_function = oceosmp_on_full_log; // NULL => ignore // used in setting up system log and fixed data array app_config.log_number_of_entries = NUMBER_OF_LOG_ENTRIES; // 0 => use default app_config.number_of_tasks = NUMBER_OF_TASKS; // >= 1 app_config.number_of_mutexes = NUMBER_OF_MUTEXES; app_config.number_of_rwmutexes = NUMBER_OF_RWMUTEXES; app_config.number_of_counting_semaphores = NUMBER_OF_SEMAPHORES; app_config.number_of_data_queues = NUMBER_OF_DATAQS; /** * FOR SPARC TARGET ONLY. */ app_config.sys_time_timer_index = SYS_TIME_TIMER_INDEX; // 0 => invalid index /** * FOR SPARC TARGET ONLY. * Not Used for ARM. Always Nested */ app_config.interrupt_nesting_enabled = TRUE; // TRUE => single vector app_config.oceos_cpu_switch_int_number = OCEOS_CPU_INTER_COM_INT_NUMBER; // User should provide SGI ID (0-15) app_config.timed_actions_queue_size = NUMBER_OF_ACTION_ENTRIES; app_config.CS_log_entries_base2 = CS_LOG_DEF_ENTRIES_BASE2; /** * Set starting index of CPU that will be used by OCEOSMP */ app_config.oceos_cpu_start_index = OCEOS_START_CPU_INDEX; /** * Set last index of CPU that will be used by OCEOSMP */ app_config.oceos_cpu_last_index = OCEOS_LAST_CPU_INDEX; /* * Set system/peripheral clock used to initialise system timer */ app_config.soc_peripheral_clck = BSP_SYSFREQ * 1000 * 1000; // initialise OCEOSMP S32_t status; status = oceos_init(app_config); if (OCEOS_SUCCESS > status) { oceosmp_print("\n oceos_init failure\n\r"); return 0; } else { return 1; } // else
oceos_init_finish()
Header File
initialisation.h
Description
Finalizes the fixed data array after all tasks etc. have been createdAll information needed to start OCEOS can be found in the fixed data area when oceos_init_finish() has completed.
Once all tasks etc. have been created oceos_init_finish() checks the accumulated information against the application configuration data stored in the fixed meta structure.
oceos_init_finish also calculates the size of the dynamic data area and checks it does not overlap with the system stack, the system log, or the fixed data, and if all ok sets up pointers to the various dynamic area components in the fixed data.
It then adds an XOR checksum to the fixed data area, and checks that this is followed by FILLER, which it replaces with the end sentinel.
On successful completion it restores the interrupt level to its value before oceos_init() was called, otherwise interrupts remain disabled.
Prototype
/** * Finalizes the fixed data array after all tasks etc. have been created * * All information needed to start OCEOS can be found in the fixed data area * when oceos_init_finish() has completed. * * Once all tasks etc. have been created oceos_init_finish() checks the * accumulated information against the application configuration data * stored in the fixed meta structure. * * oceos_init_finish also calculates the size of the dynamic data area and * checks it does not overlap with the system stack, the system log, or the * fixed data, and if all ok sets up pointers to the various dynamic area * components in the fixed data. * * It then adds an XOR checksum to the fixed data area, and checks that this * is followed by FILLER, which it replaces with the end sentinel. * * On successful completion it restores the interrupt level to its value * before oceos_init() was called, otherwise interrupts remain disabled. * * @return OCEOS_SUCCESS All OK * ERR_SYS_FIXED_CORRUPT System Meta data is NULL or corrupt * ERR_SYS_DYN_CORRUPT System Dynamic area corrupt * ERR_WRONG_CPU_CORE Executing directive on wrong CPU * ERR_WRONG_PHASE Called before oceos_init() * ERR_TASKS_INCOMPLETE Created wrong number of tasks * ERR_MUTEX_INCOMPLETE Created wrong number of mutexes * ERR_RWMUTEX_INCOMPLETE Created wrong number of rwmutexes * ERR_SEM_INCOMPLETE Created wrong number of semaphores * ERR_DATAQ_INCOMPLETE Created wrong number of dataqs * ERR_TASK_MAX_ID_INVALID Task's max id invalid * ERR_MUTEX_MAX_ID_INVALID Mutexe's max id invalid * ERR_RWMUTEX_MAX_ID_INVALID Rwmutexe's max id invalid * ERR_SEM_MAX_ID_INVALID Semaphore's max id invalid * ERR_DATAQ_MAX_ID_INVALID Dataq's max id invalid * ERR_TOTAL_JOBS_NUMBER_WRONG Wrong number of total jobs created * ERR_ORDER_ARRAY_PTR_INVALID Order array pointer is NULL or mis-aligned * ERR_FIXED_AREA_TOO_SMALL Not enough space for fixed data area */ S32_t oceos_init_finish(void);Parameters
There are no input parameters to this function.Returns
This function returns an S32_t with one of the status codes defined above.Example Usage
/* * Finish initialising OCEOS and setting up the fixed data */ status = oceos_init_finish(); if(OCEOS_SUCCESS > status){ // LOG oceosmp_print("\nAbandoning, problem ending OCEOS initialisation\n\r"); return -1; } // if
oceos_start()
Header File
initialisation.h
Description
Starts OCEOS scheduling.
Create dynamic OCEOS structures and start scheduling.
This function should only be called once and only after oceos_init() and oceos_init_finish() have been called successfully.
Normally this function does not return.
If a problem is detected the function terminates and returns an appropriate DIRECTIVE_STATUS code, with interrupts disabled.Prototype
/** * Starts OCEOS scheduling * * Create dynamic OCEOS structures and start scheduling * * This function should only be called once * and only after oceos_init() * and oceos_init_finish() have * been called successfully. * Normally this function does not return. * If a problem is detected the function * terminates and returns an appropriate * DIRECTIVE_STATUS code, with interrupts disabled. * * @param fixed_array_ptr Pointer to fixed data array * @param start_task Task ID * @param data_ptr Pointer to data to be passed to the task * @return OCEOSMP_EXIT OCEOSMP return from scheduling and exit * ERR_SYS_FIXED_CORRUPT Fixed area pointer is null or bad sentinel * ERR_FIXED_AREA_SIZE_WRONG Fixed area size is zero * ERR_FIXED_AREA_END_SENTINEL_BAD Fixed data end sentinel corrupt * ERR_FIXED_AREA_BAD_XOR Fixed area bad checksum or checksum mis-match * ERR_INIT_NOT_DONE oceos_start() called without initialisation * ERR_DYN_AREA_PTR_BAD Dynamic area pointer invalid in sysMetaPtr * ERR_INT_HANDLER_BAD IRQ controller pointer provided by BCC is NULL;or OCEOS handler is not set * ERR_DYN_JOB_PTR_BAD Job array pointer is NULL * ERR_FIXED_TASK_PTR_BAD Tasks array pointer is NULL * ERR_JOB_COUNT_WRONG Total job count inconsistent * ERR_DYN_MUTEX_PTR_BAD Mutex dynamic pointer is NULL * ERR_DYN_LOCK_PTR_BAD Mutex lock array pointer is NULL * ERR_DYN_RWMUTEX_PTR_BAD Rwmutex dynamic pointer is NULL * ERR_DYN_RWLOCK_PTR_BAD Rwmutex lock array pointer is NULL * ERR_FIXED_SEM_PTR_BAD Semaphore fixed pointer is NULL * ERR_DYN_SEM_PTR_BAD Semaphore dynamic pointer is NULL * ERR_SEM_PEND_PTR_BAD Semaphore pending queue pointer is NULL * ERR_FIXED_DATAQ_PTR_BAD Dataq fixed pointer is NULL * ERR_DYN_DATAQ_PTR_BAD Dataq dynamic pointer is NULL * ERR_DATAQ_PEND_PTR_BAD Dataq pending queue pointer is NULL * ERR_DATAQ_DATA_PTR_BAD Dataq data pointer is NULL * ERR_CPU_INT_NUMBER_INVALID SPARC only.IRQ number for CPU inter-comunication invalid(zero or used by timer) * ERR_REGISTER_CPU_IRQ_FAILED SPARC only. Failed to set CPU IRQ handler in BCC * ERR_CPU_STACK_INVALID Current CPU stack not within specified range * ERR_CPU_PRIORITY_STACK_INVALID Per CPU priority stack invalid * ERR_LOG_AREA_END_SENTINEL_BAD Log area end sentinel override * ERR_TA_CONFIG_PTR_BAD SPARC only; Timed action configuration data pointer is NULL * ERR_TA_TIMER_INDEX_INVALID SPARC only; Timed action sub-timer index in timer unit is invalid * ERR_TA_IRQ_NUMBER_INVALID SPARC only; Timer action timer IRQ number is invalid * ERR_TA_BCC_IRQ_REGISTER_FAILED SPARC only; Timed action timer IRQ handler failed to register */ S32_t oceos_start( const U32_t * const fixed_array_ptr,// pointer to fixed data array const U32_t start_task, // taskID void * const data_ptr // pointer to data to be passed to task );Parameters
Parameter Description fixed_array_ptr Pointer to fixed data array start_task Task ID data_ptr Pointer to data to be passed to the task Returns
This function returns S32_t with one of the status codes defined above.
Example Usage
/* Sample Task names - all here start with t_ to help avoid name confusion */ enum TASK_NAME{ t_tom, // will have task ID 0 t_dick, // will have task ID 1 }; extern U32_t fixed_data[]; ... S32_t status; status = oceos_start(fixed_data, t_tom, NULL);
oceos_exit()
Header File
initialisation.h
Description
Ends scheduling and exit from oceos_start(). No task can be started after this.
OCEOS will exit when the current job ends.
An idle task in an endless loop should check that scheduling is enabled.Prototype
/** * Ends scheduling and exit from oceos_start. * No task can be started after this. * OCEOS will exit when the current job ends. * An idle task in an endless loop should check that scheduling is enabled. * * @return OCEOS_SUCCESS * ERR_SYS_FIXED_CORRUPT System Fixed area corrupt * ERR_WRONG_PHASE Called before scheduling started */ S32_t oceos_exit(void);Parameters
There are no input parameters to this function.Returns
This function returns S32_t with one of the status codes defined above.
Example Usage
// Exit OCEOS oceos_exit();
oceos_CPU_sleep()
Header File
initialisation.h
Description
Puts CPU in sleep mode.
User must to be sure that interrupts are enabled.Prototype
/** * Puts CPU in sleep mode. * User must to be sure that interrupts are enabled. * * @return OCEOS_SUCCESS */ S32_t oceos_CPU_sleep(void);Parameters
There are no input parameters to this function.Returns
This function returns an S32_t with one of the status codes defined above.Example Usage
// Put CPU to sleep oceos_CPU_sleep();
oceosmp_cpu_disable()
Header File
initialisation.h
Description
This function ends execution of all tasks running on particular CPU and removes the CPU from scheduling.Prototype
/** * Ends execution of all tasks running on particular CPU and removes this CPU from scheduling. * @param cpu_id * @return OCEOS_SUCCESS * ERR_SYS_FIXED_CORRUPT System Fixed area corrupt * ERR_SYS_DYN_CORRUPT System Dynamic area corrupt * ERR_WRONG_PHASE Directive was called before OCEOS initialisation is finished * ERR_ID_INVALID CPU ID outside allowed range 0 to 254 * ERR_ID_WRONG CPU ID >= number of available CPUs * ERR_CPU_ALREADY_DISABLED CPU already disabled */ S32_t oceosmp_cpu_disable( U32_t cpu_id );Parameters
Parameter Description cpu_id ID of CPU core to be disabled. Returns
This function returns an S32_t with one of the status codes defined above.Example Usage
S32_t status, faulty_cpu; ... // Disable faulty CPU core status = oceosmp_cpu_disable(faulty_cpu));
oceosmp_cpu_enable()
Header File
initialisation.h
Description
This function adds a disabled CPU core to the OCEOSmp scheduler. It should only be called after scheduling has startedPrototype
/** * Adds disabled CPU to OCEOSmp scheduler * * N.B. This function should only be called after scheduling has started * * @param cpu_id * * @return OCEOS_SUCCESS * ERR_SYS_FIXED_CORRUPT System Fixed area corrupt * ERR_SYS_DYN_CORRUPT System Dynamic area corrupt * ERR_WRONG_PHASE Directive was called before OCEOS initialisation is finished * ERR_ID_INVALID CPU ID outside allowed range 0 to 254 * ERR_ID_WRONG CPU ID >= number of available CPUs; or the same as currently running * ERR_CPU_ALREADY_ENABLED CPU already enabled */ S32_t oceosmp_cpu_enable( U32_t cpu_id );Parameters
Parameter Description cpu_id ID of CPU core to be enabled. Returns
This function returns an S32_t with one of the status codes defined above.Example Usage
S32_t status, good_cpu; ... // Enable CPU core status = oceosmp_cpu_enable(good_cpu));
oceosmp_cpu_terminate()
Header File
initialisation.h
Description
This function removes a CPU core from the OCEOSmp scheduler and marks it so it cannot be restarted. It puts CPU to sleep with interrupts disabled. It should only be called after scheduling has started.Prototype
/** * Removes CPU from OCEOSMP scheduler and terminates, cannot be restarted. * Puts CPU to sleep with interrupts disabled * * N.B. This function should only be called after scheduling has started * Steps: * 1. Set terminate flag on this CPU; * 2. Trigger software interrupt to transfer execution to IRQ handler; * 3. Check flag and if set => put CPU to sleep in while loop with interrupts disabled; * 4. Set MAX priority on this CPU priority stack; * 5. Remove CPU from scheduling; * 6. Clean up all the tasks by calling task terminate function and free up all the * preempted jobs by this CPU; * * @param cpu_id * * @return OCEOS_SUCCESS * ERR_SYS_FIXED_CORRUPT System Fixed area corrupt * ERR_SYS_DYN_CORRUPT System Dynamic area corrupt * ERR_WRONG_PHASE Directive was called before OCEOS initialisation is finished * ERR_ID_INVALID CPU ID outside allowed range 0 to 254 * ERR_ID_WRONG CPU ID >= number of available CPUs; or the same as currently running * ERR_CPU_ALREADY_TERMINATED CPU already terminated */ S32_t oceosmp_cpu_terminate( U32_t cpu_id );Parameters
Parameter Description cpu_id ID of CPU core to be terminated. Returns
This function returns an S32_t with one of the status codes defined above.Example Usage
S32_t status, faulty_cpu; ... // Terminate CPU core status = oceosmp_cpu_terminate(faulty_cpu));
Task directives
Directive | Description | main | task | IRQ handler |
---|---|---|---|---|
oceos_task_create() | Create Task | * | ||
oceos_task_start() | Start Task | * | * | |
oceos_task_timed_start() | Schedule a task to start execution at a given system time | * | * | |
oceos_task_disable() | Disable Task | * | * | |
oceos_task_enable() | Enable Task | * | * | |
oceos_task_self() | Returns the task ID of the currently executing task | * | * | |
oceos_task_get_priority() | Get priority of a task | * | * | |
oceos_task_get_status() | Get status of a task | * | * | |
oceos_task_kill() | Directive to terminate current task | * | * | |
oceos_task_get_info() | Get task information | * | * |
Task data structures
Header File
tasks.h
Description
The following data structures are used by some of the task directives.Data structures
/** * A pointer to this structure is passed to oceos_task_create(). * The structure is first initialised according to a tasks's parameters, * and is not used again after the task is created and may then be discarded. */ struct task_descriptor { void (*function_start)(void*); // name of task start function void (*function_end)(void*); // optional, NULL or task end function U32_t task_id; // 0 to 254, usually an enum U32_t task_jobs_max; // 1 to 15, max concurrent 'jobs' U32_t task_priority; // 1 (highest) to 254 (lowest) U32_t task_threshold; // >=1, <= task_priority (higher or same priority) U32_t task_turned_on_initially; // 0: disabled initially, else enabled U32_t time_deadline_microsecs; // start request to finish, 0 to ignore U32_t time_min_interval_microsecs; // between start requests, 0 to ignore U32_t uses_cpu_affinity; // 0: not restricted, else core restricted U32_t uses_cpu_affinity_core_id;// core ID to which restricted if affinity used }__attribute__ ((aligned (8))); /** * Task info used with oceos_task_get_info */ struct task_info { U64_t time_max_delay; // maximum time job is waiting on ready queue before becoming active U64_t time_max_finish; // maximum time to finish job execution after starting U64_t time_max_exec; // maximum time spent executing U64_t time_total_exec; // total CPU time used by this task U64_t time_min_gap_starts; // minimum time between job creations, can be reset U64_t time_min_gap_finish_start; // minimum time between job ending and new job creation, can be reset U64_t time_last_start; // time of most recent job creation U64_t time_last_finish; // time of most recent job finish unsigned int jobs_current_max :16; // maximum number of current jobs for this task, no roll over, can be reset unsigned int jobs_total :16; // number of times this task was started, no roll-over, can be reset U32_t jobs_current; // Number of task instances currently in use by oceos U32_t preempt_max; // maximum times any job was pre-empted, no roll-over, can be reset }__attribute__ ((aligned (8))); /* A task's status is returned as below if queried */ enum TASK_STATUS { TASK_DISABLED, // cannot be scheduled, and no current jobs TASK_ENABLED, // can be scheduled, but no current jobs TASK_INVALID, // task does not exist };oceos_task_create()
Header File
tasks.h
Description
Create a task. Can only be use before OCEOS starts. Stores the task information in the OCEOS fixed data area. This directive populates the data structures for a task. It should be called after oceos_init() and before oceos_init_finish().
It must be called for each task otherwise oceos_start() will return an error.Prototype
/** * Create a task using a task descriptor structure * * Can only be used in Initialisation Phase. * * A task has twelve constant parameters set when the task is created. * Rather than setting a list of these parameters the named fields of a * task_descriptor structure are set and a pointer to it passed here. * * The task_descriptor structure fields are described above. * Once the task has been created the structure can be discarded. * * To create a task: * set up a task_descriptor structure, * set its fields to the parameter values for the task, * pass a pointer to the structure to this directive. * * The structure is checked for validity by oceos_task_create and its * information used to set the task details in the OCEOS fixed data area. * * @param struct task_descriptor * fields give task characteristics * * @return OCEOS_SUCCESS No errors or warnings * WARN_NO_END_FUNCTION Warning, no end task function specified * * ERR_SYS_FIXED_CORRUPT System Fixed area corrupt * ERR_WRONG_CPU_CORE Executing directive on wrong CPU * ERR_WRONG_PHASE Called before oceos_init() is done * ERR_TOO_MANY MAX number of tasks already created * ERR_ID_INVALID Task ID outside allowed range 0 to 254 * ERR_ID_WRONG Task ID outside >= number of tasks * ERR_T_ALREADY_ALLOCATED Task ID already in use * ERR_T_PRIORITY_INVALID Task priority outside allowed range 1 to 254 * ERR_THRESHOLD_INVALID Task threshold outside range 1 to 254 * ERR_THRESHOLD_WRONG Task threshold higher priority than task priority * ERR_JOBS_MAX_INVALID Job number outside range 1 to 15 * ERR_JOBS_TOO_MANY System capacity exceeded * ERR_AFFINITY_WRONG CPU core specified is outside chosen range * ERR_START_FUNCTION_BAD Task start function address either NULL or misaligned */ S32_t oceos_task_create( const struct task_descriptor * const task_description_ptr );Parameters
Parameter Description struct task_descriptor * Pointer to task descriptor which contains task attributes Returns
This function returns an S32_t with one of the return codes defined above.Example Usage
/* Sample Task names - all here start with t_ to help avoid name confusion */ enum TASK_NAME{ t_0, t_1, t_2 }; /* * APPLICATION FUNCTION DECLARATIONS */ void fun0(void *); void fun1(void *); void fun2(void *); void end_function(void *); const struct task_descriptor tasks_data[NUMBER_OF_TASKS] = { {fun0, end_function, t_0, 2, 10, 8, TASK_ENABLED, 0, 0, 0, 0}, {fun1, end_function, t_1, 2, 10, 8, TASK_ENABLED, 0, 0, 0, 0}, {fun2, end_function, t_2, 2, 10, 8, TASK_ENABLED, 0, 0, 0, 0} }; S32_t status; ... // create tasks (names are defined in the application header) for (i=0; i<NUMBER_OF_TASKS; i++){ if ( oceos_task_create(&tasks_data[i]) != OCEOS_SUCCESS ){ oceosmp_print("\nFailed to create task\n\r"); return -i; } }