/***************************************************************************
 * Copyright (c) 2024 Microsoft Corporation
 * Copyright (c) 2026-present Eclipse ThreadX contributors
 *
 * This program and the accompanying materials are made available under the
 * terms of the MIT License which is available at
 * https://opensource.org/licenses/MIT.
 *
 * SPDX-License-Identifier: MIT
 **************************************************************************/

/**************************************************************************/
/**************************************************************************/
/**                                                                       */
/**   OSEK IMPLEMENTATION                                                 */
/**                                                                       */
/**************************************************************************/
/**************************************************************************/


/* Include necessary files.  */

#include "os.h"

/* Include some required internal headers. */

#include <tx_timer.h>
#include <tx_thread.h>
#include <tx_initialize.h>


/* Declare a structure to hold application information.  */

APPLICATION_INFO_PTR                    Application;


/* Define a global variable to hold operating mode of this wrapper.  */

static UINT                             osek_wrapper_operation_mode = OSEK_INIT_NOT_DONE;


/* Define the threads for the System Manager.  */

TX_THREAD                               osek_system_manager;


/* Define ThreadX message queues for System Manager.  */

TX_QUEUE                                osek_work_queue;


/* Define a byte pool control block for the osek region0 memory used.  */

TX_BYTE_POOL                            osek_region0_byte_pool;


/* Define ThreadX timer to act as a system timer.  */

TX_TIMER                                osek_system_timer;


/************ OSEK System objects Definitions **************/

/* Define a static pool of Task structures.  */

static OSEK_TCB                         osek_tcb_pool[OSEK_MAX_TASKS];


/* Define a static pool of resource structures.  */

static OSEK_RESOURCE                    osek_res_pool[OSEK_MAX_RES];


/* Defines a static pool of alarm structures.  */

static OSEK_ALARM                       osek_alarm_pool[OSEK_MAX_ALARMS];


/* Defines a static pool of counter structures.  */

static OSEK_COUNTER                     osek_counter_pool[OSEK_MAX_COUNTERS];


/* Define a Task Ready Queue.  */
/* For each OSEK priority there is a sub queue, each queue entry holds an id of a task ready to run.  */

TaskType                                task_table [OSEK_ISR1_PRIORITY + 1u][TASK_QUEUE_DEPTH];


/* A global variable holding all 32 events (bit flags) for this OS implementation.  */

EventMaskType                           global_events;
EventMaskType                           global_event_count;


/* Define some default system objects.  */

ResourceType                            RES_SCHEDULER;
CounterType                             SYS_TIMER;


/* Variables to store current and last executed task details.  */

ULONG                                   last_run_task;
ULONG                                   system_start;                   /* If TX_TRUE indicates a fresh system start.  */
UINT                                    task_terminated;


/* Define ISR2 controlling flags.  */
/* disable_ISR2 is the global enable/disable flag , if this flag is set no ISR2 is allowed or even kept pending.  */
/* suspend_ISR2 is NON Zero then any ISR2 is kept pending (provided that disable_ISR2 must be zero before hand).  */

/* disable_ISR2 = TX_FALSE & suspend_ISR2 = TX_FALSE :: process ISR2 immediately
   disable_ISR2 = TX_FALSE & suspend_ISR2 = TX_TRUE  :: log ISR2 but don't process till suspend_ISR2 becomes TX_FALSE
   disable_ISR2 = TX_TRUE  & suspend_ISR2 DON't care :: No ISR2 logged and executed  */

UINT                                    disable_ISR2 = TX_TRUE;         /* This flag must be TX_FALSE to allow ISR 2.  */
UINT                                    suspend_ISR2 = TX_TRUE;         /* This flag must be TX_FALSE to register and execute ISR2.  */
UINT                                    ISR2_pending = TX_FALSE;

/* Track initialization status.  */

static UINT                             osek_init_state; /* Set to 0 for uninitialized, 1 for initialized by not yet started and 2 if started.  */

#define OSEK_NOT_INIT (0U)
#define OSEK_INIT     (1U)
#define OSEK_STARTED  (2U)

#define OSEK_MAX_LINK_DEPTH (1024U) /* Maximum depth of linked resource, to prevent infinite loops in case of a corrupted list.  */

/* OSEK API Services and associated structures.  */

struct Service_ActivateTask             service_ActivateTask;
struct Service_TerminateTask            service_TerminateTask;
struct Service_ChainTask                service_ChainTask;
struct Service_Schedule                 service_Schedule;
struct Service_GetTaskID                service_GetTaskID;
struct Service_GetTaskState             service_GetTaskState;

struct Service_DisableAllInterrupts     service_DisableAllInterrupts;
struct Service_EnableAllInterrupts      service_EnableAllInterrupts;
struct Service_SuspendAllInterrupts     service_SuspendAllInterrupts;
struct Service_ResumeAllInterrupts      service_ResumeAllInterrupts;
struct Service_SuspendOSInterrupts      service_SuspendOSInterrupts;
struct Service_ResumeOSInterrupts       service_ResumeOSInterrupts;

struct Service_GetResource              service_GetResource;
struct Service_ReleaseResource          service_ReleaseResource;

struct Service_SetEvent                 service_SetEvent;
struct Service_ClearEvent               service_ClearEvent;
struct Service_GetEvent                 service_GetEvent;
struct Service_WaitEvent                service_WaitEvent;

struct Service_GetAlarmBase             service_GetAlarmBase;
struct Service_GetAlarm                 service_GetAlarm;
struct Service_SetRelAlarm              service_SetRelAlarm;
struct Service_SetAbsAlarm              service_SetAbsAlarm;
struct Service_CancelAlarm              service_CancelAlarm;

struct Service_GetActiveApplicationMode service_GetActiveApplicationMode;
struct Service_StartOS                  service_StartOS;
struct Service_ShutdownOS               service_ShutdownOS;

struct Service_GetServiceId             service_GetServiceId;


/**************************************************************************/
/*          OSEK internal functions prototypes                            */
/**************************************************************************/


/* Entry functions for various ThreadX threads used for OS management.  */

static void             osek_system_manager_entry(ULONG input);
static void             osek_system_timer_entry(ULONG input);
static void             osek_task_wrapper(ULONG tcb);


/* Initialization and reset for OSEK system objects.  */

static UINT             osek_memory_init (void *region0_ptr);
static void             osek_alarm_init(void);
static void             osek_tcb_init(void);
static void             osek_resource_init(void);
static void             osek_counter_init(void);

static void             osek_reset_alarm(OSEK_ALARM  *alarm_ptr);
static void             osek_reset_counter(OSEK_COUNTER  *counter_ptr);
static void             osek_reset_tcb(OSEK_TCB  *tcb_ptr);
static void             osek_reset_res(OSEK_RESOURCE  *res_ptr);

/* Some utilities.  */

static ULONG            osek_task_independent_area(void);
static OSEK_TCB         *osek_thread2tcb(TX_THREAD *thread_ptr);
static UINT             osek_remap_priority(UINT osek_priority);

/* Functions to obtain OSEK objects from predefined pools.  */

static UINT            osek_memory_allocate(ULONG size, void **memory_ptr);
static UINT            osek_get_alarm(void);
static CounterType     osek_get_counter(void);
static ResourceType    osek_get_resource(void);
static EventMaskType   osek_get_event(void);
static ULONG           osek_allocate_tcb(ULONG stack_size, OSEK_TCB **tcb_ptr);

/* Internal operation functions.  */

static StatusType      osek_do_task_terminate(OSEK_TCB  *tcb_ptr);
static StatusType      osek_do_activate_task (OSEK_TCB  *tcb_ptr);
static StatusType      osek_create_task(OSEK_TCB *tcb_ptr);
static StatusType      get_internal_resource(OSEK_TCB  *tcb_ptr);
static StatusType      release_internal_resource(OSEK_TCB  *tcb_ptr);
static StatusType      check_external_resource(OSEK_TCB  *tcb_ptr);
static StatusType      TerminateISR(void);


/* OSEK internal error function and Hook routine executors.  */

static void            osek_internal_error(ULONG error_code);
static void            exec_ErrorHook (StatusType error);
static void            exec_PreTaskHook(void);
static void            exec_PostTaskHook(void);


/*OSEK Scheduler helper functions.  */

static void            add_task_to_table(OSEK_TCB *tcb_ptr);
static void            start_osek_tasks(void);
static void            push_task_to_table(OSEK_TCB *tcb_ptr);
static void            pop_task_from_table(OSEK_TCB *tcb_ptr);
static UINT            check_task_to_run (OSEK_TCB *tcb_ptr );
static void            check_linked_resources(void);
static StatusType      ActivateISR(ISRType ISRID);


/**************************************************************************/


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    StartOS                                             PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function starts the OS. If StartOSHook is defined it is        */
/*    called.                                                             */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    StatusType                     Application mode                     */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    StartupHook                    If defined                           */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Application                                                         */
/*                                                                        */
/**************************************************************************/
void   StartOS(StatusType  os_mode)
{

ULONG               request[SYSMGR_QUEUE_MSG_LENGTH];
StatusType          status;

   check_linked_resources();

   Application->application_mode = OSDEFAULTAPPMODE;

   /* Check for any startup hook routine.  */
   if (Application->startup_hook_handler != TX_NULL)
   {
       /* Change operation mode for to startuphook mode.  */
       osek_wrapper_operation_mode = STARTUPHOOK_MODE;
       (Application->startup_hook_handler)(os_mode);
   }

   /* Change back to default operations mode.  */
   osek_wrapper_operation_mode = NORMAL_EXECUTION_MODE;

   /* Now send message to system thread to start the task scheduler.  */

   /* Build the request.  */
   request[0] = SYSMGR_START_OS;            /* Request type.  */
   request[1] = 0u;                         /* Dummy.  */
   request[2] = 0u;                         /* Dummy.  */
   request[3] = 0u;                         /* Dummy.  */

   /* Now send a message to the SysMgr supervisor thread.        */
   /* to start OS task scheduler.                                */

   status = tx_queue_send(&osek_work_queue, request, TX_NO_WAIT);

   /* This should always succeed.  */
   if (status != TX_SUCCESS)
   {
       /* System internal error.  */
       osek_internal_error(SYS_MGR_START_OS);
   }

   return;
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    CreateTask                                          PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function creates a new task with specified attributes.         */
/*    This call is allowed only during Application Initialization.        */
/*    This is not a standard OSEK API call.                               */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    priority                      Priority of the Task                  */
/*    stack_size                    Stack size of the Task                */
/*    entry_function                Task entry function pointer           */
/*    policy                        Scheduling policy for this Task       */
/*    active_no                     Maximum activation number             */
/*    start                         Starting state of the task            */
/*    type                          Task type: Basic/Extended             */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    TaskId                        Task Id if successful                 */
/*    TX_NULL                       Error while creating the task         */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    osek_allocate_tcb             Get a TCB from the pool               */
/*    osek_create_task              Create an OSEK Task                   */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*   Initialization code                                                  */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
TaskType       CreateTask(const CHAR *name, void(*entry_function)(), UINT priority, UINT max_activation,
                            ULONG stack_size, SCHEDULE policy, AUTOSTART start, UINT type, AppModeType mode)
{

OSEK_TCB       *tcb_ptr;      /* Pointer to task control block.  */
ULONG           temp32;
ULONG           status;


   /* Check whether we are called during initialization.  */
   /* This will ensure that no one calls this function after system is started.  */
   if (osek_init_state != OSEK_INIT)
   {
       Application->osek_object_creation_error++;

       /* Return OSEK internal error. NOTE: This is not a standard OSEK error.  */
       return ((TaskType)TX_NULL);
   }

   /* Now check the validity of all input parameters.  */

   /* Entry point function.  */
   if (entry_function == TX_NULL)
   {
       /* Entry function not specified! Return an error. This is not a standard OSEK error.  */
       Application->osek_object_creation_error++;
       return ((TaskType)TX_NULL);
   }

   /*  Task priority. */
   if (priority > OSEK_HIGHEST_PRIORITY)
   {
       /* Return an internal error. This is not a standard OSEK error.  */
       Application->osek_object_creation_error++;
       return ((TaskType)TX_NULL);
   }

   /* The max_activation parameter must be within limit, that is a non zero value but less
      than OSEK_MAX_ACTIVATION. */
   if ((max_activation > OSEK_MAX_ACTIVATION) || (max_activation == 0u))
   {
       /* Return an internal error. This is not a standard OSEK error.  */
       Application->osek_object_creation_error++;
       return ((TaskType)TX_NULL);
   }

   /* Adjust the input stack size and check. */
   /* Force stack size to a multiple of 4 bytes, round up if needed.  */
   temp32 = ((stack_size + 3u) & ~0x3u);

   /* Add a little extra padding to stack.  */
   temp32 += OSEK_STACK_PADDING;

   /* Is task stack big enough? ThreadX needs a minimum stack size for each task.  */
   if (temp32 < TX_MINIMUM_STACK)
   {
       /* Return an error as there is no enough stack.  This is not a standard OSEK error.  */
       Application->osek_object_creation_error++;
       return ((TaskType)TX_NULL);
   }

   /* Scheduling Policy */
   if ((policy != FULL) && (policy != NON))
   {
       /* Return an error as policy supplied is unknown.  This is not a standard OSEK error.  */
       Application->osek_object_creation_error++;
       return ((TaskType)TX_NULL);
   }

   /* Task Type */
   if ((type != BASIC) && (type != EXTENDED))
   {
     /* Return an error as task type supplied is unknown.  This is not a standard OSEK error.  */
     Application->osek_object_creation_error++;
     return ((TaskType)TX_NULL);
   }

   /* AUTO START option.  */
   if ((start != TRUE) && (start != FALSE))
   {
       /* Return an error as Start type is unknown.This is not a standard OSEK error.  */
       Application->osek_object_creation_error++;
       return ((TaskType)TX_NULL);
   }

   /* Got all input parameters within limits, now try to get a free Task Control Block (TCB) for this new task.  */
   tcb_ptr = TX_NULL;
   status = osek_allocate_tcb(temp32, &tcb_ptr);

   /* Make sure we got a TCB.  */
   if((status != TRUE) || (tcb_ptr == TX_NULL))
   {
       /* Return an error since no memory is available.  This is not a standard OSEK error.  */
       Application->osek_object_creation_error++;
       return ((TaskType)TX_NULL);
   }

   /* Now fill up the TCB with all supplied parameters.  */

   /* Store TASK object ID this is same for all TCB, this helps in checking whether the data
      structure is really a TASK CONTROL BLOCK.  */
   tcb_ptr->osek_task_id = OSEK_TASK_ID;

   /* Store task's name and type.  */
   tcb_ptr->name = name;
   tcb_ptr->task_type = type;

   /* Store the statically assigned (design time) priority and same would be RUN time priority.  */
   tcb_ptr->org_prio = priority;
   tcb_ptr->cur_threshold = priority;

   /* Store the task entry point. This is where the task will begin upon activation or chaining.  */
   tcb_ptr->task_entry = entry_function;

   /* Store current task activation number as well as the maximum activations defined for this task.  */
   tcb_ptr->max_active = max_activation;
   tcb_ptr->current_active = 0u;
   tcb_ptr->internal_res = TX_FALSE;

   /* Store the scheduling policy defined for the task.  */
   tcb_ptr->policy = policy;

   /* Store the start up condition of the task.  */
   tcb_ptr->task_autostart = start;

   /* A task is always created in suspended state even though it is defined as an AUTO START.  */
   tcb_ptr->suspended = TX_TRUE;
   tcb_ptr->waiting = TX_FALSE;

   /* Store task's application mode.  */
   tcb_ptr->task_Appl_Mode = mode;

   /* Now create the ThreadX thread which actually runs this task.  */
   status = osek_create_task(tcb_ptr);

   /* Check whether we encounter any error during ThreadX thread creation.  */
   if (status == E_OS_SYSTEM)
   {
       /* Can't create a task? This is not a standard OSEK error.*/
       Application->osek_object_creation_error++;
       return ((TaskType) TX_NULL);
   }

   /* Everything worked fine so far. Return TaskID. This TaskID is nothing  but a TCB structure
      type casted to TaskType UDT.  */
   return ((TaskType)tcb_ptr);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    CreateISR                                           PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function creates a new task which will execute an ISR.         */
/*    This call is allowed only during Application Initialization.        */
/*    This is not a standard OSEK API call.                               */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    priority                      Priority of the ISR                   */
/*    stack_size                    Stack size of the ISR                 */
/*    entry_function                Task entry function pointer           */
/*    policy                        Scheduling policy for this task       */
/*    active_no                     Maximum activation number             */
/*    start                         Starting state of the task            */
/*    type                          Task type: Basic/Extended             */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    TaskId                        Task Id if successful                 */
/*    TX_NULL                       Error while creating the ISR          */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    osek_allocate_tcb             Get a TCB from the pool               */
/*    osek_create_task              Create an OSEK Task                   */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*   Initialization code                                                  */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/

ISRType CreateISR(const CHAR *name, void (*entry_function)(), UINT category, ULONG stack_size)
{

OSEK_TCB       *tcb_ptr;      /* Pointer to task control block.  */
ULONG           temp32;
ULONG           status;


   /* Check if we are called during initialization.  */
   if((osek_init_state != OSEK_INIT) ||  /* Not in initialization.  */
        (_tx_thread_current_ptr == &_tx_timer_thread))
   {
       /* Return default error.  */
       Application->osek_object_creation_error++;

       return((ResourceType)TX_NULL);
   }

   /* Scheduling policy.  */
   if ((category != CATEGORY1) && (category != CATEGORY2))
   {
       /* Return an error as policy supplied is unknown.  This is not a standard OSEK error. */
       Application->osek_object_creation_error++;
       return ((TaskType)TX_NULL);
   }

   /* Entry point function.  */
   if(entry_function == NULL)
   {
       /* Entry function not specified! Return an error. This is not a standard OSEK error.  */
       Application->osek_object_creation_error++;
       return ((TaskType)TX_NULL);
   }

   /* Adjust the input stack size and check. */
   /* Force stack size to a multiple of 4 bytes, round up if needed.  */
   temp32 = ((stack_size + 3u) & ~0x3u);

   /* Add a little extra padding to stack.  */
   temp32 += OSEK_STACK_PADDING;

   /* Is task stack big enough? ThreadX needs a minimum stack size for each task.  */
   if (temp32 < TX_MINIMUM_STACK)
   {
       /* Return an error as there is not enough stack.  This is not a standard OSEK error. */
       Application->osek_object_creation_error++;
       return ((ISRType)TX_NULL);
   }

   /* Got all input parameters within limits, now try to get a free task control block(TCB) for this new ISR.  */
   tcb_ptr = TX_NULL;
   status = osek_allocate_tcb(temp32, &tcb_ptr);
   /* Make sure we got a TCB.  */
   if((status != TRUE) || (tcb_ptr == TX_NULL))
   {
       /* Return an error since no memory is available.  This is not a standard OSEK error.  */
       Application->osek_object_creation_error++;
       return ((TaskType)TX_NULL);
   }

   /* Got a tcb , now fill up the TCB with all supplied parameters.  */

   /* Store ISR objectID ,this is same for all ISRs, this helps in checking whether the data
      structure is really a ISR CONTROL BLOCK.  */
   tcb_ptr->osek_task_id = OSEK_ISR_ID;

   /* Store ISR name.  */
   tcb_ptr->name = name;
   /* Store ISR category.  */
   tcb_ptr->task_type = category;

   /* Store the statically assigned (design time) priority and same would be runtime priority.  */

   if (category == 1u)
   {
       tcb_ptr->org_prio = OSEK_ISR1_PRIORITY;
   }
   else
   {
       tcb_ptr->org_prio = OSEK_ISR2_PRIORITY;
   }

   tcb_ptr->cur_threshold = tcb_ptr->org_prio;

   /* Store the ISR entry point. This is where the ISR will begin.  */
   tcb_ptr->task_entry = entry_function;

   /* Store maximum activations defined for ISR.  */
   /* Only 1 ISR of this name can be pending.   */
   tcb_ptr->max_active = 1u;
   tcb_ptr->current_active = 0u;
   tcb_ptr->internal_res = TX_FALSE;

   /* Store the scheduling policy defined for the task.  */
   tcb_ptr->policy = NON;

   /* Store the start up condition of the ISR which of course is DO NOT START.  */
   tcb_ptr->task_autostart = FALSE;

   /* An ISR is always created in suspended state.  */
   tcb_ptr->suspended = TX_TRUE;
   tcb_ptr->waiting = TX_FALSE;

   /* Now create the ThreadX thread which actually mimics this ISR.  */
   status = osek_create_task(tcb_ptr);

   /* Check whether we encounter any error during ThreadX thread creation.  */
   if (status == E_OS_SYSTEM)
   {
       /* Can't create a task? This is not a standard OSEK error.  */
       Application->osek_object_creation_error++;
       return ((ISRType)TX_NULL);
   }

   /* Everything worked fine so far. Return ISRID. This  is nothing  but a TCB structure
      type casted to ISRType UDT.  */
   return ((ISRType)tcb_ptr);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    ActivateTask                                        PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This call transfers a task from suspended state into the ready      */
/*    state. The operating system ensures that the task code is being     */
/*    executed from the first statement. The service may be called both   */
/*    from interrupt level and from task level. Rescheduling after this   */
/*    call depends on   from where it is called from. Also if required    */
/*    resources are freed as well as this being the highest priority task */
/*    than the task executing at this instance. If E_OS_LIMIT is returned */
/*    then activation is ignored. When an extended task is transferred    */
/*    from suspended to ready state all its events are cleared.           */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    TaskId                                Task Name                     */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    E_OK                                  If successful                 */
/*    E_OS_ID                               Invalid TaskId                */
/*    E_OS_LIMIT                            Task activation limit         */
/*                                          exceeded                      */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    tx_queue_send                         Send message to Sys Manager   */
/*    osek_internal_error                   OSEK internal error           */
/*    osek_task_independent_area            Check calling context         */
/*    tx_thread_identify                    Get ThreadX thread of caller  */
/*    osek_thread2tcb                       Convert ThreadX  to OSEK      */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Application                                                         */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
StatusType ActivateTask(TaskType TaskId)
{
TX_INTERRUPT_SAVE_AREA
OSEK_TCB       *tcb_ptr;
OSEK_TCB       *tcb_ptr_self;
UINT            status;
ULONG           request[SYSMGR_QUEUE_MSG_LENGTH];
ULONG           area;
TX_THREAD       *p_thread;


   /* Log this call and arguments passed, this is required for the macro 'OSErrorGetServiceId'.  */
   service_GetServiceId.id = (OsServiceIdType)OSServiceId_ActivateTask;
   service_ActivateTask.TaskID = TaskId;

   /* Check if we are in task context.  */
   area = osek_task_independent_area();
   if(area != TX_TRUE)
   {
       exec_ErrorHook(E_OS_CALLEVEL);
       /* Return error. */
       return (E_OS_CALLEVEL);
   }

   /* Check operating mode */
   if ((osek_wrapper_operation_mode != NORMAL_EXECUTION_MODE) && (osek_wrapper_operation_mode != ISR2_MODE))
   {
       /* Hook routines and alarm callbacks can't call  this service. */
       /* This explicit check is required because all hook routines are
          executed in task's context!  */
       exec_ErrorHook(E_OS_ID);
       return (E_OS_CALLEVEL);
   }

   /* Get OSEK TCB of the calling task.  */
   p_thread = tx_thread_identify();
   tcb_ptr_self = osek_thread2tcb(p_thread);

   if ((tcb_ptr_self->osek_task_id != OSEK_TASK_ID) && (tcb_ptr_self->osek_task_id != OSEK_ISR_ID))
   {
       /* This call is allowed only from TASK and ISR */
       return (E_OS_CALLEVEL);
   }

   /* Get OSEK TCB of the TASK to activate.  */
   tcb_ptr = (OSEK_TCB *)TaskId;
   if ((tcb_ptr == TX_NULL) || (tcb_ptr->osek_task_id != OSEK_TASK_ID))
   {
       exec_ErrorHook(E_OS_ID);
       return (E_OS_ID);
   }

   TX_DISABLE

   /* Check whether the task to be activated is activated up to its defined activation limit.  */
   if(tcb_ptr->current_active >= tcb_ptr->max_active)
   {
       TX_RESTORE
       exec_ErrorHook(E_OS_LIMIT);
       /* Reached its max activation limit.  */
       return (E_OS_LIMIT);
   }

   /* Now send a message to the system manager thread to activate this task.   */
   /* Build the request. */
   request[0] = SYSMGR_ACTIVATE_TASK;          /* Request type.  */
   request[1] = (ULONG)tcb_ptr;                /* Task to activate.  */

   /* Now check who is calling this service, a task or an ISR?  */
   if (tcb_ptr_self->osek_task_id == OSEK_TASK_ID)
   {
       request[2] = (ULONG)tcb_ptr_self;      /* Task id of the calling task.  */
   }
   else
   {
       request[2] = 0u;  /* When ISR activates a task rescheduling (if any) is held
                            till ISR completes so no need to suspend ISR task.  */
   }

   request[3] = 0u;

   /* Since the SysMgr supervisor thread has the highest priority, this call   */
   /* will be preempted by SysMgr supervisor thread.                           */
   /* SysMgr will eventually call osek_do_task_activate.                       */

   status = tx_queue_send(&osek_work_queue, request, TX_NO_WAIT);

   TX_RESTORE

   /* This should always succeed.  */
   if (status != TX_SUCCESS)
   {
       /* System internal error.  */
       osek_internal_error(SYS_MGR_SEND_ACTIVATETASK);
   }

   /* Return status.  */
   return(E_OK);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    TerminateTask                                       PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*   This service terminates the calling task, which means transferring   */
/*   the calling task from the running state into the suspended state.    */
/*   Only internal resources held by this task are released here. While   */
/*   it is assumed that any external resources occupied by the task must  */
/*   have been released before the call to TerminateTask. In case         */
/*   a resource is still occupied while calling this service, then the    */
/*   behaviour is undefined in STANDARD version of OSEK. In the EXTENDED  */
/*   version of OSEK, this service returns an error, which can be         */
/*   evaluated by the application.                                        */
/*   If successful, this call will causes rescheduling, this also means   */
/*   that upon success TerminateTask does not return to the call level.   */
/*                                                                        */
/*   NOTE:                                                                */
/*                                                                        */
/*   Ending a task function without call to TerminateTask or ChainTask is */
/*   strictly forbidden and may leave the system in an undefined state.   */
/*   But in this implementation TerminateTask service is called if needed.*/
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                            If success                          */
/*    Error Code.                     If error                            */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    osek_task_independent_area      Check if we are in task context     */
/*    osek_thread2tcb                 Get TCB pointer for thread pointer  */
/*    tx_queue_send                   Send message to Sys Manager Thread  */
/*    osek_internal_error             In case of any internal error       */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Application Code  (TASKs only)                                      */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
StatusType  TerminateTask(void)
{
TX_INTERRUPT_SAVE_AREA
OSEK_TCB       *tcb_ptr;
ULONG           request[SYSMGR_QUEUE_MSG_LENGTH];
UINT            index;
UINT            status;
ULONG           area;
TX_THREAD      *p_thread;


   service_GetServiceId.id = (OsServiceIdType)OSServiceId_TerminateTask;
   service_TerminateTask.TaskID = (StatusType)0u;

   /* Check for Task or ISR context. */
   /* All ISRs are treated as as a high priority tasks.  */
   area = osek_task_independent_area();
   if(area != TX_TRUE)
   {
       exec_ErrorHook(E_OS_CALLEVEL);
       /* Return error.  */
       return (E_OS_CALLEVEL);
   }

   /* Get OSEK TCB of this TASK/ISR.  */
   p_thread = tx_thread_identify();
   tcb_ptr = osek_thread2tcb(p_thread);
   if (tcb_ptr == TX_NULL)
   {
       exec_ErrorHook(E_OS_CALLEVEL);
       return (E_OS_CALLEVEL);
   }

   if (tcb_ptr->osek_task_id != OSEK_TASK_ID)
   {
       /* This call is allowed only from TASK and ISR.  */
       exec_ErrorHook(E_OS_CALLEVEL);
       return (E_OS_CALLEVEL);
   }


   /* Check operating mode */
   if (osek_wrapper_operation_mode != NORMAL_EXECUTION_MODE)
   {
       /* Hook routines and alarm callbacks can't call  this service.  */
       /* This explicit check is required because all hook routines are
          executed in task's context!  */
       exec_ErrorHook(E_OS_CALLEVEL);

       return (E_OS_CALLEVEL);
   }

   TX_DISABLE

   /* Check if any resource is occupied. A task can not be terminated if it is holding any resource.   */
   if(tcb_ptr->res_ocp != 0u)
   {
      TX_RESTORE

      exec_ErrorHook(E_OS_RESOURCE);

      /* Return.  */
      return (E_OS_RESOURCE);
   }

   /* Release any internal resources held.  */
   if (tcb_ptr->internal_res != 0u)
   {
       for (index = 0u; index < OSEK_MAX_INTERNAL_RES; index++)
       {
           if (tcb_ptr->internal_resource_occuplied_list[index] == 0u)
           {
               break;
           }

           ((OSEK_RESOURCE *)(tcb_ptr->internal_resource_occuplied_list[index]))->taskid = 0u;
           tcb_ptr->internal_resource_occuplied_list[index] = 0u;

       }   /* End of for loop.  */
   }

   /* Now it's okay to terminate this task, clear its events.  */
   tcb_ptr->waiting_events = 0u;
   tcb_ptr->set_events = 0u;

   /* Now all set to terminate this task.  */
   /* Send a message to the System Manager to terminate this task.  */
   /* Build the request.  */

   request[0] = SYSMGR_TERMINATE_TASK;      /* Request type.  */
   request[1] = (ULONG)tcb_ptr;             /* ID of the task to kill.  */
   request[2] = 0u;
   request[3] = 0u;

   /* Since the SysMgr supervisor thread has the highest priority,        */
   /* this call will be preempted by SysMgr supervisor thread             */
   /* SysMgr will eventually call osek_do_task_terminate and reschedule.  */

   status = tx_queue_send(&osek_work_queue, request, TX_NO_WAIT);

   TX_RESTORE

   /* This should always succeed. and Sys Manager terminates this task    */
   /* This point will never be reached, as this thread itself will be     */
   /* deleted by the system manager!                                      */

   if (status != TX_SUCCESS)
   {
       osek_internal_error(SYS_MGR_SEND_TERMINATETASK);
   }

   return (E_OK);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    ChainTask                                           PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This service causes the termination of the calling task. After      */
/*    termination of the calling task, a succeeding task (supplied as an  */
/*    input argument for the call) is activated. If the succeeding task   */
/*    is the same calling task, then this does not result in multiple     */
/*    requests and the task is not transferred to the suspended state.    */
/*    Only internal resources held by this task are released here, even   */
/*    in case the calling task is identical with the task to chain.       */
/*    While it is assumed that any external resources occupied by the     */
/*    task must have been released before the call to TerminateTask.      */
/*    In case a resource is still occupied while calling this service,    */
/*    then the behaviour is undefined in STANDARD version of OSEK.        */
/*    In the EXTENDED version of OSEK, an error is returned, which can be */
/*    evaluated by the application.                                       */
/*    If called successfully, ChainTask does not return to call level and */
/*    the status can not be evaluated. In case of error the service       */
/*    returns to the calling task and provides a status which can then be */
/*    checked by the application.                                         */
/*    If successful, this call will causes rescheduling, this also means  */
/*    that upon success ChainTask does not return to the call level.      */
/*                                                                        */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    Task_ID                              Task id to activate.           */
/*  OUTPUT                                                                */
/*                                                                        */
/*    E_OK                                 If successful.                 */
/*    E_OS_LIMIT                           Too many activations           */
/*    E_OS_CALLEVEL                        Called at interrupt level      */
/*    E_OS_RESOURCE                        Resources are not released     */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    osek_task_independent_area       Make sure called in Task context   */
/*    osek_thread2tcb                  Get TCB pointer for the thread     */
/*    tx_queue_send                    send message to sys manager thread */
/*    osek_internal_error              Any internal errors                */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Application Code  (TASKs only)                                      */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
StatusType ChainTask(TaskType  TaskID)
{
TX_INTERRUPT_SAVE_AREA
OSEK_TCB       *tcb_ptr;
OSEK_TCB       *tcb_ptr1;
ULONG           request[SYSMGR_QUEUE_MSG_LENGTH];
UINT            index;
ULONG           area;
TX_THREAD      *p_thread;

   service_GetServiceId.id = (OsServiceIdType)OSServiceId_ChainTask;
   service_ChainTask.TaskID = TaskID;

   /* Check if we are in task context.  */
   area = osek_task_independent_area();
   if(area != TX_TRUE)
   {
       exec_ErrorHook(E_OS_CALLEVEL);
       /* Return error.  */
       return(E_OS_CALLEVEL);
   }

   /* Get OSEK TCB of this TASK/ISR.  */
   p_thread = tx_thread_identify();
   tcb_ptr = osek_thread2tcb(p_thread);
   if (tcb_ptr == TX_NULL)
   {
       exec_ErrorHook(E_OS_ID);
       return (E_OS_ID);
   }

   if (tcb_ptr->osek_task_id != OSEK_TASK_ID)
   {
       /* This call is allowed only from TASK.  */
       exec_ErrorHook(E_OS_CALLEVEL);
       return (E_OS_CALLEVEL);
   }

   /* Check operating mode.  */
   if (osek_wrapper_operation_mode != NORMAL_EXECUTION_MODE)
   {
       /* ISRs, hook routines and alarm callbacks can't call  this service.  */
       /* This explicit check is required because all ISRs and hook routines are
          executed in task's context!  */
       exec_ErrorHook(E_OS_CALLEVEL);

       return (E_OS_CALLEVEL);
   }

   /* Check if any external resources are occupied.  */
   if(tcb_ptr->res_ocp != 0u)
   {
       exec_ErrorHook(E_OS_RESOURCE);

       /* The external resource is not released.  */
       return (E_OS_RESOURCE);
   }

   /* Get tcb of task to be chained.  */
   tcb_ptr1 = (OSEK_TCB *)TaskID;

   /* First, check for an invalid task pointer.  */
   if ((tcb_ptr1 == TX_NULL) || ((tcb_ptr1->osek_task_id) != OSEK_TASK_ID))
   {
       exec_ErrorHook(E_OS_ID);

       /* Return Error.  */
       return (E_OS_ID);
   }

   TX_DISABLE

   /* Check both calling task and task_to_be_chained are one and the same.  */
   if (tcb_ptr != tcb_ptr1)
   {
       /* Check for proper multiple activation.  */
       if(tcb_ptr1->current_active >= tcb_ptr1->max_active)
       {
           TX_RESTORE

           /* Reached its max activation limit.  */
           exec_ErrorHook(E_OS_LIMIT);

           return (E_OS_LIMIT);
       }
   }

   /* Store TaskID which is to be chained after termination of this task.  */
   tcb_ptr->task_to_chain = TaskID;

   /* Now release any internal resources held by the calling task.  */
   if (tcb_ptr->internal_res != 0u)
   {
       for (index = 0u ; index < OSEK_MAX_INTERNAL_RES; index++)
       {
           if (tcb_ptr->internal_resource_occuplied_list[index] == 0u)
           {
               break;
           }

           ((OSEK_RESOURCE *)(tcb_ptr->internal_resource_occuplied_list[index]))->taskid = 0u;
           tcb_ptr->internal_resource_occuplied_list[index] = 0u;

       }   /* End of for loop.  */
   }

   /* Now it's ok to terminate this task , clear its events.  */
   tcb_ptr->waiting_events = 0u;
   tcb_ptr->set_events = 0u;

   /* Send message to the system manager to suspend calling task and activate
      task to be chained.  */

   /* Build the request. */
   request[0] = SYSMGR_CHAIN_TASK;          /* Request type.  */
   request[1] = (ULONG)tcb_ptr;             /* TCB ptr of calling task.  */
   request[2] = TaskID;                     /* Task to chain.  */
   request[3] = 0u;

   /* Since the SysMgr supervisor thread has the highest priority,      */
   /* this routine will be preempted by SysMgr supervisor thread.       */

   tx_queue_send(&osek_work_queue, request, TX_NO_WAIT);

   TX_RESTORE

   /* This should always succeed and sys manager terminates this task   */
   /* This point will never be reached, as this thread itself will be    */
   /* deleted by the System Manager!                                     */

   osek_internal_error(SYS_MGR_SEND_CHAINTASK);

   return (E_OK);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    GetTaskID                                           PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    GetTaskID returns the task id of the task currently running.        */
/*    Calling GetTaskID is allowed from task level, ISR level and in      */
/*    several hook routines. This service is intended to be used by       */
/*    library functions and hook routines. If <TaskID> can�t be evaluated */
/*    (no task currently running), the service returns INVALID_TASK as    */
/*    TaskType.                                                           */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    TaskID                         Pointer to stored Task ID            */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    E_OK                           If success                           */
/*    INVALID_TASK                   If failure                           */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    tx_thread_identify             Identifies the current thread        */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Application code                                                    */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
StatusType GetTaskID(TaskRefType TaskID)
{

TX_THREAD      *thread_ptr;


   /* Check for valid pointer to store the task ID.  */
   if(TaskID == TX_NULL)
   {
       /* Return error.  */
       return (E_OS_ID);
   }

   /* Check for the pointer to thread.  */
   thread_ptr = tx_thread_identify();

   if ((thread_ptr == TX_NULL) || (thread_ptr == &_tx_timer_thread))
   {
       /* No task running TaskID can�t be evaluated return a special Error.  */
       *TaskID = INVALID_TASK;

       return (E_OK);
   }

   if ((osek_wrapper_operation_mode == STARTUPHOOK_MODE)     ||
       (osek_wrapper_operation_mode == SHUTDOWNHOOK_MODE)    ||
       (osek_wrapper_operation_mode == ALARM_CALLBACK_MODE))
   {
       *TaskID = INVALID_TASK;
   }
   else
   {
       *TaskID = last_run_task;
   }

    /* Return success.  */
    return (E_OK);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    GetTaskState                                        PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    Returns the state of a task (running, ready, waiting, suspended) at */
/*    the time of calling GetTaskState. The service may be called from    */
/*    interrupt service routines, task level, and some hook routines.     */
/*    Within a full preemptive system, calling this operating system      */
/*    service only provides a meaningful result if the task runs in an    */
/*    interrupt disabling state at the time of calling.                   */
/*    When a call is made from a task in a full preemptive system, the    */
/*    result may already be incorrect at the time of evaluation. When the */
/*    service is called for a task, which is multiply activated, the      */
/*    state is set to running if any instance of the task is running.     */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    Task_ID                              Task id to query               */
/*    State                                Pointer to result state        */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    E_OK                                 If successful                  */
/*    E_OS_ID                              Task is invalid                */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    osek_task_independent_area           Check if called from task      */
/*                                         independent area               */
/*    tx_thread_identify                   Identify the current thread    */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Application Code                                                    */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
StatusType GetTaskState(TaskType TaskID, TaskStateRefType State)
{
TX_INTERRUPT_SAVE_AREA
OSEK_TCB       *tcb_ptr;
TX_THREAD      *this_thread;
ULONG           area;
TX_THREAD      *p_thread;


   service_GetServiceId.id = (OsServiceIdType)OSServiceId_GetTaskState;
   service_GetTaskState.TaskID = (StatusType)0;

   /* Check for valid task ID.  */
   if(TaskID == 0u)
   {
       exec_ErrorHook(E_OS_ID);
       /* Return error.  */
       return (E_OS_ID);
   }

   /* Get OSEK TCB.  */
   tcb_ptr = (OSEK_TCB *)TaskID;

   /* First, check for an invalid task pointer.  */
   if((tcb_ptr == TX_NULL) || ((tcb_ptr->osek_task_id) != OSEK_TASK_ID))
   {
       exec_ErrorHook(E_OS_ID);
       /* Return error.  */
       return (E_OS_ID);
   }

   TX_DISABLE

   if ((osek_wrapper_operation_mode == STARTUPHOOK_MODE)     ||
       (osek_wrapper_operation_mode == SHUTDOWNHOOK_MODE)    ||
       (osek_wrapper_operation_mode == ALARM_CALLBACK_MODE))
   {
       TX_RESTORE

       /* Return error.  */
       return (E_OS_ID);
   }

   /* Get the ThreadX TCB.  */
   this_thread = (TX_THREAD *)tcb_ptr;

   /* Check if we are only in task context.  */
   area = osek_task_independent_area();
   if (area == TX_TRUE)
   {
       /* Get the OSEK TCB.  */
       p_thread = tx_thread_identify();
       if(this_thread == p_thread)
       {
           TX_RESTORE

           /* This is the running thread.  */
           *State = RUNNING;
           return (E_OK);
       }
   }

   if (tcb_ptr->waiting == TX_TRUE)
   {
       TX_RESTORE

       *State = WAITING;
       return (E_OK);
   }
   if (tcb_ptr->suspended == TX_TRUE)
   {
       TX_RESTORE

       *State = SUSPENDED;
       return (E_OK);
   }

   TX_RESTORE

   *State = READY;
   return (E_OK);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    Schedule                                            PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    If a higher-priority task is ready, the internal resource of the    */
/*    task is released, the current task is put into the ready state, its */
/*    context is saved and the higher-priority task is executed.          */
/*    Otherwise the calling task is continued.                            */
/*    Rescheduling can only take place if an internal resource is         */
/*    assigned to the calling task during system generation. For these    */
/*    tasks, schedule enables a processor assignment to other tasks with  */
/*    lower or equal priority than the ceiling priority of the internal   */
/*    resource and higher priority than the priority of the calling task  */
/*    in application-specific locations. When returning from schedule,    */
/*    the internal resource has been taken again.                         */
/*    This service has no influence on tasks with no internal resource    */
/*    assigned (preemptable tasks).                                       */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    E_OK                                 If success.                    */
/*    E_OS_CALLLEVEL                       Called at interrupt level      */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    osek_task_independent_area           Check if called from task      */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Application Code                                                    */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
StatusType Schedule (void)
{
TX_INTERRUPT_SAVE_AREA
OSEK_TCB       *tcb_ptr;
TX_THREAD      *this_thread;
ULONG           request[SYSMGR_QUEUE_MSG_LENGTH];
UINT            status;
ULONG           area;

   service_GetServiceId.id = (OsServiceIdType)OSServiceId_Schedule;
   service_GetTaskState.TaskID = (StatusType)0u;

   /* Check if we are in task context.  */
   area = osek_task_independent_area();
   if(area != TX_TRUE)
   {
       /* Return error.  */
       return (E_OS_CALLEVEL);
   }

   /* Get the ThreadX thread and OSEK TCB.  */
   this_thread = tx_thread_identify();
   tcb_ptr = osek_thread2tcb(this_thread);

   if (tcb_ptr == TX_NULL)
   {
       return (E_OS_ID);
   }

   if (tcb_ptr->osek_task_id != OSEK_TASK_ID)
   {
       /* This call is allowed only from TASK.  */
       return(E_OS_ID);
   }

   TX_DISABLE

   /* Check operating mode.  */
   if (osek_wrapper_operation_mode != NORMAL_EXECUTION_MODE)
   {

       TX_RESTORE

       /* Hook routines, alarm callbacks and ISRs can't call this service. */
       /* This explicit check is required because all hook routines are
          executed in task's context. */
       return (E_OS_ID);
   }

   /* Check if any resource is occupied.  */
   if(tcb_ptr->res_ocp != 0u)
   {
       TX_RESTORE

       exec_ErrorHook(E_OS_RESOURCE);
       /* Return.  */
       return (E_OS_RESOURCE);

   }

   /* Now release internal resources, if any, held by this task   */
   /* This call releases internal resources and moves the task to */
   /* a new queue position based on its new ceiling priority.     */
   /* release_internal_resource(tcb_ptr); */

   /* Now send message to system Manager to check any higher priority task is ready.  */
   /* Build the request.  */
   request[0] = SYSMGR_SCHEDULE;          /* Request type.  */
   request[1] = (ULONG)this_thread;       /* Self ID.  */
   request[2] = 0u;
   request[3] = 0u;

   /* Since the SysMgr supervisor thread has the highest priority,      */
   /* this routine will be preempted by SysMgr supervisor thread when   */
   /* queue read is successful.                                         */
   /* System Manager will eventually call start_osek_tasks.             */

   status = tx_queue_send(&osek_work_queue, request, TX_NO_WAIT);

   TX_RESTORE

   /* This should always succeed.  */
   if (status != TX_SUCCESS)
   {
       /* System internal error.  */
       osek_internal_error(SYS_MGR_SEND_CHAINTASK);
   }

   /* Assume that the sys manager does its job.  */
   /* And has returned from schedule, restore preemption threshold if any.  */

   /* Now we need to move this task back to its priority level */
   /* before coming here all internal resources (if any are taken).  */

   TX_DISABLE

   /* Now check task's scheduling policy */
   if (tcb_ptr->policy == NON)
   {
       pop_task_from_table(tcb_ptr);
       /* If policy is NON then restore to OSEK_NON_SCHEDULE priority.  */
       tcb_ptr->cur_threshold = OSEK_NON_SCHEDULE_PRIORITY;
       push_task_to_table(tcb_ptr);
   }

   TX_RESTORE

   return (E_OK);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    CreateResource                                      PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    Creates  resources for inter-task mutual exclusion for resource     */
/*    protection                                                          */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    name                         Name of the Resource.                  */
/*    type                         Type of the resource standard/internal */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    RES_ID                       If successful                          */
/*    ZERO                         If error while creating resource       */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    osek_memory_allocate         Allocate memory from system            */
/*    osek_get_resource            Get one resource from the pool         */
/*    tx_mutex_create              Create a Mutex in ThreadX              */
/*    osek_internal_error          OSEK internal Error                    */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*   Application Code                                                     */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
ResourceType  CreateResource(const CHAR *name, StatusType type, ResourceType linked_res)
{

OSEK_RESOURCE  *res_ptr;
OSEK_RESOURCE  *linked_res_ptr;
OSEK_RESOURCE  *res1_ptr;

ResourceType    ID;
ResourceType    linked_res_id;
UINT            done_flag;
UINT            iter_max;

   /* Check whether calling from task context or ISR.  */
   if ((osek_init_state != OSEK_INIT) ||  /* Not in Initialization.  */
       (_tx_thread_current_ptr == &_tx_timer_thread))
   {
       /* Return default error.  */
       Application->osek_object_creation_error++;
       return ((ResourceType) TX_NULL);
   }

   /* Check whether the linked resource (if specified) exists.  */
   if (type == LINKED)
   {
       if (linked_res == 0u)
       {
       /* Specified linked resource doesn't exist  */
       /* OR Resource is trying to link itself.  */
           Application->osek_object_creation_error++;
           return ((ResourceType) TX_NULL);
       }

       /* Check if the resource to which this resource is linked is external.  */
       linked_res_ptr = (OSEK_RESOURCE *)linked_res;
       if (linked_res_ptr->type == INTERNAL)
       {
           /* Specified linked resource is of INTERNAL type.  */
           Application->osek_object_creation_error++;
           return ((ResourceType) TX_NULL);
       }
   }

   /* Find out any resource is available.  */
   ID = osek_get_resource();
   if(ID == 0u)
   {
       /* Resource is not available.  */
       Application->osek_object_creation_error++;
       return ((ResourceType) TX_NULL);
   }

   /* Get the OSEK resource.  */
   res_ptr = (OSEK_RESOURCE *)ID;

   res_ptr->name = name;

   res_ptr->c_priority = 0u;

   res_ptr->type = type;

   res_ptr->linked_res = linked_res;

   res_ptr->resolved_res = 0u;

   /* Now resolve if chain of linked linked resources.  */

   if (res_ptr->type == LINKED)
   {
       done_flag = FALSE;
       res1_ptr = res_ptr;
       iter_max = OSEK_MAX_LINK_DEPTH; /* Safety count to prevent infinite loop.  */
       while(done_flag == 0u)
       {
           if(iter_max == 0u) {
               /* Maximum iteration count exceeded, return an error. */
               Application->osek_object_creation_error++;
               return ((ResourceType) TX_NULL);
           }

           linked_res_id = res1_ptr->linked_res;
           linked_res_ptr = (OSEK_RESOURCE *)linked_res_id;
           if (linked_res_ptr->type == STANDARD)
           {
               res_ptr->resolved_res = linked_res_id;
               done_flag = TRUE;
           }
           res1_ptr = linked_res_ptr;

           iter_max--;
       }

   }


   /* No task is occupying this resource.  */
   res_ptr->taskid = 0u;

   res_ptr->osek_res_id = OSEK_RES_ID;

   return (ID);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    GetResource                                         PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*   This call serves to enter critical sections in the code that are     */
/*   assigned to the resource referenced by <ResID>. A critical section   */
/*   must always be left using ReleaseResource. Nested resource           */
/*   occupation is only allowed if the inner critical sections are        */
/*   completely executed within the surrounding critical section.         */
/*   Nested occupation of one and the same resource is also forbidden.    */
/*   Corresponding calls to GetResource and ReleaseResource should appear */
/*   within the same function on the same function level.                 */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    id                           Id of the resource.                    */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    E_OK                         If success                             */
/*    E_OS_CALLEVEL                Called from ISR                        */
/*    E_OS_ACCESS                  Attempt to get a resource which is     */
/*                                 already occupied by any task or ISR,   */
/*                                 or the statically assigned priority of */
/*                                 the calling task or interrupt routine  */
/*                                 is higher than the calculated ceiling  */
/*                                 priority,                              */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    osek_task_independent_area   See if called from task independent    */
/*                                 area                                   */
/*    tx_thread_identify           Identify the current thread            */
/*    osek_internal_error          OSEK internal error                    */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*   Application Code                                                     */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
StatusType  GetResource(ResourceType id)
{
TX_INTERRUPT_SAVE_AREA
OSEK_RESOURCE  *osek_res;
OSEK_TCB       *tcb_ptr;
TX_THREAD      *this_thread;
UINT            index ;
UINT            new_prio;
ULONG           request[SYSMGR_QUEUE_MSG_LENGTH];
UINT            status;
ULONG           area;



   service_GetServiceId.id = (OsServiceIdType)OSServiceId_GetResource;
   service_GetResource.ResID = id;

   /* Check we are calling from task context only.  */
   area = osek_task_independent_area();
   if(area == 0u)
   {
       exec_ErrorHook(E_OS_CALLEVEL);
       /* Return default error.  */
       return (E_OS_CALLEVEL);
   }

   /* Check for valid ID.  */
   if(id == 0u)
   {
       exec_ErrorHook(E_OS_ID);
       /* Return error.  */
       return (E_OS_ID);
   }

   /* Get thread currently executed.  */
   this_thread = tx_thread_identify();
   if(this_thread == NULL)
   {
       exec_ErrorHook(E_OS_CALLEVEL);
       return (E_OS_CALLEVEL);
   }

   /* Get RES's control block.  */
   osek_res = (OSEK_RESOURCE *)id;

   /* First, check for an invalid resource pointer.  */
   if((osek_res == TX_NULL) || ((osek_res->osek_res_id) != OSEK_RES_ID))
   {
       exec_ErrorHook(E_OS_ID);

       /* Return Error.  */
       return (E_OS_ID);
   }

   /* Get the OSEK TCB.  */
   tcb_ptr = (OSEK_TCB *) this_thread;

   /* Now check whether this resource is standard or internal.  */
   if (osek_res->type == INTERNAL)
   {
       /* Internal Resource can not be occupied via GetResource call.  */
       exec_ErrorHook(E_OS_ID);
       return (E_OS_ID);
   }

   TX_DISABLE

   /* Now check whether this resource is occupied.  */
   if (osek_res->taskid != 0u)
   {
       TX_RESTORE

       /* Already occupied by this task or any other task, this also prevent double occupancy.  */
       exec_ErrorHook(E_OS_ACCESS);

       return (E_OS_ACCESS);
   }

   /* OK up to this point, now what type of resource is it? */
   /* Because 'RES_SCEDULER' is a special type of resource.  */

   if (id == RES_SCHEDULER)
   {

       /* This task has taken this resource so update this task's resource hold count.  */
       tcb_ptr->res_ocp++;

       /* Save this task's id in the res's control block.  */
       osek_res->taskid = (TaskType)tcb_ptr;

       tcb_ptr->resource_scheduler = TX_TRUE;

       /* Being RES_SCHEDULER no need to add RES_SCEDULER in the task's list of occupied resources.  */

       /* As task is occupying RES_SCHEDULER all preemptions are blocked so make the policy to NON PREEMP.  */
       /* A NON preempt type task is already having OSEK_NON_SCHEDULE_PRIORITY during RUN time, so need
          to change it.  */

       if (tcb_ptr->policy == FULL)
       {
           /* For a FULL preempt type task assign having highest preemption threshold */
           /* Now ask the System Manager to change this task's priority, and also check if there is
              any possibility of preemption.  */
           /* Send message to System Manager to check any preemption out of ReleaseResource call.  */
           new_prio = OSEK_NON_SCHEDULE_PRIORITY;

           /* Build the request.  */
           request[0] = SYSMGR_GET_RESOURCE;          /* Request type.  */
           request[1] = (ULONG)this_thread;
           request[2] = (ULONG)new_prio;
           request[3] = 0u;

           /* Since the SysMgr supervisor thread has the highest priority,      */
           /* this routine will be preempted by SysMgr supervisor thread when   */
           /* queue is successful.                                              */
           /* System Manager will eventually call start_osek_tasks.             */

           status = tx_queue_send(&osek_work_queue, request, TX_NO_WAIT);

           /* This should always succeed.  */
           if (status != TX_SUCCESS)
           {
               /* System internal error.  */
               osek_internal_error(SYS_MGR_SEND_CHAINTASK);

           }
       }

       TX_RESTORE

       return (E_OK);

   }   /* End if ( id == RES_SCHEDULER ).  */


   /* Not RES_SCEDULER. */

   /* Check whether this resource is assigned to this task or not?  */
   for (index = 0u; index < OSEK_MAX_EXTERNAL_RES; index++)
   {
       if (tcb_ptr-> external_resource_list[index] == id) {
           /* Yes it is registered with this task, stop searching.  */
           break;
       }
   } /* Check next in the list.  */

   /* Checked entire list and found that this resource is not in the list?  */
   if (index >= OSEK_MAX_EXTERNAL_RES)
   {
       TX_RESTORE

       exec_ErrorHook(E_OS_NOFUNC);

       /* Return error.  */
       return (E_OS_NOFUNC);
   }

   /* Yes this resource is assigned to this task.  */
   /* First check the task has room to hold one more resource?  */

   /* Find the next free entry in the task's res occupied list.  */
   for (index = 0u; index < OSEK_MAX_EXTERNAL_RES; index++)
   {
       if(tcb_ptr->external_resource_occuplied_list[index] == 0u)
       {
           /* Found next free entry but do not add this resource to the list at this moment.  */
           break;
       }
   }

   /* We got an entry or not?  */
   if (index >= OSEK_MAX_EXTERNAL_RES)
   {
       TX_RESTORE

       /* This is very unlikely, as list is big enough to hold all resources defined in the system.  */
       exec_ErrorHook(E_OS_ACCESS);

       /* Return Error.  */
       return (E_OS_ACCESS);
   }

   /* Now entry is available, take this resource.  */

   tcb_ptr->external_resource_occuplied_list[index] = id;
   /* Save this task's id in the res's control block to indicate that this is the owner of this res.  */
   osek_res->taskid = (TaskType)(tcb_ptr);
   /* This task has taken this resource so update this task's resource hold count.  */
   tcb_ptr->res_ocp++;

   /* Now we need to change this task's preemption threshold to this resource's ceiling priority.  */
   /* But if the task is of NON scheduling no need to take any action , it is already having
      highest preemption threshold.  */

   if ((tcb_ptr->policy == FULL) && (tcb_ptr->cur_threshold < osek_res->c_priority))
   {
       /* Need to change the at the task is having lower preemption threshold. */
       /* Remove this task from its current queue and place it in front of
          occupied resource's ceiling priority queue.  */

       new_prio = osek_res->c_priority;

       /* Build the request. */
       request[0] = SYSMGR_GET_RESOURCE;          /* Request type.  */
       request[1] = (ULONG)this_thread;
       request[2] = (ULONG)new_prio;
       request[3] = 0u;

       /* Since the SysMgr supervisor thread has the highest priority,      */
       /* this routine will be preempted by SysMgr supervisor thread when   */
       /* queue is successful.                                              */
       /* System Manager will eventually call start_osek_tasks.             */

       status = tx_queue_send(&osek_work_queue, request, TX_NO_WAIT);

       /* This should always succeed.  */
       if (status != TX_SUCCESS)
       {
           /* System internal error.  */
           osek_internal_error(SYS_MGR_SEND_CHAINTASK);
       }
   }

   TX_RESTORE

   return (E_OK);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    ReleaseResource                                     PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*   ReleaseResource is the counterpart of GetResource and serves to      */
/*   leave critical sections in the code that are assigned to the         */
/*   resource referenced by <ResID>. For information on nesting           */
/*   conditions, see GetResource. The service may be called from an ISR   */
/*   and from task level                                                  */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    id                           Id of the resource.                    */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    E_OK                         If successful                          */
/*    E_OS_NOFUNC                  Attempt to release a resource which is */
/*                                 not occupied by any task or ISR, or    */
/*                                 another resource has to be released    */
/*                                 before,If error occurs while creating  */
/*                                 task                                   */
/*    E_OS_ACCESS                  Attempt to release a resource which has*/
/*                                 a lower ceiling priority than the      */
/*                                 statically assigned priority of the    */
/*                                 calling task or interrupt routine.     */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*                                                                        */
/*    osek_task_independent_area   See if called from task independent    */
/*                                 area                                   */
/*    tx_thread_identify           Identify the current thread            */
/*    osek_internal_error          OSEK internal error                    */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*   Application Code                                                     */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
StatusType  ReleaseResource(ResourceType id)
{
TX_INTERRUPT_SAVE_AREA
OSEK_RESOURCE  *osek_res;
OSEK_TCB       *tcb_ptr;
TX_THREAD      *this_thread;
UINT           index;
UINT           res_prio;
UINT           location;
UINT           new_prio;
ULONG          request[SYSMGR_QUEUE_MSG_LENGTH];
UINT           status;
ULONG          area;

   service_GetServiceId.id = (OsServiceIdType)OSServiceId_ReleaseResource;
   service_ReleaseResource.ResID = id;

   /* Fist check valid resource id and proper calling context.  */

   /* Check we calling from from task context only.  */
   area = osek_task_independent_area();
   if(area == 0u)
   {
       exec_ErrorHook(E_OS_CALLEVEL);

       /* Return default error.  */
       return (E_OS_CALLEVEL);
   }

   /* Check for valid Resource ID.  */
   if(id == 0u)
   {
       exec_ErrorHook(E_OS_ID);

       /* Return error.  */
       return (E_OS_ID);
   }

   /* Get thread currently executed.  */
   this_thread = tx_thread_identify();
   if(this_thread == TX_NULL)
   {
       exec_ErrorHook(E_OS_CALLEVEL);

       return (E_OS_CALLEVEL);
   }

   /* Get OSEK resource control block.  */
   osek_res = (OSEK_RESOURCE *)id;

   /* Get the OSEK TCB.  */
   tcb_ptr = (OSEK_TCB *)this_thread;

   /* Now check whether this resource is standard or internal.  */

   if (osek_res->type == INTERNAL)
   {
       /* Internal resource can not be released via ReleaseResource call.  */
       exec_ErrorHook(E_OS_ID);

       return (E_OS_ID);
   }

   TX_DISABLE

   /* Is this task holding any resource? Check for resource count.  */
   if(tcb_ptr->res_ocp == 0u)
   {
       TX_RESTORE

       /* No resource taken yet trying to release resource?  */
       exec_ErrorHook(E_OS_NOFUNC);

       /* Return error.  */
       return(E_OS_NOFUNC);
   }

   /* Check whether this resource is occupied by this task.  */
   /* A task cannot release resource which are not occupied by itself.  */

   if (osek_res->taskid != (TaskType)tcb_ptr)
   {
       TX_RESTORE

       exec_ErrorHook(E_OS_NOFUNC);

       return (E_OS_NOFUNC);
   }

   /* Everything is valid up to this point, now try to release the resource requested.  */
   /* Check what type of Resource it is as RES_SCEDULER is a special case of resource.  */

   if (id == RES_SCHEDULER)
   {

       /* Remove this task's id from the res's control block which usually indicate that this is the
          owner of this res  and also update this task's resource hold count.  */
       osek_res->taskid = 0u;
       tcb_ptr->res_ocp--;

       /* As the task is giving up RES_SCHEDULER, make the associated flag FALSE.  */
       tcb_ptr->resource_scheduler = TX_FALSE;

       /* If Task is NON scheduling type, no preemption takes place.  */
       if (tcb_ptr->policy == NON)
       {
           TX_RESTORE

           /* Release this resource.  */
           return (E_OK);
       }

       /* With FULL scheduling, a change in preemption to highest
          ceiling priority of any other resources held by this task is needed.  */
       /* Check RES_SCEDULER is the only resource occupied by this task, then restore this task's threshold
          to its original priority.  */

       /* Assume no other resources are held.  */
       new_prio = tcb_ptr->org_prio;

       if (tcb_ptr->res_ocp > 0u)
       {
           /* If no other external resources are held the task will revert back to
              to its original design time priority.  */
           /* Or check the ceiling priorities of other external resources held by this task.  */

           for (index = 0u; index < OSEK_MAX_EXTERNAL_RES; index++)
           {
               if (tcb_ptr->external_resource_occuplied_list[index] == 0u)
               {
                   break;
               }

               res_prio = ((OSEK_RESOURCE *) (tcb_ptr->external_resource_occuplied_list[index]))->c_priority;
               if  (new_prio < res_prio) {
                   new_prio = res_prio;
               }
           }
       }

       /* Done with external resource, now check if there are any internal resources held?  */
       for ( index = 0u; index < OSEK_MAX_INTERNAL_RES; index++)
       {
           if (tcb_ptr->internal_resource_occuplied_list[index] == 0u)
           {
               break;
           }

           res_prio = ((OSEK_RESOURCE *) (tcb_ptr->internal_resource_occuplied_list[index]))->c_priority;

           if (new_prio < res_prio)
           {
               new_prio = res_prio;
           }
       }


       /* new_prio now holds the highest of ceiling priority of the remaining
      resources held by this task.  */

       /* Now ask the system manager to change this task's priority, and also check if there is
          any possibility of preemption.  */
       /* Send message to the system manager to check any preemption out of ReleaseResource call.  */

       /* Build the request. */
       request[0] = SYSMGR_RELEASE_RESOURCE;          /* Request type.  */
       request[1] = (ULONG)this_thread;
       request[2] = (ULONG)new_prio;
       request[3] = 0u;

       /* Since the SysMgr supervisor thread has the highest priority,      */
       /* this routine will be preempted by SysMgr supervisor thread when   */
       /* queue is successful.                                              */
       /* System Manager will eventually call start_osek_tasks.             */

       status = tx_queue_send(&osek_work_queue, request, TX_NO_WAIT);

       /* This should always succeed.  */
       if (status != TX_SUCCESS)
       {
           /* System internal error.  */
           osek_internal_error(SYS_MGR_SEND_CHAINTASK);

       }

       TX_RESTORE

       /* Assume that the system manager does its job.  */
       return (E_OK);

   } /* End if ( id == RES_SCHEDULER ).  */


   /* Not a RES_SCHEDULER.  */

   /* Are we releasing the resource which is last taken?  */
   for (index = 0u; index < OSEK_MAX_EXTERNAL_RES; index++)
   {
       if ( tcb_ptr->external_resource_occuplied_list[index] == 0u)
       {
           /* Reached at the last entry, stop searching.  */
           break;
       }
   } /* Next entry.  */

   if (index == 0u)
   {
       /* List is empty and resource is taken?  */
       return(E_OS_NOFUNC);
   }

   location = index - 1u; /* Save the location of last resource entry.  */

   /* Check the last resource taken.  */
   if (tcb_ptr->external_resource_occuplied_list[location] != id)
   {
       /* Are we trying to release the resource which was not in LIFO order.  */
       exec_ErrorHook(E_OS_NOFUNC);

       /* Return error.  */
       return(E_OS_NOFUNC);
   }

   /* Now to change preemption threshold to suit next resource with highest ceiling priority */
   /* But if the task has got NON scheduling policy then do nothing.  */

   tcb_ptr->external_resource_occuplied_list[location] = 0u;
   /* And remove this task's id from the res's control block.  */
   osek_res->taskid = 0u;
   tcb_ptr->res_ocp--;

   if ((tcb_ptr->policy == NON ) || (tcb_ptr->resource_scheduler == TX_TRUE))
   {
       /* In case of NON scheduling policy or if a Task holds a RES_SCHEDULER, no need to change preemption.  */
       /* Even if a resource is released the task is still remains in OSEK_NON_SCHEDULE_PRIORITY.  */
       /* just  remove this resource from the list.  */
       return (E_OK);
   }

   /* FULL scheduling policy and no RES_SCHEDULER held.  */

   /* Assume no other resources are held.  */
   new_prio = tcb_ptr->org_prio;

   if (tcb_ptr->res_ocp > 0u)
   {
       /* This task is holding more than one resources.  */
       /* Find out new highest ceiling priority.  */
       /* Assume task's original priority is the highest.  */
       for ( index = 0u; index < OSEK_MAX_EXTERNAL_RES; index++)
       {

           /* Get this resource's ceiling priority.  */
           if ( tcb_ptr->external_resource_occuplied_list[index] == 0u) {
               break;
           }

           res_prio = ((OSEK_RESOURCE *) (tcb_ptr->external_resource_occuplied_list[index]) )->c_priority;
           /* Check if this is more than Task's static priority.  */
           if (new_prio < res_prio)
           {
                new_prio = res_prio;
           }
       }

   }

   /* Done with external resource, now check if there are any internal resources held?  */
   for (index = 0u; index < OSEK_MAX_INTERNAL_RES; index++)
   {
       if (tcb_ptr->internal_resource_occuplied_list[index] == 0u)
       {
           break;
       }

       res_prio = ( (OSEK_RESOURCE *) (tcb_ptr->internal_resource_occuplied_list[index]) )->c_priority;

       if (new_prio < res_prio )
       {
           new_prio = res_prio;
       }
   }

   /* new_prio now holds the highest of ceiling priority of the remaining
      resources held by this task.  */

   /* Now ask the system manager to change this task's priority, and also check if there is
      any possibility of preemption.  */
   /* Send message to system manager to check any preemption out of ReleaseResource call.  */

   /* Build the request.  */
   request[0] = SYSMGR_RELEASE_RESOURCE;          /* Request type.  */
   request[1] = (ULONG)this_thread;
   request[2] = (ULONG)new_prio;
   request[3] = 0u;

   /* Since the SysMgr supervisor thread has the highest priority,      */
   /* this routine will be preempted by SysMgr supervisor thread when   */
   /* queue is successful.                                              */
   /* System manager will eventually call start_osek_tasks.             */

   status = tx_queue_send(&osek_work_queue, request, TX_NO_WAIT);

   TX_RESTORE

   /* This should always succeed.  */
   if (status != TX_SUCCESS)
   {
       /* System internal error.  */
       osek_internal_error(SYS_MGR_SEND_CHAINTASK);
   }

   /* Assume that system manager does its job.  */
   return (E_OK);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    RegisterTasktoResource                              PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*   This function registers a resource to the task specified, provided   */
/*   a free entry is available in the task's list of resources.           */
/*   If entry is registered then resource's ceiling priority is also      */
/*   adjusted to this task's priority provided that the task's priority   */
/*   is higher than the resource's current ceiling priority.              */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    Resource                     Id of the resource.                    */
/*    TaskID                       ID of the task                         */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    E_OK                         If successful                          */
/*    E_OS_NOFUNC                  No free entries                        */
/*    E_OS_ID                      Invalid task or resource id.           */
/*                                 not occupied by any task or ISR, or    */
/*                                 another resource has to be released    */
/*                                 before.                                */
/*   E_OS_ACCESS                   Attempt to release an invalid resource */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*   Application Code  (System Creation section)                          */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
StatusType     RegisterTasktoResource(ResourceType Resource, TaskType TaskID)
{

OSEK_TCB       *tcb_ptr;
OSEK_RESOURCE  *resource_ptr;
UINT            index;

   /* Check if we are in initialization.  */
   /* This will ensure that no one calls this function after system is started.  */
   if (osek_init_state != OSEK_INIT)
   {
       /* Return OSEK internal error. This is not a standard OSEK error.  */
       Application->osek_object_creation_error++;
       return ((StatusType)TX_NULL);
   }

   /* Check for valid Resource ID.  */
   if(Resource == 0u)
   {
       /* Return error.  */
       Application->osek_object_creation_error++;
       return (E_OS_ID);
   }

   /* Check if task id is valid.  */
   if(TaskID == 0u)
   {
       /* Return error.  */
       return (E_OS_ID);
   }

   /* Convert object IDs to object control block pointers.  */
   resource_ptr = (OSEK_RESOURCE *)Resource;
   tcb_ptr = (OSEK_TCB *)TaskID;

    /* Check for valid resource pointer.  */
   if (resource_ptr == TX_NULL)
   {
       Application->osek_object_creation_error++;
       return (E_OS_ID);
   }

   if (resource_ptr->osek_res_id != OSEK_RES_ID)
   {
       Application->osek_object_creation_error++;
       return (E_OS_ID);
   }

   /* Check for valid task pointer.  */
   if (tcb_ptr == TX_NULL)
   {
       Application->osek_object_creation_error++;
       return (E_OS_ID);
   }

   if ((tcb_ptr->osek_task_id != OSEK_TASK_ID) && (tcb_ptr->osek_task_id != OSEK_ISR_ID))
   {
       Application->osek_object_creation_error++;
       return (E_OS_ID);
   }

   /* This task is to be registered with this resource.  */
   /* Add this Resource to the task's list of resource.  */
   /* provided there is space left for this.  */

   /* Before check whether the resource is internal or standard?  */
   if ((resource_ptr->type == STANDARD)|| (resource_ptr->type == LINKED))
   {

       for (index = 0u; index < OSEK_MAX_EXTERNAL_RES; index++)
       {
           if (tcb_ptr->external_resource_list[index] == 0u)
           {
               /* Empty entry found, write this resource there.  */
               tcb_ptr->external_resource_list[index] = Resource;

               /* Also clear the resource occupancy count.  */
               tcb_ptr->external_resource_occuplied_list[index] = 0u;

               /* As this resource is attached to a TASK or ISR change this resource's ceiling priority
                  to task's (or ISR's) priority provided that  it is higher than resource's current ceiling priority.  */
               if (tcb_ptr->org_prio > resource_ptr->c_priority)
               {
                   resource_ptr->c_priority = tcb_ptr->org_prio;
               }

               /* Job done.  */
               break;
           } /* Try next entry.  */
       }

       if (index >= OSEK_MAX_EXTERNAL_RES) /* No free entry.  */
       {
           Application->osek_object_creation_error++;
           return (E_OS_NOFUNC);
       }
       else
       {
           return (E_OK);
       }
   } /* END STANDARD.  */
   else
   {
       /* Attaching Internal resource to this task, so set the flag.  */
       tcb_ptr->internal_res = TX_TRUE;

       for (index = 0u; index < OSEK_MAX_INTERNAL_RES; index++)
       {
           if (tcb_ptr->internal_resource_list[index] == 0u)
           {
               /* Empty entry found write this resource there.  */
               tcb_ptr->internal_resource_list[index] = Resource;

               /* As this resource is attached to the resource change this resource's ceiling priority
                  to this task's original priority provide it is higher than resource's current ceiling priority.  */
               if (tcb_ptr->org_prio > resource_ptr->c_priority)
               {
                   resource_ptr->c_priority =  tcb_ptr->org_prio;
               }

               /* Job done.  */
               break;
           } /* Try next entry.  */
       }

       if (index >= OSEK_MAX_INTERNAL_RES) /* No free entry.  */
       {
           Application->osek_object_creation_error++;
           return (E_OS_NOFUNC);
       }
       else
       {
           return (E_OK);
       }
   }
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    RegisterISRtoResource                               PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*   This function registers a resource to the ISR specified, provided    */
/*   a free entry is available in the ISR's list of resources.            */
/*   If entry is registered then resource's ceiling priority is also      */
/*   adjusted to this task's priority provided that the task's priority   */
/*   is higher than the resource's current ceiling priority.              */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    Resource                     Id of the resource.                    */
/*    TaskID                       ID of the task                         */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    E_OK                         If successful                          */
/*    E_OS_NOFUNC                  No free entries                        */
/*    E_OS_ID                      Invalid task or resource id.           */
/*                                 not occupied by any task or ISR, or    */
/*                                 another resource has to be released    */
/*                                 before                                 */
/*   E_OS_ACCESS                   Attempt to release an invalid resource */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    RegisterTasktoResource       Register resource.                     */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*   Application Code                                                     */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
StatusType     RegisterISRtoResource(ResourceType Resource, ISRType ISRID)
{
StatusType     status;

   status = RegisterTasktoResource(Resource, ISRID);
   return (status);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    CreateEvent                                         PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    Creates an event. It is a 32 bit number with only one bit set.      */
/*                                                                        */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    eventid                      If success                             */
/*    0                            If error occurs                        */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    osek_get_event               Get the event                          */
/*    osek_internal_error          OSEK internal error                    */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*   OSEK internal call                                                   */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
EventMaskType CreateEvent(void)
{
EventMaskType  event;

   event = osek_get_event();
   if (event == 0u)
   {
       /* Error will be returned whenever the ThreadX call fails.  */
       Application->osek_object_creation_error++;
       return (0u);
   }

   return (event);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    SetEvent                                            PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    Sets events of the given task according to the event mask.          */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    task ID                      ID for the task                        */
/*    mask                         Mask of the events to be set.          */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    E_OK                         If successful                          */
/*    E_OS_ID                      Invalid task or event id               */
/*    E_OS_STATE                   Invalid target task state              */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    tx_event_flags_set            Set ThreadX event flag.               */
/*    osek_internal_error           OSEK Internal error                   */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*   Application Code                                                     */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
StatusType  SetEvent(TaskType task_id, EventMaskType mask)
{
TX_INTERRUPT_SAVE_AREA
OSEK_TCB       *tcb_ptr;
TX_THREAD      *this_thread;
EventMaskType   balance_events;
ULONG           request[SYSMGR_QUEUE_MSG_LENGTH];
UINT            status;
OSEK_TCB       *p_this_tcb;


   service_GetServiceId.id = (OsServiceIdType)OSServiceId_SetEvent;
   service_SetEvent.TaskID = task_id;

   /* Check if task id not valid.  */
   if(task_id == 0u)
   {
       exec_ErrorHook(E_OS_ID);

       /* Return error.  */
       return (E_OS_ID);
   }

   /* Get TCB_PTR.  */
   tcb_ptr = (OSEK_TCB *)task_id;

   if (tcb_ptr->osek_task_id != OSEK_TASK_ID)
   {
       exec_ErrorHook(E_OS_ID);

       /* Return error.  */
       return (E_OS_ID);
   }

   /* Check if any event is assigned to task.  */
   if ((tcb_ptr->events == 0u) || (tcb_ptr->task_type == BASIC))
   {
       exec_ErrorHook(E_OS_ACCESS);

       /* No event assigned to task, return error.  */
       return (E_OS_ACCESS);
   }

   TX_DISABLE

   if (tcb_ptr->suspended == TX_TRUE)
   {
       TX_RESTORE

       exec_ErrorHook(E_OS_STATE);

       /* Return error.  */
       return (E_OS_STATE);
   }

   /* Check this event mask with the task .  */
   /* Update the set events for this task with this new mask.  */
   tcb_ptr->set_events = tcb_ptr->set_events | mask;

   /* See how many events are set.  */
   balance_events = tcb_ptr->set_events & tcb_ptr->waiting_events;

   /* Is there any from waiting events.  */
   if (balance_events != 0u)
   {
       /* Get calling task's ThreadX thread */
       this_thread = tx_thread_identify();

       /* Check whether the same running task is setting its own events or
          the task is already out of wait state.  */
       /* if yes then no need to add this task in the ready list and of course no
          need to check for any preemption possibilities.  */

       p_this_tcb = osek_thread2tcb(this_thread);
       if ((tcb_ptr != p_this_tcb) && (tcb_ptr->waiting == TX_TRUE))
       {
            tcb_ptr->waiting = TX_FALSE;
            /* Now, send message to the system manager to check any preemption out of SetEvent() call.  */

           /* Build the request. */
           request[0] = SYSMGR_SETEVENT;              /* Request type.  */
           request[1] = (ULONG)this_thread;           /* ThreadX Thread for this task.  */
           request[2] = (ULONG)tcb_ptr;               /* id in OSEK_TCB format.  */
           request[3] = 0u;

           /* Since the SysMgr supervisor thread has the highest priority,      */
           /* this routine will be preempted by SysMgr supervisor thread when   */
           /* queue is successful.                                              */
           /* System Manager will eventually call start_osek_tasks.             */

           status = tx_queue_send(&osek_work_queue, request, TX_NO_WAIT);

           /* This should always succeed.  */
           if (status != TX_SUCCESS)
           {
               /* System internal error.  */
               osek_internal_error(SYS_MGR_SEND_CHAINTASK);

           }
       }

   }

   TX_RESTORE

   return (E_OK);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    ClearEvent                                          PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    Clears events of the calling task according to the event mask.      */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    mask                         Mask of the events to be cleared       */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    E_OK                         If success                             */
/*    ERROR                        If error occurs while creating task    */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    tx_event_flags_set            Set or clears ThreadX event flag      */
/*    osek_task_independent_area    See if out of task context            */
/*    tx_thread_identify            Identify the current thread           */
/*    tx_event_flags_set            Set the event Flags                   */
/*    osek_internal_error           OSEK internal error                   */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*   Application Code                                                     */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
StatusType  ClearEvent(EventMaskType mask)
{
TX_INTERRUPT_SAVE_AREA
TX_THREAD               *this_thread;
OSEK_TCB                *tcb_ptr;
ULONG                    area;

    service_GetServiceId.id = (OsServiceIdType)OSServiceId_ClearEvent;
    service_ClearEvent.EventID = mask;
    /* Check if we are calling from initialization.  */
    if (osek_init_state == OSEK_INIT)
    {
        exec_ErrorHook(E_OS_CALLEVEL);

        /* Return error.  */
        return (E_OS_CALLEVEL);
    }

    /* Check if we are not at task level.  */
    area = osek_task_independent_area();
    if(area == 0u)
    {
        exec_ErrorHook(E_OS_CALLEVEL);

        /* Return error.  */
        return (E_OS_CALLEVEL);
    }

    this_thread = tx_thread_identify();

    /* Get OSEK TCB.  */
    tcb_ptr = (OSEK_TCB *)this_thread;

    /* Check if any event is assigned to task.  */
    if ((tcb_ptr->events == 0u) || (tcb_ptr->task_type == BASIC))
    {
        exec_ErrorHook(E_OS_ACCESS);

        /* No event assigned to task, return error.  */
        return (E_OS_ACCESS);
    }

    TX_DISABLE

    /* Update the events.  */
    tcb_ptr->set_events = tcb_ptr->set_events & (~mask);
    TX_RESTORE

    return (E_OK);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    GetEvent                                            PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    Gets the current event setting of the given task.                   */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    task_id                      ID or the task                         */
/*    mask                         Mask of the events to be set.          */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    E_OK                         If successful                          */
/*    ERROR                        If an error occurs                     */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    osek_internal_error          OSEK internal error                    */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*   Application Code                                                     */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
StatusType  GetEvent(TaskType task_id, EventMaskRefType event)
{
TX_INTERRUPT_SAVE_AREA
OSEK_TCB               *tcb_ptr;

    service_GetServiceId.id = (OsServiceIdType)OSServiceId_GetEvent;
    service_GetEvent.TaskID = task_id;

    /* Check if task id is valid.  */
    if(task_id == 0u)
    {
        exec_ErrorHook(E_OS_ID);

        /* Return error.  */
        return (E_OS_ID);
    }

    /* Get the tcb pointer.  */
    tcb_ptr = (OSEK_TCB *)task_id;

    if (tcb_ptr->osek_task_id != OSEK_TASK_ID)
    {
        exec_ErrorHook(E_OS_ID);

        /* Return error.  */
        return (E_OS_ID);
    }

    /* Check if any event is assigned to task and task is extended type.  */
    if ((tcb_ptr->events == 0u) || (tcb_ptr->task_type == BASIC))
    {
        exec_ErrorHook(E_OS_ACCESS);

        /* No event assigned to task, return error.  */
        return (E_OS_ACCESS);
    }

    TX_DISABLE

    if (tcb_ptr->suspended == TX_TRUE)
    {
        TX_RESTORE

        exec_ErrorHook(E_OS_STATE);

        /* Return error.  */
        return (E_OS_STATE);
    }

    /* Get the event.  */
    *event = tcb_ptr->set_events;

    TX_RESTORE

    return (E_OK);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    WaitEvent                                           PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    Transfers the calling task into the waiting state until specified   */
/*    events are set.                                                     */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    mask                         Mask of the events to be set           */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    E_OK                         If success                             */
/*    ERROR                        If error occurs while creating task    */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    tx_event_flags_get           Retrieves ThreadX event flag from      */
/*                                 specified ThreadX event flag group     */
/*    osek_internal_error          OSEK internal error                    */
/*    tx_thread_identify           Identify current thread                */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*   Application Code                                                     */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
StatusType  WaitEvent(EventMaskType mask)
{
TX_INTERRUPT_SAVE_AREA
OSEK_TCB              *tcb_ptr;
TX_THREAD             *this_thread;
ULONG                  request[SYSMGR_QUEUE_MSG_LENGTH];
UINT                   index;
UINT                   status;


    service_GetServiceId.id = (OsServiceIdType)OSServiceId_WaitEvent;
    service_WaitEvent.EventID = mask;


    /* Check if we are in interrupt.  */
    if((_tx_thread_current_ptr == TX_NULL) ||           /* Not in a task.  */
       (_tx_thread_system_state != 0u))                 /* In an ISR.      */
    {
        exec_ErrorHook(E_OS_CALLEVEL);

        /* Return error.  */
        return (E_OS_CALLEVEL);
    }

    /* Check if the thread is currently executed.  */
    this_thread = tx_thread_identify();
    if(this_thread == TX_NULL)
    {
        exec_ErrorHook(E_OS_CALLEVEL);

        /* Not allowed on the calling thread.  */
        return (E_OS_CALLEVEL);
    }

    /* Get OSEK TCB.  */
    tcb_ptr = (OSEK_TCB *)this_thread;

    /* Check if any event is assigned to task or the task is of BASIC type.  */
    if ((tcb_ptr->events == 0u) || (tcb_ptr->task_type == BASIC))
    {
        exec_ErrorHook(E_OS_ACCESS);

        /* No event assigned to task, return error.  */
        return (E_OS_ACCESS);
    }

    /* Check if any resource is occupied by this task.  */
    if(tcb_ptr->res_ocp != 0u)
    {
        exec_ErrorHook(E_OS_RESOURCE);

        /* Return error.  */
        return (E_OS_RESOURCE);
    }

    TX_DISABLE

    tcb_ptr->waiting_events = mask;

    /* Is any event set?  */
    if ((tcb_ptr->set_events & tcb_ptr->waiting_events) != 0u)
    {
        TX_RESTORE

        return (E_OK);
    }
    else
    {
        /* Events are not set wait for them.  */
        tcb_ptr->waiting = TX_TRUE;
    }

    /* Release any internal resources held.  */
    if (tcb_ptr->internal_res != 0u)
    {
        for (index = 0u; index < OSEK_MAX_INTERNAL_RES; index++)
        {
            if (tcb_ptr->internal_resource_occuplied_list[index] == 0u)
            {
                break;
            }

            ((OSEK_RESOURCE *)(tcb_ptr->internal_resource_occuplied_list[index]))->taskid = 0u;
            tcb_ptr->internal_resource_occuplied_list[index] = 0u;

        }
    }

    /* Now, send message to system thread to check any preemption out of the WaitEvent() call.  */

    /* Build the request.  */
    request[0] = SYSMGR_WAITEVENT;               /* Request type.  */
    request[1] = (ULONG)this_thread;             /* Self ID.  */
    request[2] = (ULONG)tcb_ptr;                 /* Self Id in OSEK_TCB format.  */
    request[3] = 0u;
    /* Now send a message to the SysMgr supervisor thread and ask        */
    /* to check any preemption is possible.                              */
    /* Since the SysMgr supervisor thread has the highest priority,      */
    /* this routine will be preempted by SysMgr supervisor thread when   */
    /* queue is successful.                                              */
    /* System Manager will eventually call start_osek_tasks.             */

    status = tx_queue_send(&osek_work_queue, request, TX_NO_WAIT);

    TX_RESTORE

    /* This should always succeed.  */
    if (status != TX_SUCCESS)
    {
       /* System internal error.  */
       osek_internal_error(SYS_MGR_SEND_CHAINTASK);
    }

    return (E_OK);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    RegisterEventtoTask                                 PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*   This function registers an event to the task specified, provided     */
/*   a free entry is available in the task's list of events.             */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    event_id                     Id of the event                        */
/*    TaskID                       Id of the task                         */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    E_OK                         If successful                          */
/*    E_OS_NOFUNC                  No free entries                        */
/*    E_OS_ID                      Invalid task or resource id.           */
/*                                 not occupied by any task or ISR, or    */
/*                                 another resource has to be released    */
/*                                 before.                                */
/*   E_OS_ACCESS                   Attempt to release an invalid resource */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*   Application Code  (System Creation section)                          */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
StatusType    RegisterEventtoTask(EventMaskType eventid, TaskType TaskID)
{

OSEK_TCB      *tcb_ptr;

    /* Check if we are in initialization.  */
    /* This will ensure that no one calls this function after system is started.  */
    if (osek_init_state != OSEK_INIT)
    {
        /* Return OSEK internal error. This is not a standard OSEK error.  */
        Application->osek_object_creation_error++;
        return ((StatusType)TX_NULL);
    }

    /* Check if task id is valid.  */
    if(TaskID == 0u)
    {

        /* Return error.  */
        Application->osek_object_creation_error++;

        return (E_OS_ID);
    }



    /* Convert object IDs to object control block pointers.  */
    tcb_ptr = (OSEK_TCB*)TaskID;


    /* Check for valid task pointer.  */
    if (tcb_ptr == TX_NULL)
    {
        Application->osek_object_creation_error++;

        return (E_OS_ID);
    }

    if(tcb_ptr->osek_task_id != OSEK_TASK_ID)
    {
        Application->osek_object_creation_error++;

        return (E_OS_ID);
    }

    /* This task is to be registered with this event.  */
    tcb_ptr->events = tcb_ptr->events | eventid;


    return (E_OK);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    EnableInterrupt                                     PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This service enables interrupts.                                    */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    E_OK                         If successful                          */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*   Application Code                                                     */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
StatusType  EnableInterrupt(void)
{
    TX_INTERRUPT_SAVE_AREA

    TX_DISABLE

    if (disable_ISR2 != 0u) {
        disable_ISR2--;
    }

    TX_RESTORE

    return (E_OK);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    DisableInterrupt                                    PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This service disables interrupts.                                   */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    E_OK                         If successful                          */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*   Application Code                                                     */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
StatusType  DisableInterrupt(void)
{
    TX_INTERRUPT_SAVE_AREA

    TX_DISABLE

    disable_ISR2++;

    TX_RESTORE

    return (E_OK);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    GetInterruptDescriptor                              PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    Query of interrupt status and returns the current CPU interrupt     */
/*    mask                                                                */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    mask                        A reference to the interrupt mask to be */
/*                                filled. In the mask, a "1" means (Group */
/*                                of) Interrupt is enabled.               */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    E_OK                         If success                             */
/*    ERROR                        If error occurs while creating task    */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    tx_interrupt_control         Enables or disables interrupts         */
/*                                 specified by new_posture               */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*   Application Code                                                     */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
StatusType  GetInterruptDescriptor(UINT *mask)
{
UINT       old_posture;
UINT       new_posture;

    /* Get the old posture of the interrupt.  */
    old_posture = tx_interrupt_control(TX_INT_DISABLE);

    new_posture = old_posture;

    /* Invert the mask for OSEK interrupt.  */
    *mask = ~old_posture ;

    /* Restore the same interrupts.  */
    tx_interrupt_control(new_posture);

    return (E_OK);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    SuspendAllInterrupts                                PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*   This call serves to enter critical sections by disabling all         */
/*   interrupts.                                                          */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    E_OK                         If successful                          */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*   Application Code                                                     */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
void   SuspendAllInterrupts (void)
{
    TX_INTERRUPT_SAVE_AREA

    TX_DISABLE
    suspend_ISR2++;
    TX_RESTORE
}

/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    ResumeAllInterrupts                                 PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*   Exits a critical section entered by calling SuspendAllInterrupts.    */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    E_OK                         If successful                          */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    osek_task_independent_area   See if called from task independent    */
/*                                 area                                   */
/*    tx_thread_identify           Identify the current thread            */
/*    osek_internal_error          Osek internal error                    */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*   Application Code                                                     */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
void   ResumeAllInterrupts (void)
{
TX_INTERRUPT_SAVE_AREA
TX_THREAD      *thread_ptr;
UINT           status;
ULONG          request[SYSMGR_QUEUE_MSG_LENGTH];

    TX_DISABLE
   if (suspend_ISR2 != 0u)
   {
       suspend_ISR2--;
   }

   if (suspend_ISR2 == 0u)
   {
       /* Interrupts resume, check if any pending.  */
       /* get the pointer to the calling thread.  */
       thread_ptr = tx_thread_identify();

       /* Now send a message to the SysMgr supervisor thread to execute the error hook.  */
       /* Build the request.  */
       request[0] = SYSMGR_ERRORHOOK;           /* Request type.            */
       request[1] = (ULONG)thread_ptr;          /* Ptr of calling thread.   */
       request[2] = 0u;                         /* Input to Error hook.     */
       request[3] = 0u;

       /* Since the SysMgr supervisor thread is has the highest priority,  */
       /* this routine will be preempted by SysMgr supervisor thread when   */
       /* queue read is successful.                                         */

       status = tx_queue_send(&osek_work_queue, request, TX_NO_WAIT);

       /* This should always succeed.  */
       if (status != TX_SUCCESS)
       {
           TX_RESTORE

           /* System internal error.  */
           osek_internal_error(SYS_MGR_SEND_CHAINTASK);

           /* Return.  */
           return;
       }

   } /* end  if (!suspend_ISR2).  */

   TX_RESTORE

   return;
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    DisableAllInterrupts                                PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*   This call serves to enter critical sections by disabling all         */
/*   interrupts.                                                          */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*   Application Code                                                     */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
void   DisableAllInterrupts (void)
{
TX_INTERRUPT_SAVE_AREA

    TX_DISABLE
    disable_ISR2++;
    TX_RESTORE
}

/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    EnableAllInterrupts                                 PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*   Exits a critical section entered by calling DisableAllInterrupts.    */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*   Application Code                                                     */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
void   EnableAllInterrupts (void)
{
TX_INTERRUPT_SAVE_AREA

    TX_DISABLE
    if (disable_ISR2 != 0u)
    {
        disable_ISR2--;
    }
    TX_RESTORE
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    SuspendOSInterrupts                                 PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*   This call serves to enter critical sections by disabling all         */
/*   interrupts.                                                          */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*   Application Code                                                     */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
void   SuspendOSInterrupts (void)
{
TX_INTERRUPT_SAVE_AREA

    TX_DISABLE
    suspend_ISR2++;
    TX_RESTORE
}

/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    ResumeOSInterrupts                                  PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*   Exits a critical section entered by calling SuspendOSInterrupts.     */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    osek_task_independent_area   See if called from task independent    */
/*                                 area                                   */
/*    tx_thread_identify           Identify the current thread            */
/*    osek_internal_error          OSEK internal error                    */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*   Application Code                                                     */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
void   ResumeOSInterrupts (void)
{
TX_INTERRUPT_SAVE_AREA
TX_THREAD      *thread_ptr;
UINT           status;
ULONG          request[SYSMGR_QUEUE_MSG_LENGTH];

    TX_DISABLE

   if (suspend_ISR2 != 0u)
   {
       suspend_ISR2--;
   }

   if (suspend_ISR2 == 0u)
   {
       /* Interrupts resume, check if any pending.  */
       /* get the pointer to the calling thread.  */
       thread_ptr = tx_thread_identify();

       /* Now send a message to the SysMgr supervisor thread to execute the error hook  */
       /* Build the request.  */
       request[0] = SYSMGR_ERRORHOOK;           /* Request type.  */
       request[1] = (ULONG)thread_ptr;          /* Pointer of calling thread.  */
       request[2] = 0u;                         /* Input to Error hook.  */
       request[3] = 0u;

       /* Since the SysMgr supervisor thread is with the highest priority,  */
       /* this routine will be preempted by SysMgr supervisor thread when   */
       /* queue read is successful.                                         */

       status = tx_queue_send(&osek_work_queue, request, TX_NO_WAIT);

       /* This should always succeed.  */
       if (status != TX_SUCCESS)
       {
           TX_RESTORE

           /* System internal error.  */
           osek_internal_error(SYS_MGR_SEND_CHAINTASK);

           /* Return.  */
           return;
       }

   } /* end  if (!suspend_ISR2). */

   TX_RESTORE

   return;
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    GetActiveApplicationMode                            PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*   This call returns the current application mode.                      */
/*                                                                        */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    Current application mode                                            */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*   Application Code                                                     */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
AppModeType GetActiveApplicationMode(void)
{
    return (Application->application_mode);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    GetCounterValue                                     PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    Returns the current value of a counter.                             */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    counter_ptr                          Pointer to OSEK Counter        */
/*    tick_ptr                             Pointer to ticks               */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    E_OK                                 If successful                  */
/*    E_OS_ID                              Invalid counter object         */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*   None                                                                 */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*   Application Code                                                     */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
StatusType  GetCounterValue(OSEK_COUNTER *counter_ptr, TickRefType tick_ptr)
{

    /* Check for valid counter.  */
    if ((counter_ptr != TX_NULL) && (counter_ptr->osek_counter_id == OSEK_COUNTER_ID))
    {
        *tick_ptr = counter_ptr->counter_value;
    }
    else
    {
        /* There is error in counter object supplied.  */
        return (E_OS_ID);
    }

    return (E_OK);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    CreateCounter                                       PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    Creates a counter.                                                  */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    N/A                                                                 */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    COUNTER_ID                   Reference to counter                   */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    osek_memory_allocate         Allocate memory from system            */
/*    osek_counter_name_check      Check if counter name duplicate        */
/*    osek_get_counter             Get pointer to counter structure       */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*   Application Code                                                     */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
CounterType  CreateCounter(const CHAR *name, TickType max_allowed_value, TickType ticks_per_base,
                       TickType min_cycle, TickType start_value)
{

CounterType      cntr_id;
OSEK_COUNTER     *cntr_ptr;
UINT             index;

    /* Check if we are in initialization.  */
    /* This will ensure that no one calls this function after system is started.  */
    if (osek_init_state != OSEK_INIT)
    {
        /* Return OSEK internal error. This is not a standard OSEK error.  */
        Application->osek_object_creation_error++;

        return((TaskType)TX_NULL);
    }

    /* Check if there is space for this counter.  */
    cntr_id = osek_get_counter();
    if (cntr_id == 0u)
    {
        /* Return error.  */
        Application->osek_object_creation_error++;

        return ((CounterType) TX_NULL);
    }

    /* Get the pointer to counter structure.  */
    cntr_ptr = (OSEK_COUNTER *)cntr_id;


    if (max_allowed_value > MAXALLOWEDVALUE)
    {
        /* Return OSEK internal error. This is not a standard OSEK error.  */
        Application->osek_object_creation_error++;

        return ((TaskType)TX_NULL);
    }

    /* Store maximum value of this counter.  */
    cntr_ptr->maxallowedvalue = max_allowed_value;

    if (min_cycle > MAXALLOWEDVALUE)
    {
        /* Return OSEK internal error. This is not a standard OSEK error.  */
        Application->osek_object_creation_error++;

        return ((TaskType)TX_NULL);
    }

    /* Store minimum allowed number of ticks of the counter.  */
    cntr_ptr->mincycle = min_cycle;

    if (ticks_per_base > MAXALLOWEDVALUE)
    {
        /* Return OSEK internal error. This is not a standard OSEK error.  */
        Application->osek_object_creation_error++;

        return ((TaskType)TX_NULL);
    }

    /* Store ticksperbase.  */
    cntr_ptr->ticksperbase = ticks_per_base;

    /* Store start up value.  */
    if (start_value > max_allowed_value)
    {
        cntr_ptr->counter_value = start_value;
    }
    else
    {
        cntr_ptr->counter_value = 0u;
    }

    /* Store object identifier.  */
    cntr_ptr->osek_counter_id = OSEK_COUNTER_ID;

    /* Now initialize the list of alarms attached to this counter.  */

    for (index = 0u; index < OSEK_MAX_ALARMS; index++)
    {
        cntr_ptr-> alarm_list[ index ] = 0u;
    }

    cntr_ptr->cntr_in_use = TX_TRUE;

    cntr_ptr->name = name;

    /* Return the created counter.  */
    return ((CounterType) cntr_ptr);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    IncrCouner                                          PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function increments the specified counter, checks its new      */
/*    value with all alarms attached to it and triggers expired alarms.   */
/*    If an alarm is expired then its actions are executed from here.     */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    Counter                       Counter to update                     */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    E_OK                          If successful                         */
/*    E_OS_ID                       If counter id is not correct          */
/*    E_OS_NOFUNC                   In case of any errors                 */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    osek_internal_error          OSEK internal error                    */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*   Application Code                                                     */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
StatusType     IncrCounter(CounterType cntr)
{

TX_INTERRUPT_SAVE_AREA

OSEK_COUNTER   *cntr_ptr;
UINT           index;
UINT           msg_cnt;
UINT           save_op_mode;
AlarmType      alarmid;
OSEK_ALARM     *this_alarm;
UINT           this_action;
UINT           alarm_fired;
UINT           status;
OSEK_TCB       *tcb_ptr;
ULONG          request[SYSMGR_QUEUE_MSG_LENGTH];
EventMaskType  balance_events;

cntr_ptr = (OSEK_COUNTER *)cntr;

    /* Check for valid counter.  */
    if ((cntr_ptr == TX_NULL) && (cntr_ptr->osek_counter_id != OSEK_COUNTER_ID))
    {
        /* There is error in counter object supplied.  */
        return (E_OS_ID);
    }

    /* Disable interrupt.  */
    TX_DISABLE

    if (cntr_ptr->cntr_in_use == TX_FALSE)
    {
        TX_RESTORE

        return (E_OS_ID);
    }

    if (cntr_ptr->ticksperbase == 0u)
    {
        TX_RESTORE

        return (E_OS_NOFUNC);
    }


    /* Increment counters sub count and check it with tick_pre-Base.  */
    cntr_ptr->sub_count++;
    if (cntr_ptr->sub_count < cntr_ptr->ticksperbase)
    {
        /* Still need to count enough to reach tics-per-base, no need to increment
           main count.  */
        TX_RESTORE

        return (E_OK);
    }

    /* Reached to tick-per-base, reset it and increment main count.  */
    cntr_ptr->sub_count = 0u;

    /* Now increment the counter value.  */
    if ( cntr_ptr->counter_value >= cntr_ptr->maxallowedvalue)
    {
        cntr_ptr->counter_value = 0u;
    }
    else
    {
        (cntr_ptr->counter_value)++;
    }

    /* Now check if counter is rolled back to zero.  */
    if ( cntr_ptr->counter_value == 0u)
    {
        /* Counter is rolled back set flags in all Alarms attached to this counter.  */
        for (index = 0u; index < OSEK_MAX_ALARMS; index++)
        {
            alarmid = cntr_ptr->alarm_list[index];
            if (alarmid == 0u)
            {
                continue;
            }

            /* Something is defined.  */
            this_alarm = (OSEK_ALARM *)alarmid;

            /* But is it a valid OSEK ALARM?  */
            if((this_alarm == TX_NULL) || (this_alarm->osek_alarm_id != OSEK_ALARM_ID))
            {
                continue;
            }

            /* Yes this is a valid alarm , but is it armed?  */
            if ( this_alarm->armed == TX_FALSE)
            {
                continue;
            }
            /* This is an ALARM and is armed, set its rollback flag.  */
            /* This flag will be cleared when an alarm is armed again or expired.  */
            this_alarm->counter_rollback = TX_TRUE;
        }
    }

    /* Reset a count of messages sent to the system manager.  */
    msg_cnt = 0u;

    /* Now it is time to check all alarms for expiration.  */
    for (index = 0u; index < OSEK_MAX_ALARMS; index++)
    {

        alarm_fired = TX_FALSE;

        /* Get the alarm id.  */
        alarmid = cntr_ptr->alarm_list[index];
        if (alarmid == 0u)
        {
            continue;                                           /* This alarm is not for me, go to check next alarm.  */
        }

        /* Something is defined, try to get the AlarmID.  */
        this_alarm = (OSEK_ALARM *)alarmid;

        /* But is it a valid OSEK ALARM?  */
        if((this_alarm == TX_NULL) || (this_alarm->osek_alarm_id != OSEK_ALARM_ID))
        {
            continue;
        }

        /* Yes this is a valid alarm , but is it armed?  */
        if (this_alarm->armed == TX_FALSE)                     /* This alarm is not armed, go to check next alarm.  */
        {
            continue;
        }

        /* Now check this with counter's current value, if it is less than it do not fire alarm.  */
        if (this_alarm->rel_abs_mode == RELATIVE_ALARM)
        {
            /* It is a REALTIVE ALARM.  */
            if (cntr_ptr->counter_value < this_alarm->expiration_count)
            {
                continue;                                                      /* Not yet expired.  */
            }
            else
            {
                /* Alarm expired, set flag.  */
                alarm_fired = TX_TRUE;
            }
        } /* End  It is a REALTIVE ALARM.  */
        else
        {
            /* It is ABSOLUTE ALARM.  */
            if (cntr_ptr->counter_value < this_alarm->expiration_count)
            {
                /* counter is less than expiration. */
                continue;                                                         /* Not yet expired.  */
            }

            if (cntr_ptr->counter_value == this_alarm->expiration_count)
            {
                /* If both are equal alarm is fired.  */
                alarm_fired = TX_TRUE;
            }
            else
            {
            /* count > expiration alarm to fire only if roll back occurred.  */
            /* This check is required, because when an Alarm is started in ABS mode, counter's current value could
               be more than the alarm's expiration count, so that may fire an Alarm the moment it is Armed,
               in fact, under such condition (counter's current value  more than
               the alarm's expiration count, at the time of arming the alarm) the alarm will expires only when , the
               counter counts to its max value then rolls back to zero then again counts up and now when it
               reaches the alarm's expiration count, the alarm gets fired.  */

                if (this_alarm->counter_rollback == TX_FALSE)
                {
                    continue;
                }
                else
                {
                    alarm_fired = TX_TRUE;
                }

            }

        }  /*   END:  else { ABSOLUTE ALARM ..  */


        /* STILL IN for  ( index = 0; index < OSEK_MAX_ALARMS; index++)  LOOP.  */

        /* Check alarm has fired?  */

        if (alarm_fired == TX_FALSE)
        {
            continue;
        }

        /* Reached here means an alarm has fired.  */
        /* Clear the counter roll back flag.  */
        this_alarm->counter_rollback = TX_FALSE;

        /* Dis arm the Alarm */
        this_alarm->armed = TX_FALSE;

        /* But is it cyclic?  */
        if (this_alarm->cycle != 0u)
        {
            /* Yes, then load new expiration count.  */
            this_alarm->expiration_count += this_alarm->cycle;
            /* Arm the alarm for next cycle.  */
            this_alarm->armed = TX_TRUE;
        }

        /* Get what action to be taken for this alarm.  */
        this_action = this_alarm->action;

        /* Check for action to be taken.  */
        switch(this_action)
        {
            case CALLBACK:

                /* Call a call-back function.  */
                if (this_alarm->alarm_callback != TX_NULL)
                {
                    save_op_mode  = osek_wrapper_operation_mode;
                    osek_wrapper_operation_mode = ALARM_CALLBACK_MODE;
                    (this_alarm->alarm_callback)();
                    osek_wrapper_operation_mode = save_op_mode;
                 }
                 break;

            case ACTIVATETASK:
                /* Activate a task.  */
                /* Get the OSEK TCB for the task to be activated.  */
                tcb_ptr = (OSEK_TCB *)(this_alarm->task);

                /* Check for any invalid thread pointer.  */
                if((tcb_ptr == TX_NULL) || ((tcb_ptr->task.tx_thread_id) != TX_THREAD_ID))
                {
                    break;
                }

                /* Check whether the task is activated up to its defined multiple activations.  */
                if(tcb_ptr->current_active >= tcb_ptr->max_active)
                {
                    break;
                }

               /* Now send a message to the System Manager thread to activate this task.  */
               /* Build the request.  */
               request[0] = SYSMGR_ACTIVATE_TASK;                /* Request type.  */
               request[1] = (ULONG)tcb_ptr;                      /* task to Activate.  */
               request[2] = last_run_task;                       /* task currently executing.  */
               request[3] = 0u;
               status = tx_queue_send (&osek_work_queue, request, TX_NO_WAIT);

               /* This should always succeed.  */
               if (status != TX_SUCCESS)
               {
                  /* System internal error.  */
                  osek_internal_error(SYS_MGR_SEND_ACTIVATETASK);
               }

               /* One message sent, increment the msg counter, this is required because
                  the System manager message queue can hold only certain number of messages.  */
               msg_cnt++;
               break;

            case SETEVENT:
                /* Set the specified events for the specified task.  */
                /* Check if task id not valid.  */
                if (this_alarm->task == TX_NULL)
                {
                    break;
                }

                /* Get TCB_PTR.  */
                tcb_ptr = (OSEK_TCB *) (this_alarm->task);

                if (tcb_ptr->osek_task_id != OSEK_TASK_ID)
                {
                    break;
                }

                    /* Check if any event is assigned to task.  */
                    if ((tcb_ptr->events == 0u) || (tcb_ptr->task_type == BASIC))
                    {
                        break;
                    }

                    if (tcb_ptr->suspended == TX_TRUE)
                    {
                        break;
                    }

                    /* Check this event mask with the task.  */
                    /* Update the set events for this task with this new mask.  */
                    tcb_ptr->set_events = tcb_ptr->set_events | (this_alarm->events);

                    /* See if any events is set.  */
                    balance_events = tcb_ptr->set_events & tcb_ptr->waiting_events;

                    /* Is there any from waiting events.  */
                    if (balance_events != 0u)
                    {

                        if (tcb_ptr->waiting == TX_TRUE)
                        {
                            tcb_ptr->waiting = TX_FALSE;
                            /* Now, send message to the system manager to check any preemption out of SetEvent call. */

                            /* Build the request. */
                            request[0] = SYSMGR_SETEVENT;            /* Request type.  */
                            request[1] = last_run_task;              /* Task currently executing.  */
                            request[2] = (ULONG)tcb_ptr;             /* Task id for which events are set.  */
                            request[3] = 0u;
                            status = tx_queue_send(&osek_work_queue, request, TX_NO_WAIT);

                            /* This should always succeed.  */
                            if (status != TX_SUCCESS)
                            {
                                /* System internal error.  */
                                osek_internal_error(SYS_MGR_SEND_CHAINTASK);
                            }


                            /* One message sent, increment the msg counter, this required because
                               System manager message queue can hold only certain number of messages.  */
                            msg_cnt++;

                        }  /* End if (tcb_ptr->waiting == TX_TRUE).  */
                    }      /* End if (balance_events).  */
                    break;

            default:
           break;
        } /* switch ends.  */

        /* A situation may arise that multiple alarms expire at time (being set to same expiration count and mode)
           Which means timer has to send multiple alarm action messages to the system manager. But as the system manager accepts
           only certain number of messages at a time, we can't send more than that number of alarm action
           messages (SetEvent, ActivateTask) in one loop,
           so check if the system manager queue is filled up if yes stop checking for next alarm, we'll come again to check
           balance alarms.  */

        if (msg_cnt == (SYSMGR_QUEUE_MSG_COUNT))
        {
            break;
        }

    }  /* for ends.  */

    /* Enable interrupt.  */
    TX_RESTORE

    return (E_OK);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    DefineSystemCounter                                 PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This functions sets the system counter by assigning the specified   */
/*    counter as a system counter.                                        */
/*    If a counter is already defined as a system counter this call will  */
/*    return an error.                                                    */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    Counter                       Counter to assign as system counter   */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    E_OK                          If successful                         */
/*    E_OS_ID                       If counter id is invalid              */
/*    E_OS_NOFUNC                   Counter already assigned              */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    tx_timer_activate             starts the Thread timer to update     */
/*                                  this SystemCounter                    */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*   Application Code                                                     */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
StatusType DefineSystemCounter (CounterType cntr)
{

OSEK_COUNTER  *cntr_ptr;
OSEK_COUNTER  *this_counter;
UINT          index;
UINT          attached;

    /* Check if we are in initialization.  */
    /* This will ensure that no one calls this function after system is started.  */
    if (osek_init_state != OSEK_INIT)
    {
        /* Return OSEK internal error. This is not a standard OSEK error.  */
        Application->osek_object_creation_error++;

        return ((TaskType)TX_NULL);
    }

    /* Convert counter id to counter pointer.  */

    cntr_ptr = (OSEK_COUNTER *)cntr;

    /* Check for valid counter.  */
    if ((cntr_ptr == TX_NULL) && (cntr_ptr->osek_counter_id != OSEK_COUNTER_ID))
    {
        /* There is error in counter object supplied.  */
        Application->osek_object_creation_error++;

        return (E_OS_ID);
    }

    if (cntr_ptr->cntr_in_use == TX_FALSE)
    {
        Application->osek_object_creation_error++;

        return (E_OS_ID);
    }

    /* Now check if there any a counter exists attached to system timer?  */
    attached = TX_FALSE;

    /* Search for a free counter.  */
    this_counter = osek_counter_pool;
    for (index = 0u; index < OSEK_MAX_COUNTERS; index++)
    {
        /* Is this guy is attached to system timer?  */
        if (this_counter->system_timer == TX_TRUE)
        {
            /* This counter is attached to system timer.  */
            attached = TX_TRUE;
            /* Stop searching.  */
            break;
        }

        this_counter++;
    } /* check all counters.  */

    /* No body attached to system timer?  */
    if (attached == TX_FALSE)
    {
        /* No one is attached, attach counter supplied to system timer.  */
        cntr_ptr->system_timer = TX_TRUE;

        /* Now start the system timer.  */
        tx_timer_activate(&osek_system_timer);

        return (E_OK);
    }

    /* One counter is already attached to system timer.  */
    Application->osek_object_creation_error++;

    return (E_OS_NOFUNC);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    CreateAlarm                                         PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    Creates an alarm.                                                   */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    ticks                        Tick count                             */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    ALARM_ID                     Reference to alarm                     */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    osek_get_alarm               Get the alarm if possible              */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*   Application Code                                                     */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
AlarmType  CreateAlarm(const CHAR *name, CounterType cntr, UINT action, ULONG events, TaskType task,
                     void (*callback)(), UINT Startup, TickType Alarmtime, TickType Cycle )
{

AlarmType        alarm_id;
OSEK_COUNTER     *cntr_ptr;
OSEK_TCB         *tcb_ptr;
OSEK_ALARM       *this_alarm;
UINT             index;
TickType         current_value;
StatusType       status;

    /* Check if we are in Initialization.  */
    /* This will ensure that no one calls this function after system is started.  */
    if (osek_init_state != OSEK_INIT)
    {
        /* Return OSEK internal error. This is not a standard OSEK error.  */
        Application->osek_object_creation_error++;

        return ((TaskType)TX_NULL);
    }

    /* Start with validating arguments passed.  */
    cntr_ptr = (OSEK_COUNTER*)cntr;
    if ((cntr_ptr == TX_NULL) || (cntr_ptr->osek_counter_id != OSEK_COUNTER_ID)|| (cntr_ptr->cntr_in_use == TX_FALSE))
    {
        /* Counter is not valid.  */
        Application->osek_object_creation_error++;
        return (E_OS_ID);
    }

    if (cntr_ptr->cntr_in_use != TX_TRUE)
    {
        /* Counter is not in use.  */
        Application->osek_object_creation_error++;

        return (E_OS_ID);
    }

    tcb_ptr = (OSEK_TCB *)task;

    /* Check the action to be taken and parameters passed.  */
    switch(action)
    {
        case SETEVENT:

            /* For SetEvents there should not be call back function.  */
            if((events == 0u) || (task == 0u) || (callback != TX_NULL))
            {
                /* Return error.  */
                Application->osek_object_creation_error++;

                return (E_OS_NOFUNC);
            }

            if ((tcb_ptr == TX_NULL) || (tcb_ptr->osek_task_id != OSEK_TASK_ID))
            {
                /* Task is not valid.  */
                Application->osek_object_creation_error++;

                return (E_OS_ID);
            }

            if (tcb_ptr->tcb_in_use != TX_TRUE)
            {
                /* Task is not in use */
                Application->osek_object_creation_error++;
                return (E_OS_ID);
            }

            break;

        case ACTIVATETASK:
            /* For activate task there should not be any call-back function or any event.  */
            if((task == 0u) || (events != 0u) || (callback != TX_NULL))
            {
                /* Return error.  */
                Application->osek_object_creation_error++;

                return (E_OS_NOFUNC);
            }

            if ((tcb_ptr == TX_NULL) || (tcb_ptr->osek_task_id != OSEK_TASK_ID))
            {
                /* Task is not valid.  */
                Application->osek_object_creation_error++;
                return (E_OS_ID);
            }

            if (tcb_ptr->tcb_in_use != TX_TRUE)
            {
                /* Task is not in use.  */
                Application->osek_object_creation_error++;
                return (E_OS_ID);
            }

            break;

        case CALLBACK:
            /* For ALARMCALLBACK there should not be task or any event.  */
            if((callback == TX_NULL) || (events != 0u) || (task != 0u))
            {
                /* Return error.  */
                Application->osek_object_creation_error++;

                return (E_OS_NOFUNC);
            }

            break;

        default:
            /* Return error.  */
            Application->osek_object_creation_error++;

            return (E_OS_NOFUNC);

            break;
    }

    /* Check if there is space for this alarm.  */
    alarm_id = osek_get_alarm();
    if (alarm_id == 0u)
    {
        /* Return error.  */
        Application->osek_object_creation_error++;

        return (E_OS_NOFUNC);
    }

    /* Got correct inputs, get pointer to alarm.  */
    this_alarm = (OSEK_ALARM *)alarm_id;

    /* Store object id.  */
    this_alarm->osek_alarm_id = OSEK_ALARM_ID;

    /* Before attaching this alarm to a counter, disarm it.  */
    this_alarm->armed = TX_FALSE;

    this_alarm->name = name;

    /* Now, try attaching this alarm to the counter specified.  */
    for (index = 0u; index < OSEK_MAX_ALARMS; index++)
    {
        /* Find a free entry in the list maintained by the counter.  */
        if (cntr_ptr->alarm_list[index] == 0u)
        {
            /* Found one.  */
            cntr_ptr->alarm_list[index] = alarm_id;

            break;
        }
    }

    /* Searched the entire list and came empty handed?  */
    if (index >= OSEK_MAX_ALARMS)
    {
        /* Return error.  */
        osek_reset_alarm(this_alarm);

        Application->osek_object_creation_error++;

        return (E_OS_NOFUNC);
    }

    /* Got the counter, now save the counter in to ALARM structure.  */
    this_alarm->cntr = cntr_ptr;

    /*  Maximum allowed value and minimum cycles for this alarms this values are from */
    /*  the counter to which this alarm is attached.  */
    this_alarm->max_allowed_value = cntr_ptr->maxallowedvalue;
    this_alarm->min_cyc = cntr_ptr->mincycle;
    this_alarm->ticks_per_base = cntr_ptr->ticksperbase;

    this_alarm->name = name;

    /* Store the ACTION upon alarm expiration.  */
    this_alarm->action = action;

    /* Store event in case of SETEVENT action.  */
    this_alarm->events = events;

    /* Check for call back and store it.  */
    if(callback != TX_NULL)
    {
        this_alarm->alarm_callback = callback;
    }

    if (Startup != 0u)
    {
        this_alarm->auto_start = TX_TRUE;
    }

    /* Save the TASK in to ALARM structure.  */
    this_alarm->task = tcb_ptr;

    /* Everything is OK so far, now fill this alarm control block with some default parameters.  */

    /* Reset max cycles, current cycles and expiration count.  */
    this_alarm->expiration_count = 0u;
    this_alarm->cycle = 0u;

    /* Now it is time to check for AUTOSTART.  */
    if (this_alarm->auto_start != 0u)
    {
        /* Check start.  */
        if ((Alarmtime == 0u) || (Alarmtime > this_alarm->max_allowed_value))
        {
            /* Invalid input parameter.  */
            Application->osek_object_creation_error++;

            return (E_OS_VALUE);
        }

        /* Check cycle. */
        if (Cycle != 0u)
        {
            if ((Cycle < this_alarm->min_cyc) || (Cycle > this_alarm->max_allowed_value))
            {
                /* Invalid input parameter.  */
                Application->osek_object_creation_error++;

                return (E_OS_VALUE);
            }
        }

        /* All input parameters are ok, store relative value and cycle.  */
        this_alarm->cycle = Cycle;

        status = GetCounterValue(cntr_ptr, &current_value);
        if (status != E_OK)
        {
            Application->osek_object_creation_error++;

            return (E_OS_VALUE);  /* Some problem in getting counter's current value.  */
        }

        this_alarm->expiration_count = current_value + Alarmtime; /* Load the counter with its expiration count.  */

        /* Now set the relative mode.  */
        this_alarm->rel_abs_mode = RELATIVE_ALARM;
        this_alarm->counter_rollback = TX_FALSE;
        this_alarm->armed = TX_TRUE;
        this_alarm->occupied = TX_TRUE;

    }  /* End..   this_alarm->auto_start.  */

    return(alarm_id);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    GetAlarmBase                                        PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    Reads the alarm base characteristics. Returns info which is a       */
/*    in which the information of the data type AlarmbaseType is          */
/*    stored.                                                             */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    AlarmID                       Reference to alarm                    */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    Info                          user_defined parameters of the        */
/*                                  counter associated with alarm.        */
/*  CALLS                                                                 */
/*                                                                        */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*   Application Code                                                     */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
StatusType  GetAlarmBase(AlarmType AlarmID, AlarmBaseRefType info)
{

OSEK_ALARM          *alarm_ptr;


    service_GetServiceId.id = (OsServiceIdType)OSServiceId_GetAlarmBase;
    service_GetAlarmBase.AlarmID = AlarmID;

    /* Get the OSEK alarm.  */
    alarm_ptr = (OSEK_ALARM *) AlarmID;

    /* Check valid ID.  */
    if((alarm_ptr == 0u) || (alarm_ptr->osek_alarm_id != OSEK_ALARM_ID))
    {
        exec_ErrorHook (E_OS_ID);

        /* Invalid AlarmID.  */
        return (E_OS_ID);
    }

    info->maxallowedvalue = alarm_ptr->max_allowed_value;
    info->mincycle = alarm_ptr->min_cyc;
    info->ticksperbase = alarm_ptr->ticks_per_base;

    return (E_OK);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    SetAbsAlarm                                         PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    Sets an alarm to an absolute cycle value.                           */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    AlarmID                      Reference to alarm.                    */
/*    start                        Absolute value in ticks.               */
/*    cycle                        Cycle value in case of cyclic alarm.   */
/*                                 In case of single alarm it must be     */
/*                                 zero.                                  */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    E_OK                         If successful                          */
/*    ERROR                        If error occurs while creating task    */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    osek_internal_error          OSEK internal error                    */
/*    tx_time_get                  Get system time                        */
/*    tx_timer_create              Create the timer is created            */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*   Application Code                                                     */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
StatusType SetAbsAlarm(AlarmType  AlarmID, TickType start, TickType cycle)
{
    TX_INTERRUPT_SAVE_AREA
    OSEK_ALARM          *osek_alarm;


    service_GetServiceId.id = (OsServiceIdType)OSServiceId_SetAbsAlarm;
    service_SetAbsAlarm.AlarmID = AlarmID;
    service_SetAbsAlarm.start = start;
    service_SetAbsAlarm.cycle = cycle;

    /* Convert AlarmID to OSEK_ALARM.  */
    osek_alarm = (OSEK_ALARM *) AlarmID;

    /* Check valid ID.  */
    if((osek_alarm == 0u) || (osek_alarm->osek_alarm_id != OSEK_ALARM_ID))
    {
        exec_ErrorHook (E_OS_ID);

        /* Invalid AlarmID.  */
        return (E_OS_ID);
    }

    TX_DISABLE

    /* Check already armed?  */
    if (osek_alarm->armed == TX_TRUE)
    {
        TX_RESTORE

        exec_ErrorHook(E_OS_STATE);

        return (E_OS_STATE);
    }

    /* Check start.  */
    if ((start == 0u) || ( start > osek_alarm->max_allowed_value))
    {
        TX_RESTORE

        /* Invalid input parameter.  */
        exec_ErrorHook(E_OS_VALUE);

        return (E_OS_VALUE);
    }


    /* Check cycle.  */
    if (cycle != 0u)
    {
        if ((cycle < osek_alarm->min_cyc) || ( cycle > osek_alarm->max_allowed_value))
        {
            TX_RESTORE

            exec_ErrorHook(E_OS_VALUE);

            /* Invalid input parameter.  */
            return (E_OS_VALUE);
        }
    }

    /* All input parameters are ok, store abs value and cycle.  */
    osek_alarm->cycle = cycle;
    osek_alarm->expiration_count = start; /* Load the counter with its expiration count.  */

    /* Now set the absolute mode.  */
    osek_alarm->rel_abs_mode = ABSOLUTE_ALARM;

    /* Now, arm the alarm.  */
    osek_alarm->armed = TX_TRUE;
    osek_alarm->occupied = TX_TRUE;
    osek_alarm->counter_rollback = TX_FALSE;

    TX_RESTORE

   /* Return OK.  */
    return (E_OK);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    SetRelAlarm                                         PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    Sets an alarm to a relative cycle value from the current time.      */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    AlarmID                      Reference to alarm.                    */
/*    increment                    Relative value in ticks                */
/*    cycle                        Cycle value in case of cyclic alarm    */
/*                                 In case of single alarm it must be     */
/*                                 zero.                                  */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    E_OK                         If successful                          */
/*    ERROR                        If an error occurs                     */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    osek_internal_error          OSEK internal error                    */
/*    tx_timer_change              Change the timer                       */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*   Application Code                                                     */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
StatusType  SetRelAlarm(AlarmType AlarmID, TickType increment, TickType cycle)
{
TX_INTERRUPT_SAVE_AREA
OSEK_ALARM          *osek_alarm;
OSEK_COUNTER        *counter_ptr;
TickType            current_value;
StatusType          status;


    service_GetServiceId.id = (OsServiceIdType)OSServiceId_SetRelAlarm;
    service_SetRelAlarm.AlarmID = AlarmID;
    service_SetRelAlarm.increment = increment;
    service_SetRelAlarm.cycle = cycle;

    /* Convert AlarmID to OSEK_ALARM.  */
    osek_alarm = (OSEK_ALARM *)AlarmID;

    /* Check valid ID.  */
    if((osek_alarm == TX_NULL) || (osek_alarm->osek_alarm_id != OSEK_ALARM_ID))
    {
        exec_ErrorHook(E_OS_ID);

        /* Invalid AlarmID.  */
        return (E_OS_ID);
    }

    TX_DISABLE

    /* Check already armed?  */
    if (osek_alarm->armed == TX_TRUE)
    {
        TX_RESTORE

        exec_ErrorHook(E_OS_STATE);

        return (E_OS_STATE);
    }

    /* Check start.  */
    if ((increment == 0u) || (increment > osek_alarm->max_allowed_value))
    {
        TX_RESTORE

        exec_ErrorHook(E_OS_VALUE);

        /* Invalid input parameter.  */
        return (E_OS_VALUE);
    }

    /* Check cycle.  */
    if (cycle != 0u)
    {
       if ((cycle < osek_alarm->min_cyc) || (cycle > osek_alarm->max_allowed_value))
        {
           TX_RESTORE

            exec_ErrorHook(E_OS_VALUE);

            /* Invalid input parameter.  */
            return (E_OS_VALUE);
        }
    }

    /* All input parameters are ok, store rel value and cycle.  */
    osek_alarm->cycle = cycle;
    counter_ptr = osek_alarm->cntr;

    status = GetCounterValue(counter_ptr, &current_value);
    if (status != E_OK)
    {
        TX_RESTORE
        return (E_OS_STATE);
    }

    osek_alarm->expiration_count = current_value + increment; /* Load the counter with its expiration count.  */

    /* Now set the relative mode.  */
    osek_alarm->rel_abs_mode = RELATIVE_ALARM;
    osek_alarm->counter_rollback = TX_FALSE;

    /* Now, arm the alarm.  */
    osek_alarm->armed = TX_TRUE;
    osek_alarm->occupied = TX_TRUE;

    TX_RESTORE

    /* Return OK.  */
    return (E_OK);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    CancelAlarm                                         PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    Cancels the alarm: the alarm transition into the stop state.        */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    AlarmID                      Reference to alarm                     */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    E_OK                         If successful                          */
/*    ERROR                        If an error occurs                     */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    tx_timer_deactivate         Timer deactivate                        */
/*    osek_internal_error         OSEK internal error                     */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*   Application Code                                                     */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
StatusType  CancelAlarm(AlarmType  AlarmID)
{
TX_INTERRUPT_SAVE_AREA
    OSEK_ALARM          *osek_alarm;

    service_GetServiceId.id = (OsServiceIdType)OSServiceId_CancelAlarm;
    service_CancelAlarm.AlarmID = AlarmID;

    /* Check valid ID and absolute ticks.  */
    osek_alarm = (OSEK_ALARM *) AlarmID;
    if((osek_alarm == TX_NULL) || (osek_alarm->osek_alarm_id != OSEK_ALARM_ID))
    {
        exec_ErrorHook(E_OS_ID);

        /* Invalid AlarmID.  */
        return (E_OS_ID);
    }

    TX_DISABLE

    /* Is this alarm in use?  */
    if ((osek_alarm->armed == TX_FALSE) || (osek_alarm->occupied == TX_FALSE))
    {
        TX_RESTORE

        exec_ErrorHook(E_OS_NOFUNC);

        return (E_OS_NOFUNC);
    }

    /* Alarm is in use so make it inactive.  */
    osek_alarm->armed = TX_FALSE;

    TX_RESTORE

    /* Return OK.  */
    return (E_OK);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    GetAlarm                                            PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    Returns the no. of ticks before the alarm expires.                  */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    ticks                        Pointer to the returned tick count     */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    N/A                                                                 */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    tx_timer_info_get            Retrieves information about specified  */
/*                                 timer.                                 */
/*    osek_internal_error          OSEK internal error                    */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*   Application Code                                                     */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
StatusType  GetAlarm(AlarmType AlarmID, TickRefType tick_ptr)
{
TX_INTERRUPT_SAVE_AREA
OSEK_ALARM          *osek_alarm;
OSEK_COUNTER        *counter_ptr;
TickType             current_ticks;
StatusType           status;


    service_GetServiceId.id = (OsServiceIdType)OSServiceId_GetAlarm;
    service_GetAlarm.AlarmID = AlarmID;

    /* Check valid ID and absolute ticks.  */
    osek_alarm = (OSEK_ALARM *) AlarmID;
    if((osek_alarm == TX_NULL) || (osek_alarm->osek_alarm_id != OSEK_ALARM_ID))
    {
        exec_ErrorHook (E_OS_ID);

        /* Invalid AlarmID.  */
        return (E_OS_ID);
    }

    TX_DISABLE

    if ((osek_alarm->armed == FALSE) || (osek_alarm->occupied == TX_FALSE))
    {
        TX_RESTORE

        exec_ErrorHook(E_OS_NOFUNC);

        return (E_OS_NOFUNC);      /* Alarm expired or not in use.  */
    }

    counter_ptr = osek_alarm->cntr;

    status = GetCounterValue(counter_ptr, &current_ticks);
    if (status != E_OK)
    {
        TX_RESTORE

        exec_ErrorHook (E_OS_ID);
        return (E_OS_ID);
    }

    if (osek_alarm->expiration_count < current_ticks)
    {
        /* Alarm's expiration count is less than current counter value means */
        /* alarm will expire after the counter rolls back and reach alarm's expiration count.  */
        *tick_ptr = (osek_alarm->max_allowed_value - current_ticks + osek_alarm->expiration_count);
    }
    else
    {
        /* Alarm's expiration is more than counter's current value. */
        *tick_ptr = (osek_alarm->max_allowed_value - current_ticks);
    }

    TX_RESTORE

    return (E_OK);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*  osek_initialize                                       PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function sets up, configures and initializes all the           */
/*    "behind-the-scenes" data structures, tables, memory regions, etc.   */
/*    used by the OSEK at run-time.                                       */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    osek_memory                            OSEK pointer                 */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    tx_thread_create                      Create system manager thread  */
/*    tx_timer_create                       Create a system timer         */
/*    osek_memory_init                      Initialize OSEK memory        */
/*    tx_queue_create                       Create system manager queue   */
/*    osek_tcb_init                         Initialize OSEK tasks         */
/*    osek_resource_init                    Initialize OSEK resources     */
/*    osek_alarm_init                       Initialize OSEK alarms        */
/*    osek_counter_init                     Initialize OSEK counter       */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Start-up code                                                       */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/

UCHAR *osek_initialize(void *osek_memory, APPLICATION_INFO_PTR application1)
{

UCHAR       *pointer;
UINT         status;
UINT         i;
UINT         j;

    /* Initialization started, set init state.  */
    osek_init_state = OSEK_INIT;

    Application = application1;
    Application->osek_object_creation_error = 0u;
    /* Setup temporary memory pointer so we can start allocating
       space for the OSEK data structures.  The important thing to
       remember here is that the system threads stack, the region0
       memory, and the queue are allocated sequentially from the
       address specified by OSEK_memory.  */

    pointer =  (UCHAR *)osek_memory;

    /* Create the work item message queue.  */
    status = tx_queue_create(&osek_work_queue, "OSEK work queue", SYSMGR_QUEUE_MSG_LENGTH,
                                pointer, SYSMGR_QUEUE_DEPTH * SYSMGR_QUEUE_MSG_LENGTH);
    if(status != TX_SUCCESS)
    {
        Application->osek_object_creation_error++;
    }

    pointer = pointer + (SYSMGR_QUEUE_DEPTH * SYSMGR_QUEUE_MSG_LENGTH);

    /* Create the system manager thread.  */
    status = tx_thread_create(&osek_system_manager, "OSEK System Manager", osek_system_manager_entry,
                                 0, pointer, OSEK_SYSTEM_STACK_SIZE, SYSMGR_PRIORITY, SYSMGR_THRESHOLD,
                                 TX_NO_TIME_SLICE, TX_AUTO_START);
    if (status != TX_SUCCESS)
    {
        /* Error creating the system manager thread.  */
        Application->osek_object_creation_error++;
    }

    pointer =  pointer + OSEK_SYSTEM_STACK_SIZE;

    /* Set up a memory "heap" or TX_REGION0_SIZE_IN_BYTES used internally
       by the osek.  */

    status = osek_memory_init(pointer);

    if (status != TX_SUCCESS)
    {
        Application->osek_object_creation_error++;
    }

    pointer =  pointer + TX_REGION0_SIZE_IN_BYTES;


    /* Create the system timer.  */
    status = tx_timer_create( &osek_system_timer, "OSEK SYSTEM TIMER", osek_system_timer_entry,
                           0,5,5,TX_NO_ACTIVATE);

    if (status != TX_SUCCESS)
    {
        Application->osek_object_creation_error++;
    }

    /* Check whether any error occurred during system object creation.  */
    if (Application->osek_object_creation_error != 0u)
    {
        osek_internal_error(THREADX_OBJECT_CREATION_ERROR);
    }

    /* Initialize static pool of task control blocks.  */
    osek_tcb_init();

    /* Set up a pool of resource used internally by the OSEK layer.  */
    osek_resource_init();

    /* Set up a pool of counter used internally by the OSEK layer.  */
    osek_counter_init();

    /* Set up a pool of alarm used internally by the OSEK layer.  */
    osek_alarm_init();

    /* Clear all events.  */
    global_events = 0u;
    global_event_count = 0u;

     /* Clear task table.  */

    for (i = 0u; i < (OSEK_ISR1_PRIORITY + 1u); i++)
    {
        for (j = 0u; j < TASK_QUEUE_DEPTH; j++)
        {
            task_table[i][j] = 0u;
        }
    }

    /* Change OSEK mode.  */
    osek_wrapper_operation_mode = INITSYSTEM_MODE;

    system_start = TX_TRUE;

    /* All done.  */
    return (pointer);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*  osek_cleanup                                          PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    Cleans up after an OS shutdown. Used for testing.                   */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    application1                          Application pointer.          */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    TX_SUCCESS                            If successful.                */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Start-up code                                                       */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/

UINT osek_cleanup(APPLICATION_INFO_PTR application1)
{

UINT status;
UINT i;
OSEK_TCB *p_tcb;

    /* Delete the system manager thread.  */
    status = tx_thread_delete(&osek_system_manager);
    if (status != TX_SUCCESS)
    {
        /* System internal error.  */
        osek_internal_error(SYS_MGR_START_OS);
    }

    /* Delete the system manager work queue.  */
    status = tx_queue_delete(&osek_work_queue);
    if (status != TX_SUCCESS)
    {
        /* System internal error.  */
        osek_internal_error(SYS_MGR_START_OS);
    }

    /* Delete the system timer. */
    status = tx_timer_delete(&osek_system_timer);
    if (status != TX_SUCCESS)
    {
        /* System internal error.  */
        osek_internal_error(SYS_MGR_START_OS);
    }

    /* Delete the memory pool used for OSEK objects.  */
    status = tx_byte_pool_delete(&osek_region0_byte_pool);
    if (status != TX_SUCCESS)
    {
        /* System internal error.  */
        osek_internal_error(SYS_MGR_START_OS);
    }

    /* Terminate and delete all the threads.  */
    for(i = 0u; i < OSEK_MAX_TASKS; i++) {
        p_tcb = &osek_tcb_pool[i];
        if(p_tcb->task.tx_thread_entry != NULL) {
            status = tx_thread_terminate(&p_tcb->task);
            if (status != TX_SUCCESS)
            {
                /* System internal error.  */
                osek_internal_error(SYS_MGR_START_OS);
            }

            status = tx_thread_delete(&p_tcb->task);
            if (status != TX_SUCCESS)
            {
                /* System internal error.  */
                osek_internal_error(SYS_MGR_START_OS);
            }

            p_tcb->task.tx_thread_entry = NULL;
        }
    }

    /* Clear the memory pool to prevent errors on restart.  */
    memset(osek_tcb_pool, 0u, sizeof(osek_tcb_pool));

    /* OSEK cleaned up, change init state to not initialized.  */
    osek_init_state = OSEK_NOT_INIT;

    return TX_SUCCESS;
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    process_ISR2                                        PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    isrname                      ISR to process.                        */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    ActivateISR                  Puts ISR in the queue area             */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*   Wrapper Internal code (Not available for Application)                */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
void   process_ISR2(ISRType isrname)
{

   if (disable_ISR2 != 0u)
   {
       /* ISR2 disabled, do nothing.  */
       return;
   }

   ActivateISR(isrname);

   return;
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    ShutdownOS                                          PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function shuts down the OS. If ShutdownHook is defined it is   */
/*    called.                                                             */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    StatusType                     Returned error to the hook           */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    ErrorHook                      If defined                           */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Application or OS                                                   */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
void   ShutdownOS(StatusType error)
{
TX_INTERRUPT_SAVE_AREA
ULONG       request[SYSMGR_QUEUE_MSG_LENGTH];
UINT        status;

    TX_DISABLE

    /* Disable ISRs.  */
    disable_ISR2 = TX_TRUE;

   /* Check for any shutdown hook routine.  */
   if (Application->shutdown_hook_handler != TX_NULL)
   {
       /* Change operation mode for to shutdownhook mode. */
       osek_wrapper_operation_mode = SHUTDOWNHOOK_MODE;

       (Application->shutdown_hook_handler)(error);

   }

   /* Change to default operations mode.  */
   osek_wrapper_operation_mode = NORMAL_EXECUTION_MODE;

   /* Now send message to system thread to shut down the system.  */
   /* Build the request.  */
   request[0] = SYSMGR_SHUTDOWN_OS;         /* Request type.  */
   request[1] = 0u;                         /* Dummy.  */
   request[2] = 0u;                         /* Dummy.  */
   request[3] = 0u;                         /* Dummy.  */

   /* Now send a message to the SysMgr supervisor thread.  */

   status = tx_queue_send(&osek_work_queue, request, TX_NO_WAIT);

   TX_RESTORE

   /* This should always succeed.  */
   if (status != TX_SUCCESS)
   {
       /* System internal error.  */
       osek_internal_error(SYS_MGR_START_OS);
   }

   return;
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    ActivateISR                                         PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This call activates a task which eventually executes an ISR code    */
/*    This call puts the task in the ready queue.                         */
/*    The operating system ensures that the task code is being executed   */
/*    from the first statement. Rescheduling after this call depends on   */
/*    whether required resources for this ISR are free or not and no      */
/*    other higher priority are running.                                  */
/*    If E_OS_LIMIT is returned then activation is ignored as there is    */
/*    one request of same ISR is already pending.                         */
/*                                                                        */
/*    ** NOTE**                                                           */
/*    This is not a standard OSEK API call.                               */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    ISRId                                 ISR Name                      */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    E_OK                                  If successful                 */
/*    E_OS_ID                               Invalid ISR id                */
/*    E_OS_LIMIT                            One ISR already pending       */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    tx_queue_send                         Send message to Sys Manager   */
/*    osek_internal_error                   OSEK internal error           */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    OSEK Wrapper Internal code (not available for Applications)         */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
static StatusType ActivateISR(ISRType ISRID)
{
TX_INTERRUPT_SAVE_AREA
OSEK_TCB       *tcb_ptr;
UINT            status;
ULONG           request[SYSMGR_QUEUE_MSG_LENGTH];

   /* Get the OSEK TCB for the ISR to be activated.  */
   tcb_ptr = (OSEK_TCB *)ISRID;

   /* Check for a valid ISR id.  */
   if((tcb_ptr == TX_NULL) || (tcb_ptr->osek_task_id != OSEK_ISR_ID))
   {
       /* Return Error.  */
       return (E_OS_ID);
   }

   TX_DISABLE

   /* Check whether an ISR of same name is pending.  */
   if(tcb_ptr->current_active >= tcb_ptr->max_active)
   {
       TX_RESTORE
       /* Reached its max activation limit.  */
       return (E_OS_LIMIT);
   }

   /* Now send a message to the system manager to activate this ISR.  */
   /* Build the request.  */

   request[0] = SYSMGR_ACTIVATE_TASK;          /* Request type.                */
   request[1] = (ULONG)tcb_ptr;                /* ISR to Activate,             */
   request[2] = last_run_task;                 /* Running task if any.         */
   request[3] = 0u;

   /* Since the SysMgr supervisor thread has the highest priority, this call   */
   /* will be preempted by SysMgr supervisor thread.                           */
   /* SysMgr will eventually call osek_do_task_activate().                     */

   status = tx_queue_send(&osek_work_queue, request, TX_NO_WAIT);

   TX_RESTORE

   /* This should always succeed.  */
   if (status != TX_SUCCESS)
   {
       /* System internal error.  */
       osek_internal_error(SYS_MGR_SEND_ACTIVATETASK);
   }

   /* Return status.  */
   return (E_OK);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    TerminateISR                                        PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*   This service terminates the calling ISR.                             */
/*   Only internal resources held by this ISR are released here. While    */
/*   it is assumed that any external resources occupied by the ISR must   */
/*   have been released before the call to TerminateISR. In case          */
/*   a resource is still occupied while calling this service, then the    */
/*   behaviour is undefined in STANDARD version of OSEK. In the EXTENDED  */
/*   version of OSEK, this service returns an error, which can be         */
/*   evaluated by the application.                                        */
/*   If successful, this call will causes rescheduling, this also means   */
/*   that upon success TerminateTask does not return to the call level.   */
/*                                                                        */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                            If success                          */
/*    Error Code.                     If error                            */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    osek_task_independent_area      Check if we are in task context     */
/*    osek_thread2tcb                 Get TCB pointer for thread pointer  */
/*    tx_queue_send                   Send message to sys manager thread  */
/*    osek_internal_error             In case of any internal error       */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    OSEK Wrapper Internal code (Not available for Applications)         */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
static StatusType  TerminateISR(void)
{
TX_INTERRUPT_SAVE_AREA
OSEK_TCB       *tcb_ptr;
ULONG           request[SYSMGR_QUEUE_MSG_LENGTH];
UINT            index;
UINT            status;
ULONG           area;
TX_THREAD      *p_thread;


   /* Check for task or ISR context */
   /* All ISR are treated as as a high priority tasks.  */
   area = osek_task_independent_area();
   if(area != TX_TRUE)
   {
       /* Return error.  */
       return (E_OS_CALLEVEL);
   }

   /* Get OSEK TCB of this TASK/ISR  */
   p_thread = tx_thread_identify();
   tcb_ptr = osek_thread2tcb(p_thread);
   if (tcb_ptr == NULL)
   {
       return (E_OS_CALLEVEL);
   }

   if ((tcb_ptr->osek_task_id != OSEK_ISR_ID))
   {
       /* This call is allowed only from ISR.  */
       return (E_OS_CALLEVEL);
   }


   /* Check operating mode.  */
   if ((osek_wrapper_operation_mode != ISR1_MODE) && (osek_wrapper_operation_mode != ISR2_MODE))
   {
       /* Hook toutines and alarm callbacks can't call this service.  */
       /* This explicit check is required because all hook routines are
      executed in task's context.  */
       return (E_OS_CALLEVEL);
   }

   TX_DISABLE

   /* Check if any resource is occupied. A task can not be terminated if it is holding any resource.  */
   if(tcb_ptr->res_ocp != 0u)
   {
       TX_RESTORE

      /* Return.  */
      return (E_OS_RESOURCE);
   }

   /* Release any internal resources held.  */
   if (tcb_ptr->internal_res != 0u)
   {
       for (index = 0u; index < OSEK_MAX_INTERNAL_RES; index++)
       {
           if (tcb_ptr->internal_resource_occuplied_list[index] == 0u)
           {
               break;
           }

           ((OSEK_RESOURCE *)(tcb_ptr->internal_resource_occuplied_list[index]))->taskid = 0u;
           tcb_ptr->internal_resource_occuplied_list[index] = 0u;

       }   /* End of for loop.  */
   }

   /* Now all set to terminate this task.  */
   /* Send a message to the System Manager to terminate this task.  */
   /* Build the request.  */

   request[0] = SYSMGR_TERMINATE_TASK;      /* Request type.  */
   request[1] = (ULONG)tcb_ptr;             /* ID of the task to kill.  */
   request[2] = 0u;
   request[3] = 0u;

   /* Since the SysMgr supervisor thread has the highest priority,        */
   /* this call will be preempted by SysMgr supervisor thread             */
   /* SysMgr will eventually call osek_do_task_terminate and reschedule.  */

   status = tx_queue_send(&osek_work_queue, request, TX_NO_WAIT);

   TX_RESTORE

   /* This should always succeed. and Sys Manager terminates this task    */
   /* This point will never be reached, as this thread itself will be     */
   /* deleted by the system manager!                                      */
   /* Still as a safety precaution enter system internal error loop.      */

   if (status != TX_SUCCESS)
   {
       osek_internal_error(SYS_MGR_SEND_TERMINATETASK);
   }

   return (E_OK);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    osek_system_manager_entry                          PORTABLE C       */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This is the System Manager thread for the OSEK.                     */
/*    All OSEK service calls that may cause rescheduling, ends up in      */
/*    sending a message to a queue, and this highest priority thread      */
/*    'System Manager' reads this message and acts upon it.               */
/*    It then calls the actual task scheduler which selects the next ready*/
/*    task from a queue of READY tasks.                                   */
/*    After completing the request this routine returns back to read      */
/*    next message which suspends this System Manager Thread and the task */
/*    selected by the task scheduler starts running.                      */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    input                          Not used  (Don't care)               */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    tx_queue_receive               Get message from ThreadX queue       */
/*    osek_do_task_terminate         Terminate the OSEK task.             */
/*    osek_do_task_activate          Activate the task                    */
/*    osek_internal_error            OSEK internal error.                 */
/*    osek_do_delete_task            Delete the OSEK task                 */
/*    pop_task_from_table            Removes a task from the queue        */
/*    tx_thread_suspend              Suspends the calling task            */
/*    add_task_to_table              Adds a task to the TASK ready queue  */
/*    start_osek_tasks               Runs the next ready task from queue  */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Wrapper Internal code (Not available to Application )               */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
static void  osek_system_manager_entry(ULONG input)
{
TX_THREAD      *this_thread;
OSEK_TCB       *tcb_ptr;
UINT            status;
StatusType      osek_status;
UINT            i;
UINT            j;
ULONG           request[SYSMGR_QUEUE_MSG_LENGTH];


   /* The input argument 'input' is not needed , hence not used */
   /* This statement is added just to avoid compiler warning.  */
   (void)&input;

   /* Loop forever, waiting for any new message in the work queue.  */
   for(;;)
   {
       /* Wait forever for the next work request.  */
       status = tx_queue_receive(&osek_work_queue, &request, TX_WAIT_FOREVER);

       /* Make sure we didn't encounter any trouble.  */
       if (status != TX_SUCCESS)
       {
           osek_internal_error(SYSMGR_FATAL_ERROR);
           continue;
       }

       /* Look at the first entry in the message for the request type.  */
       switch(request[0u])
       {
           case    SYSMGR_TERMINATE_TASK:

              /* ISR ends up in terminating itself so there is no separate switch case
                 for 'Return from ISR'.  */
              /* As the task is terminated, remove it from the queue.  */
              pop_task_from_table((OSEK_TCB *)request[1u]);
              /* Now Terminate the task.  */
              osek_status = osek_do_task_terminate((OSEK_TCB *)request[1u]);
              if(osek_status != E_OK) {
                  osek_internal_error(SYSMGR_FATAL_ERROR);
              }

              task_terminated = TX_TRUE;

              /* Enforce default operations mode.  */
              osek_wrapper_operation_mode = NORMAL_EXECUTION_MODE;

              break;


           case    SYSMGR_CHAIN_TASK:

               /* As calling task is terminated remove it from the queue.  */
               pop_task_from_table ((OSEK_TCB *)request[1u]);

               /* Now terminate the calling task.  */
               osek_status = osek_do_task_terminate((OSEK_TCB *)request[1u]);
               if(osek_status != E_OK) {
                   osek_internal_error(SYSMGR_FATAL_ERROR);
               }

               task_terminated = TX_TRUE;

               /* Now activate the task to be chained.  */
               osek_status = osek_do_activate_task((OSEK_TCB *)request[2u]);
               if(osek_status != E_OK) {
                   osek_internal_error(SYSMGR_FATAL_ERROR);
               }

               break;

           case    SYSMGR_START_OS:

               system_start = TX_TRUE;                    /* Indicates a fresh OS start.  */
               disable_ISR2 = TX_FALSE;
               suspend_ISR2 = TX_FALSE;

               /* OSEK started change init mode.  */
               osek_init_state = OSEK_STARTED;

               break;

           case    SYSMGR_ACTIVATE_TASK:

               /* First suspend the calling task but if an ISR is activating a task then */
               /* no need to suspend ISR Task as rescheduling (if required) is done only */
               /* after ISR completes. With ISR calling this service the request[2] is   */
               /* always a NULL.  */
               if (request[2] != 0u)
               {
                   this_thread = (TX_THREAD *)request[2];
                   status = tx_thread_suspend(this_thread);
                   if (status != TX_SUCCESS)
                   {
                       osek_internal_error(SYSMGR_FATAL_ERROR);
                   }
               }

               /* Now activate the requested task.  */
               osek_status = osek_do_activate_task((OSEK_TCB *)request[1]);
               if(osek_status != E_OK) {
                   osek_internal_error(SYSMGR_FATAL_ERROR);
               }

               break;

           case    SYSMGR_RELEASE_RESOURCE:

               tcb_ptr = (OSEK_TCB *)request[1];

               /* First remove the task from its current queue position.  */
               pop_task_from_table( tcb_ptr);

               /* Now change this task prio to a new one after release res.  */
               tcb_ptr->cur_threshold = (UINT)request[2];

               /* Now move this task to its new position.  */
               push_task_to_table(tcb_ptr);

               /* Now suspend the calling task.  */
               if (request[1u] != 0u)
               {
                   this_thread = (TX_THREAD *)request[1];
                   status = tx_thread_suspend(this_thread);
                   if (status != TX_SUCCESS)
                   {
                       osek_internal_error(SYSMGR_FATAL_ERROR);
                   }
               }
               break;

           case    SYSMGR_GET_RESOURCE:

               tcb_ptr = (OSEK_TCB *)request[1];

               /* First remove the task from its current queue position.  */
               pop_task_from_table ( tcb_ptr);

               /* Now change this task prio to a new one after release res.  */
               tcb_ptr->cur_threshold = (UINT)request[2];

               /* Now move this task to its new position.  */
               push_task_to_table(tcb_ptr);

               /* Now suspend the calling task.  */
               if (request[1u] != 0u)
               {
                    this_thread = (TX_THREAD *)request[1u];
                    status = tx_thread_suspend(this_thread);
                    if (status != TX_SUCCESS)
                    {
                        osek_internal_error(SYSMGR_FATAL_ERROR);
                    }
               }

               break;

           case    SYSMGR_SCHEDULE:

               /* Get TCB for the calling task.  */
               tcb_ptr = (OSEK_TCB *)request[1u];

               /* Now release any internal resources held
                  and move the task to its original priority queue.  */
               osek_status = release_internal_resource(tcb_ptr);
               if(osek_status != E_OK) {
                   osek_internal_error(SYSMGR_FATAL_ERROR);
               }

               /* Suspend the calling task.  */
               if (request[1u] != 0u)
               {
                   this_thread = (TX_THREAD *)request[1u];
                   status = tx_thread_suspend(this_thread);
                   if (status != TX_SUCCESS)
                   {
                       osek_internal_error(SYSMGR_FATAL_ERROR);
                   }
               }

               break;

           case    SYSMGR_SETEVENT:

               /* Add this out of wait state task to the ready queue as a newest member.  */
               ((OSEK_TCB *)request[2u])->cur_threshold = ((OSEK_TCB *)request[2u])->org_prio;

               add_task_to_table((OSEK_TCB *)request[2u]);

               /* Suspend the calling task.  */
               if (request[1u] != 0u)
               {
                   this_thread = (TX_THREAD *)request[1u];
                   status = tx_thread_suspend(this_thread);
                   if (status != TX_SUCCESS)
                   {
                       osek_internal_error(SYSMGR_FATAL_ERROR);
                   }
               }

               break;

           case    SYSMGR_WAITEVENT:

               /* Remove from the queue the task that went into waiting state.  */
               pop_task_from_table((OSEK_TCB *)request[2u]);

               /* Suspend it.  */
               this_thread = (TX_THREAD *)request[1u];

               status = tx_thread_suspend(this_thread);
               if (status != TX_SUCCESS)
               {
                   osek_internal_error(SYSMGR_FATAL_ERROR);
               }

               break;

           case    SYSMGR_SHUTDOWN_OS:
               /* System shut down, clear task queue.  */

               for (i = 0u; i < (OSEK_ISR1_PRIORITY + 1u); i++)
               {
                   for (j = 0u; j < TASK_QUEUE_DEPTH; j++)
                   {
                       if (task_table[i][j] != 0u)
                       {
                           status = tx_thread_terminate((TX_THREAD *)(task_table[i][j]));
                           if(status != TX_SUCCESS) {
                               osek_internal_error(SYSMGR_FATAL_ERROR);
                           }
                           task_table [i][j] = 0u;
                       }
                   }
               }

               return;

               break;

           case    SYSMGR_ERRORHOOK:
               this_thread = (TX_THREAD *)request[1u];

                   /* Although an ERRORHOOK won't call any API Service that may cause
                      rescheduling there could be an ISR logged while an Errorhook
                      was executing, so Errorhook call ends up in sending a message to
                      SYS manager to reschedule if necessary.  */

                   /* Suspend the task causing Error condition.  */
               status = tx_thread_suspend(this_thread);
               if (status != TX_SUCCESS)
               {
                   osek_internal_error(SYSMGR_FATAL_ERROR);
               }

                   break;

           default:

                   /* We should NEVER get here... call a fatal error.  */
                   /* System internal error.  */
                   osek_internal_error(SYSMGR_FATAL_ERROR);

                   break;

       } /* End of switch.  */

       /* Now call scheduler to check for any preemption and resume.  */
       start_osek_tasks();

   }  /* wile (1) System Manager forever loop.  */

}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*  osek_memory_init                                      PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function attempts to create a ThreadX byte pool that will      */
/*    act as a "heap" for the OSEK dynamic internal objects               */
/*    memory needs.                                                       */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    region0_ptr                            OSEK memory pointer          */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    tx_byte_pool_create                   Create region0 byte pool      */
/*    osek_internal_error                   Internal OSEK error           */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Start-up code                                                       */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
static UINT osek_memory_init (void  *region0_ptr)
{
UINT    retval;

    /* Create a ThreadX byte pool that will provide memory
       needed by the OSEK.  */
    retval = tx_byte_pool_create((TX_BYTE_POOL *)&osek_region0_byte_pool,
                                 "OSEK REGION 0",
                                 region0_ptr,
                                 TX_REGION0_SIZE_IN_BYTES);

    return (retval);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    osek_counter_init                                   PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function sets up, configures and initializes all the           */
/*    counter structures, which are defined at compile-time in order to   */
/*    ensure that there is sufficient memory.                             */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    osek_reset_counter                    Reset a Counters structure    */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Start-up code                                                       */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
static void  osek_counter_init(void)
{

ULONG       index;

    /* Loop through array of semaphores and initialize each one.  */
    for (index = 0u; index < OSEK_MAX_COUNTERS; index++)
    {
        osek_reset_counter(&(osek_counter_pool[index]));
    }
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    osek_reset_counter                                  PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function resets a counter structure.                           */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    counter_ptr                             Counter pointer             */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Start-up code                                                       */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
static void osek_reset_counter(OSEK_COUNTER *counter_ptr)
{
TX_INTERRUPT_SAVE_AREA
UINT  index;

    TX_DISABLE

    /* This counter is now no longer in use.  */
    counter_ptr->cntr_in_use = TX_FALSE;

    /* Make any counter initial ticks to 0.  */
    counter_ptr->counter_value = 0u;

    /* Make max. allowable ticks to 0.  */
    counter_ptr->maxallowedvalue = 0u;

    /* Make no. of alarm repetition to 0.  */
    counter_ptr->mincycle = 0u;

    /* Make ticks per base = 1.  */
    counter_ptr->ticksperbase = 1u;

    /* Not attached yet to system timer.  */
    counter_ptr->system_timer = TX_FALSE;

    /* Clear alarm list.  */
    for (index = 0u; index < OSEK_MAX_ALARMS; index++)
    {
        counter_ptr->alarm_list[index] = 0u;
    }

    counter_ptr->osek_counter_id = 0u;

    TX_RESTORE

    return;
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    osek_alarm_init                                   PORTABLE C        */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function sets up, configures and initializes all the           */
/*    alarm structures, which we define at compile-time in order to       */
/*    ensure that there is sufficient memory.                             */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    osek_reset_alarm                                                    */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Start-up code                                                       */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
static void  osek_alarm_init(void)
{

ULONG       index;

    /* Loop through array of Semaphores and initialize each one.  */
    for(index = 0u; index < OSEK_MAX_ALARMS; index++)
    {
        osek_reset_alarm(&(osek_alarm_pool[index]));
    }
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    osek_reset_alarm                                    PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function resets an alarm structure to its default state.       */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    alarm_ptr                             Alarm pointer                 */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Start-up code                                                       */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
static void osek_reset_alarm(OSEK_ALARM *alarm_ptr)
{
TX_INTERRUPT_SAVE_AREA

    TX_DISABLE

    /* First unarm the timer.  */
    alarm_ptr->armed = TX_FALSE;

    /* This alarm is now no longer in use.  */
    alarm_ptr->alarm_in_use = TX_FALSE;
    alarm_ptr->occupied = TX_FALSE;

    /* Make Call back function to TX_NULL.  */
    alarm_ptr->alarm_callback = TX_NULL;

    /* Make any counter reference to TX_NULL.  */
    alarm_ptr->cntr = TX_NULL;

    /* Make any task and event reference to TX_NULL.  */
    alarm_ptr->task = TX_NULL;
    alarm_ptr->events = 0u;
    alarm_ptr->action = 0u;

    /* Make its default value = 0.  */
    alarm_ptr->max_allowed_value = 0u;
    alarm_ptr->min_cyc = 0u;
    alarm_ptr->cycle = 0u;
    alarm_ptr->expiration_count = 0u;
    alarm_ptr->auto_start = 0u;

    alarm_ptr->osek_alarm_id = 0u;

    TX_RESTORE

    return;
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    osek_tcb_init                                       PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function sets up, configures and initializes all the           */
/*    task control blocks, which are defined at compile-time in order to  */
/*    ensure that there is sufficient memory.                             */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    osek_reset_tcb                         Reset a task control block   */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Start-up code                                                       */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
static void  osek_tcb_init(void)
{

ULONG       index;

    /* Loop through array of TCBs and initialize each one.  */
    for(index = 0u; index < OSEK_MAX_TASKS; index++)
    {
        osek_reset_tcb(&(osek_tcb_pool[index]));
    }
}

/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    osek_resource_init                                  PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function sets up, configures and initializes all the           */
/*    resource structures, which are defined at compile-time in order to  */
/*    ensure that there is sufficient memory.                             */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    osek_reset_res                        Reset a semaphore structure   */
/*    CreateResource                        Create the resource in OSEK   */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Start-up code                                                       */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
static void  osek_resource_init(void)
{

ULONG             index;
OSEK_RESOURCE     *res_ptr;


    /* Loop through array of resources and initialize each one.  */
    for(index = 0u; index < OSEK_MAX_RES; index++)
    {
        osek_reset_res(&(osek_res_pool[index]));
    }

    RES_SCHEDULER = CreateResource("RES_SCHEDULER", STANDARD, 0u);
    res_ptr = (OSEK_RESOURCE *)RES_SCHEDULER;
    res_ptr->c_priority = OSEK_NON_SCHEDULE_PRIORITY;
}

/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    osek_reset_res                                      PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function resets a resource a structure to its default state.   */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    res_ptr                               Resource pointer              */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Start-up code                                                       */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
static void osek_reset_res(OSEK_RESOURCE  *res_ptr)
{
TX_INTERRUPT_SAVE_AREA

    TX_DISABLE

    /* Indicate this entry is not in use.  */
    res_ptr->res_in_use = TX_FALSE;

    TX_RESTORE

    return;
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    osek_do_task_terminate                              PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function terminates the specified task.                        */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    tcb_ptr                         Task to activate                    */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                            If successful                       */
/*    Error Code.                     If an error occurs                  */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    osek_internal_error             Internal error                      */
/*    tx_thread_terminate             Terminate the thread                */
/*    tx_thread_create                Create the thread                   */
/*    osek_reset_tcb                  Free the task control block         */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    OSEK only (internal)                                                */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
static StatusType osek_do_task_terminate(OSEK_TCB  *tcb_ptr)
{
TX_INTERRUPT_SAVE_AREA
UINT                  retval;
TX_THREAD            *thread_ptr;
UINT                  priority;


    /* Converts OSEK into ThreadX.  */
    priority = osek_remap_priority(tcb_ptr->org_prio);

    /* Make the current threshold as original priority.  */
    tcb_ptr->cur_threshold = tcb_ptr->org_prio;

    /* Get the ThreadX thread pointer.  */
    thread_ptr = (TX_THREAD *)tcb_ptr;

    /* Terminate the task's thread.  */
    retval = tx_thread_terminate(thread_ptr);

    /* See if every thing is fine.  */
    if (retval != TX_SUCCESS)
    {
        /* System internal error.  */
        osek_internal_error(THREADX_THREAD_TERMINATE_TERMINATETASK);

        /* Error will be returned whenever the ThreadX call fails.  */
        return (E_OS_SYSTEM);
    }

    TX_DISABLE

    /* Delete the ThreadX thread.  */
    retval = tx_thread_delete(thread_ptr);

    /* Check if everything is fine.  */
    if (retval != TX_SUCCESS)
    {
        /* System internal error.  */
        osek_internal_error(THREADX_THREAD_DELETE_TERMINATETASK);

        /* Error will be returned whenever the ThreadX call fails.  */
        return (E_OS_SYSTEM);
    }


    if (tcb_ptr->current_active != 0u)
    {
        /* Decrement the activation count.  */
        tcb_ptr->current_active--;
    }

    /* Now check if there is any activations pending?  */
    if (tcb_ptr->current_active == 0u)
    {
        /* If no activations pending then make this task SUSPENDED.  */
        tcb_ptr->suspended = TX_TRUE;
    }

    TX_RESTORE

    tcb_ptr->waiting = TX_FALSE;

    /* Create ThreadX thread.  */
    retval = tx_thread_create(thread_ptr,
                              (char *)tcb_ptr->name,
                              osek_task_wrapper,
                              (ULONG)tcb_ptr,
                              tcb_ptr->pStackBase,
                              tcb_ptr->stack_size,
                              priority,
                              priority,
                              TX_NO_TIME_SLICE,
                              TX_DONT_START);

    /* See if ThreadX encountered an error.  */
    if (retval != TX_SUCCESS)
    {
        /* Free the task TCB structure.  */
        osek_reset_tcb(tcb_ptr);

        /* Internal error */
        osek_internal_error(THREADX_OBJECT_CREATION_ERROR);

        /* Error will be returned whenever the ThreadX call fails.  */
        return (E_OS_SYSTEM);
    }

    /* Everything is OK. */
    return (E_OK);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    osek_do_activate_task                               PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function activates the specified task.                         */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    *tcb_ptr                        task to activate                    */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                            If successful                       */
/*    Error Code.                     If an error occurs.                 */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    osek_internal_error             Internal error                      */
/*    tx_thread_resume                Activate  the thread                */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    OSEK only (internal)                                                */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
static StatusType osek_do_activate_task (OSEK_TCB  *tcb_ptr)
{
TX_INTERRUPT_SAVE_AREA
    /*  Activate a task means making it READY and place into the TASK READY queue.  */

    TX_DISABLE
    /* Increment current multiple activation count.  */
    tcb_ptr->current_active++ ;

    /* Move this task from suspended state to ready state.  */
    tcb_ptr->suspended = TX_FALSE;

    /* And add to the queue as a newest member.  */
    add_task_to_table(tcb_ptr);

    TX_RESTORE;

    return (E_OK);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*  osek_thread2tcb                                      PORTABLE C       */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*  This function returns a ThreadX thread pointer to an OSEK task        */
/*  pointer.                                                              */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    thread                         Thread pointer                       */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    *tcb                           TCB pointer                          */
/*                                   On error a null pointer is returned  */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Internal Code                                                       */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
static OSEK_TCB  *osek_thread2tcb(TX_THREAD *thread_ptr)
{

OSEK_TCB   *tcb;

    /* Make sure we were called from a thread.  */
    if (thread_ptr == TX_NULL)
    {
        /* Communicate error by means of a NULL pointer.  */
        return ((OSEK_TCB *)0u);
    }

    /* We can do this because the Thread information is intentionally
       located as the first field in the structure.  */
    tcb = (OSEK_TCB *)thread_ptr;

    /* All done.  */
    return (tcb);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    osek_task_independent_area                          PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function determines if the system is currently in a thread     */
/*    context, i.e. not timer routine, not ISR, not idling,               */
/*    not in initialization phase.                                        */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    TX_TRUE                       If in task area                       */
/*    TX_FALSE                      If not in task area                   */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    osek internal code                                                  */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
static ULONG  osek_task_independent_area(void)
{

    if (osek_init_state != OSEK_STARTED)
    {

        /* We are calling from initialization, return FALSE.  */
        return (TX_FALSE);
    }
    else if ((_tx_thread_current_ptr == TX_NULL) ||         /* Not in a thread.  */
             (_tx_thread_system_state != 0u) ||             /* In an ISR.  */
             (_tx_thread_current_ptr == &_tx_timer_thread)) /* Timer routine.  */

    {
        /* We are NOT in thread (task) context.  */
        return (TX_FALSE);
    }
    else
    {
        /* We ARE in thread (task) context.  */
        return (TX_TRUE);
    }
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    osek_create_task                                    PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function creates an OSEK task under ThreadX.                   */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    tcb_ptr                               Task control block pointer    */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    E_OK                                  If successful                 */
/*    E_OS_SYSTEM                           If failure                    */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    osek_tcb2thread                       Convert TCB to thread         */
/*    tx_thread_create                      Create thread                 */
/*    osek_reset_tcb                        OSEK free task control block  */
/*    add_task_to_table                     Add this task to queue        */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    OSEK only (internal)                                                */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
static StatusType osek_create_task(OSEK_TCB * tcb_ptr)
{

TX_INTERRUPT_SAVE_AREA

UINT                  retval;
UINT                  priority;

TX_DISABLE

   /* Converts OSEK priority into ThreadX. In ThreadX '0' is highest priority and '31' is the lowest
       while in OSEK it is exactly the opposite.  */

   priority = osek_remap_priority(tcb_ptr->org_prio);

   /* Create a ThreadX thread, osek_task_wrapper is the entry function which is common for all thread
      implementing an OSEK task to differentiate which task we supply 'task id' as an input for
      thread entry function.  */

    retval = tx_thread_create ( &(tcb_ptr->task),
                                 (char *)tcb_ptr->name,
                                 osek_task_wrapper,
                                 (ULONG)tcb_ptr,
                                 tcb_ptr->pStackBase,
                                 tcb_ptr->stack_size,
                                 priority,
                                 priority,
                                 TX_NO_TIME_SLICE,
                                 TX_DONT_START);       /* All threads implementing an OSEK TASK are created in SUSPENDED state.  */

    /* Check for any error.  */
    if (retval != TX_SUCCESS)
    {
        /* Free the task tcb structure.  */
        osek_reset_tcb(tcb_ptr);

        /* Internal error.  */
        osek_internal_error(THREADX_OBJECT_CREATION_ERROR);

        /* Error will be returned whenever the ThreadX call fails.  */
        retval = E_OS_SYSTEM;
    }
    else
    {
        /* Got the thread, now check AUTO START Specified for this task.  */
        /* If the task is not specified as 'AUTO RUN' then it is not in 'READY' State,
           so won't be added to task queue at this stage.  */

        if (tcb_ptr->task_autostart == TRUE)
        {
            /* With AUTO START the task will attain READY state
               the moment it is created, whether it will execute (RUN) will depend on Scheduler.  */

            tcb_ptr->suspended = TX_FALSE;

            /* As this task will be in Ready immediately after creation its
               Current activation counter must be increment to 1 from 0.  */
            tcb_ptr->current_active = 1u;

            /* Now add this task to Schedulers 'READY' task queue.  */
            add_task_to_table(tcb_ptr);
        }

        /* Everything is fine.  */
        retval = E_OK;
    }


TX_RESTORE

    return(retval);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    osek_allocate_tcb                                   PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function attempts to allocate memory for a task stack and an   */
/*    OSEK Thread Control Block (TCB).                                    */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    stack_size                            Requested task stack size     */
/*    tcb_ptr                               Pointer to tcb pointer        */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    TX_TRUE                               If successful.                */
/*    TX_FALSE                              If an error occurs.           */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    osek_memory_allocate                   Allocate task's stack        */
/*    osek_reset_tcb                         Free task control block      */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    OSEK internal code                                                  */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
static ULONG osek_allocate_tcb(ULONG stack_size, OSEK_TCB **tcb_ptr)
{
OSEK_TCB         * tcb;
ULONG             index;
ULONG             retval;

    /* Assume the worst.  */
    tcb = (OSEK_TCB *)TX_NULL;

    /* This next search is optimized for simplicity, not speed.  */
    tcb = osek_tcb_pool;
    for (index = 0u; index < OSEK_MAX_TASKS; index++)
    {
        /* Is thisTCB in use? If not, we can use it.  */
        if (tcb->tcb_in_use == TX_FALSE)
        {
            /* This TCB is now in use.  */
            tcb->tcb_in_use = TX_TRUE;

            /* Stop searching.  */
            break;
        }

        tcb++;
    } /* try next TCB.  */

    /* Did we search all TCBs and come up empty?  */
    if (index == OSEK_MAX_TASKS)
    {
        /* No more TCBs available - user configuration error.  */
        return(E_OS_SYS_STACK);
    }
    else
    {
        /* Found one.  */
        *tcb_ptr = tcb;
    }

    /* Reset stack pointer.  */
    tcb->pStackBase  = (CHAR *)TX_NULL;

    /* Allocate memory for the task stack.  */
    retval = osek_memory_allocate(stack_size,
                              ((void **)&(tcb->pStackBase)));

    /* Make sure we got the memory for the task stack.  */
    if ((retval == 0u) || (tcb->pStackBase == TX_NULL))
    {
        /* Failed - at least try to return the OSEK TCB memory.  */
        osek_reset_tcb(tcb);

        /* Indicate failure.  */
        return (E_OS_SYS_STACK);
    }

    /* Remember the size of the stack.  */
    tcb->stack_size  = stack_size;

    /* Return OSEK TCB to caller.  */
    return (TX_TRUE);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    osek_memory_allocate                                PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function attempts to obtain the specified amount of memory     */
/*    from the OSEK heap.                                                 */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    size                                  Number of bytes to allocate   */
/*    memory_ptr                            Pointer to the returned       */
/*                                          memory                        */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    TX_TRUE                               If successful                 */
/*    TX_FALSE                              If an error occurs            */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    tx_byte_allocate                      Allocate from the pool        */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    OSEK internal code                                                  */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
static UINT osek_memory_allocate(ULONG size, void  **memory_ptr)
{
ULONG   size_align;
UINT    retval;

   /* Initialize the pointer to NULL in case we fail.  */
   *memory_ptr = (void *)TX_NULL;

   /* Force all alignments to long word boundaries to be safe.  */
   size_align = size;
   if ((size_align) != 0u)
   {
       /* Bump size up to next 4 byte boundary.  */
       size_align = ((size_align + 0x03u) & ~0x03u);
   }

   /* Attempt to allocate the desired memory from the OSEK heap.  */
   /* Do not wait - if memory isn't available, flag an error.  */
   retval = tx_byte_allocate((TX_BYTE_POOL *)&osek_region0_byte_pool, memory_ptr,
           size_align, TX_NO_WAIT);

   /* Make sure the memory was obtained successfully.  */
   if(retval != TX_SUCCESS)
   {
       /* Error obtaining memory.  */
       return (TX_FALSE);
   }

   /* Return to caller.  */
   return (TX_TRUE);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    osek_reset_tcb                                      PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function resets a task TCB to its default state.               */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    tcb                                   Task control block pointer    */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Start-up code                                                       */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
static void osek_reset_tcb(OSEK_TCB  *tcb_ptr)
{
TX_INTERRUPT_SAVE_AREA

UINT  index;

   /* Disable interrupt.  */
   TX_DISABLE

   /* Indicate this TCB is not in use.  */
   tcb_ptr->tcb_in_use = TX_FALSE;

   /* Make suspended and waiting to FALSE.  */
   tcb_ptr->suspended = TX_TRUE;
   tcb_ptr->waiting = TX_FALSE;

   /* Make this task as BASIC.  */
   tcb_ptr->task_type = BASIC;

   /* No AUTOSTART */
   tcb_ptr->task_autostart = 0u;

   /* Erase TCB id */
   tcb_ptr->osek_task_id = 0u;

   /* Make original priority of the task to 0 (the lowest possible).  */
   tcb_ptr->org_prio = 0u;

   /* Set the thread preemption threshold to default.  */
   tcb_ptr->cur_threshold = THREADX_LOWEST_PRIORITY;

   /* Make the stack size to 0.  */
   tcb_ptr->stack_size = 0u;

   /* No task to chain.  */
   tcb_ptr->task_to_chain = 0u;

   /* Since now event is not attached Make it to TX_NULL.  */
   tcb_ptr->events = 0u;

   /* Make task entry function to TX_NULL.  */
   tcb_ptr->task_entry = TX_NULL;

   /* Make maximum activation to 0.  */
   tcb_ptr->max_active = 0u;

   /* Make current activation to 0.  */
   tcb_ptr->current_active = 0u;

   /* Clear lists for external Resource attached and Resource occupied.  */
   for (index = 0u; index < OSEK_MAX_EXTERNAL_RES; index++)
   {
       tcb_ptr->external_resource_list[index] = 0u;
       tcb_ptr->external_resource_occuplied_list[index] = 0u;
   }

   /* Clear lists for Internal Resource attached and resource occupied.  */
   for (index = 0u; index < OSEK_MAX_INTERNAL_RES; index++)
   {
       tcb_ptr->internal_resource_list[index] = 0u;
       tcb_ptr->internal_resource_occuplied_list[index] = 0u;
   }

   /* Since resource is not occupied make it to FALSE.  */
   tcb_ptr->res_ocp = 0u;

   /* All done. */

   /* Enable interrupt.  */
   TX_RESTORE

   return;
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    osek_get_resource                                   PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function finds if any resource is available in the pool.       */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    tcb                              Task control block pointer         */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    res_ptr                          Resource pointer OR null           */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Start-up code                                                       */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
static ResourceType osek_get_resource(void)
{
TX_INTERRUPT_SAVE_AREA
ULONG             index;
OSEK_RESOURCE     *res_ptr;

    TX_DISABLE

   /* Start out pessimistic - assume we won't find a match.  */
   res_ptr = (OSEK_RESOURCE *)TX_NULL;

   /* Search the resource from resource pool.  */
   res_ptr = &(osek_res_pool[0u]);
   for (index = 0u; index < OSEK_MAX_RES; index++)
   {
       /* Make sure the resource is not already in use.  */
       if (res_ptr->res_in_use == TX_FALSE)
       {
           /* This Resource is now in use.  */
           res_ptr->res_in_use = TX_TRUE;
           break;
       }

       res_ptr++;
   }

   TX_RESTORE

   /* Did we search all OSEK RESOURCES and come up empty?  */
   if (index == OSEK_MAX_RES)
   {
       return ((ResourceType) TX_NULL);
   }

   return ((ResourceType) res_ptr);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*  osek_get_alarm                                        PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function gets an alarm if it is available.                     */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    NONE                                                                */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    ALARM_ID             AlarmID if found                               */
/*    TX_FALSE             If not available                               */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    NONE                                                                */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*  API function.                                                         */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
static UINT   osek_get_alarm(void)
{
TX_INTERRUPT_SAVE_AREA
OSEK_ALARM        *this_alarm;
UINT              index;

    TX_DISABLE

   /* Assume the worst.  */
   this_alarm = (OSEK_ALARM *)TX_NULL;

   /* Search for a free alarm.  */
   this_alarm = osek_alarm_pool;

   for (index = 0u;
        index < OSEK_MAX_ALARMS;
        index++)
   {
       /* Is this alarm in use? If not, we can use it.  */
       if (this_alarm->alarm_in_use == TX_FALSE)
       {
           /* This alarm is now in use.  */
           this_alarm->alarm_in_use = TX_TRUE;

           /* Stop searching.  */
           break;
       }

       this_alarm++;
   } /* check next if this one is in use.  */

   TX_RESTORE

   /* Did we search alarms all and come up empty?  */
   if (index == OSEK_MAX_ALARMS)
   {
       /* No more alarms available - user configuration error.  */
       return ((AlarmType)0u);
   }

   /* Found one.  */

   return ((AlarmType) this_alarm);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*  osek_get_events                                       PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function gets events if it is available in the pool.           */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    NONE                                                                */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    COUNTER_ID           CounterID if found                             */
/*    TX_FALSE             if not available                               */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    NONE                                                                */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    API function                                                        */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
static EventMaskType  osek_get_event(void)
{
TX_INTERRUPT_SAVE_AREA
EventMaskType     event_mask;

    TX_DISABLE

   if (global_event_count >= OSEK_MAX_EVENTS)
   {
       TX_RESTORE

       /* Already alloted all possible events.  */
       return ((EventMaskType)0u);
   }

   /* Next event.  */
   event_mask = 1u;
   event_mask <<= global_event_count;
   global_event_count++;

   TX_RESTORE

   return (event_mask);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*  osek_get_alarm                                        PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function gets an alarm if it is available.                     */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    NONE                                                                */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    COUNTER_ID           CounterID if found                             */
/*    TX_FALSE             If not available                               */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    NONE                                                                */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    API function                                                        */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
static CounterType   osek_get_counter(void)
{
TX_INTERRUPT_SAVE_AREA
OSEK_COUNTER       *this_counter;
UINT               index;

    TX_DISABLE

   /* Assume the worst.  */
   this_counter = (OSEK_COUNTER *)TX_NULL;

   /* Search for a free counter.  */
   this_counter = osek_counter_pool;
   for ( index = 0u;
         index < OSEK_MAX_COUNTERS;
         index++)
   {
       /* Is this guy in use? If not, we can use it.  */
       if (this_counter->cntr_in_use == TX_FALSE)
       {
           /* This counter is now in use.  */
           this_counter->cntr_in_use = TX_TRUE;
           /* Stop searching.  */
           break;
       }

       this_counter++;
   } /* Try next counter.  */

   TX_RESTORE

   /* Did we search all OSEK COUNTERS and come up empty?  */
   if (index >= OSEK_MAX_COUNTERS)
   {
       /* No more Counters available - user configuration error.  */
       return ((CounterType) 0u);
   }

   /* Found one.  */
   return ((CounterType)this_counter);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    osek_system_timer_entry                             PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*   This wrapper acts as a system timer and maintains a system counter   */
/*   It is up to the user to assign any one of the OSEK counter as        */
/*   a system counter by defining it.                                     */
/*   This counter will then be updated by this system timer.              */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    input                             Not used                          */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    OSEK system timer expiry function                                   */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
static void osek_system_timer_entry(ULONG input)
{
TX_INTERRUPT_SAVE_AREA
OSEK_COUNTER      *this_counter;
UINT               index;
UINT               found;

    TX_DISABLE

    (void)&input; /* Prevent unused parameter warnings.  */

   found = TX_FALSE;
   /* Search for a counter acting as a system counter.  */
   this_counter = osek_counter_pool;
   for ( index = 0u;
         index < OSEK_MAX_COUNTERS;
         index++)
   {
       /* Is this guy in a system counter.  */
       if (this_counter->system_timer == TX_TRUE)
       {
           /* Got system counter.  */
           found = TX_TRUE;
           /* Stop searching.  */
           break;
       }

       this_counter++;
   } /* Try next counter.  */

   /* Did we search all OSEK COUNTERS and come up empty?  */
   if (found == TX_TRUE)
   {
       /* Got a system counter, update it.  */
       IncrCounter((CounterType)this_counter);
   }

   TX_RESTORE

   return;
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    osek_remap_priority                                 PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function converts a OSEK task priority into a ThreadX          */
/*    priority.                                                           */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    osek_priority                       Priority of task                */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    ThreadX priority                    Converted priority              */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    OSEK internal code                                                  */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
static UINT osek_remap_priority(UINT osek_priority)
{

   /* Remap OSEK task priority to ThreadX thread priority.              */
   /* In OSEK 0 = lowest priority and in ThreadX, 0 = highest priority, */
   /* Means ThreadX priority of a thread acting as a OSEK Task          */
   /* would be ThreadX max priority - osek_priority.                    */

   /* Return the ThreadX priority.  */
   return (THREADX_MAX_PRIORITY - 1u - osek_priority);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    osek_task_wrapper                                   PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    Every thread that is modeling a OSEK task uses this routine has     */
/*    its entry point. This routine calls the OSEK task entry function.   */
/*                                                                        */
/*    A task must end with either TerminateTask() or ChainTask(), if this */
/*    is not the way a task is ended, the control will come back to this  */
/*    osek_task_wrapper and call osek_internal_error() with an error code */
/*    'TASK_ENDING_WITHOUT_CHAIN_OR_TERMINATE'.                           */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    tcb                                Task control block pointer       */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    task_entry                         OSEK task entry                  */
/*    osek_internal_error                                                 */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Internal code                                                       */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
static void osek_task_wrapper(ULONG tcb)
{
TX_INTERRUPT_SAVE_AREA
OSEK_TCB        *tcb_ptr;
StatusType      status;

    TX_DISABLE

   /* The input argument is really a pointer to the task's TCB.  */
   tcb_ptr = (OSEK_TCB *)tcb;
   /* Check whether it is a Task or an ISR.  */
   if (tcb_ptr->osek_task_id == OSEK_TASK_ID)
   {
       osek_wrapper_operation_mode = NORMAL_EXECUTION_MODE;

       /* last_run_task now holds this new task being run.  */
       last_run_task = (ULONG)((TX_THREAD*)tcb_ptr);

       /* Check this task's scheduling policy.  */
       if (tcb_ptr->policy == NON)
       {
           pop_task_from_table(tcb_ptr);   /* This routine remove task from table based on its cur_threshold.  */

           /* Store the new preemption threshold.  */
           tcb_ptr->cur_threshold = OSEK_NON_SCHEDULE_PRIORITY;

           /* Place this task to its proper priority queue based on Scheduling policy.  */
           push_task_to_table(tcb_ptr);       /* This routine pushes a task at the front of a queue based on its cur_threshold.  */
       }

   }
   else
   {
       if (tcb_ptr->task_type == CATEGORY1)
       {
               osek_wrapper_operation_mode = ISR1_MODE;
       }
       else
       {
               osek_wrapper_operation_mode = ISR2_MODE;
       }
   }

   TX_RESTORE

   /* Invoke the OSEK task entry point with appropriate arguments.  */
   (tcb_ptr->task_entry)();

   /* In case of a task we shouldn't be here- because tasks are always ended with either
      a TerminateTask() or ChainTask() but ISR will return here.  */
   /* If it is a TASK then seems to be ended without any ChainTask or TerminateTask call
      anyway, as the task is ended it is better to Terminate it so that next available ready
      task can be run.  */


   /* Terminate the task.  */
   if (tcb_ptr->osek_task_id == OSEK_TASK_ID)
   {
       /* Change to default operations mode.  */
       osek_wrapper_operation_mode = NORMAL_EXECUTION_MODE;

       status = TerminateTask();
       if(status != E_OK) {
           osek_internal_error(SYS_MGR_SEND_TERMINATETASK);
       }
   }
   else
   {
       status = TerminateISR();
       if(status != E_OK) {
           osek_internal_error(SYS_MGR_SEND_TERMINATETASK);
       }
   }
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    osek_internal_error                                  PORTABLE C     */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function is invoked whenever an error is encountered           */
/*    in the OSEK code. This is an endless loop.                          */
/*    Source of the error can be traced by the error code.                */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    error_code                            Error code                    */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    OSEK internal code                                                  */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
static void osek_internal_error(ULONG error_code)
{
   /* This just an end less loop, to trap error.  */
   for(;;)
   {
       ; /* Empty loop.  */
   }
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    exec_ErrorHook                                       PORTABLE C     */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function invokes ErroHook routine whenever an error is         */
/*    encountered, provided ErroHook is defined.                          */
/*    Hook routines are called by the operating system, in a special      */
/*    context have higher prior than all tasks, and not interrupted by    */
/*    category 2 interrupt routines.                                      */
/*    These functions are implemented by the user with user defined       */
/*    functionality. Usually hook routines are allowed to use only a      */
/*    subset of API functions. Whether to execute these routine or not is */
/*    user configurable via OIL.                                          */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    error_code                            Passed to ErrorHook           */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    Application->error_handler          That is ErrorHook (if defined)  */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    OSEK internal code                                                  */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
static void  exec_ErrorHook (StatusType error)
{

TX_THREAD     *thread_ptr;
UINT           save_op_mode;
UINT           status;
ULONG          request[SYSMGR_QUEUE_MSG_LENGTH];

   /* Check for any startup hook routine.  */
   if (Application->error_hook_handler != TX_NULL)
   {
       /* But check whether already in ErrorHook routine? There must not be nested ErrorHook calls.  */
       if (osek_wrapper_operation_mode == ERRORHOOK_MODE)
       {
           /* Already in ErroHook.  */
           return;
       }

       /* Save old operation mode.  */
       save_op_mode = osek_wrapper_operation_mode;

       /* Change to ErroHOOK mode.  */
       osek_wrapper_operation_mode = ERRORHOOK_MODE;

       /* Now execute user defined ErroHook routine.  */
       (Application->error_hook_handler)(error);

       /* Get the pointer to thread.  */
       thread_ptr = tx_thread_identify();

       /* Restore original operation mode.  */
       osek_wrapper_operation_mode = save_op_mode;

       /* If this ErrorHook is called by a task then check for any ISR came while executing this ErrorHook.  */
       if (osek_wrapper_operation_mode == NORMAL_EXECUTION_MODE)
       {
           /* Now send a message to the SysMgr supervisor thread to execute the Error Hook.  */
           /* Build the request. */
           request[0] = SYSMGR_ERRORHOOK;           /* Request type.            */
           request[1] = (ULONG)thread_ptr;          /* ptr of calling thread.   */
           request[2] = 0u;                         /* input to Error Hook.     */
           request[3] = 0u;

           /* Since the system manager supervisor thread is with the highest priority,  */
           /* this routine will be preempted by SysMgr supervisor thread when   */
           /* queue read is successful.                                         */

           status = tx_queue_send(&osek_work_queue, request, TX_NO_WAIT);

           /* This should always succeed.  */
           if (status != TX_SUCCESS)
           {
               /* System internal error.  */
               osek_internal_error(SYS_MGR_SEND_CHAINTASK);

               /* Return.  */
               return;
           }
       }  /* End if ( osek_wrapper_operation_mode ==.  */

   } /* end  if (Application->error_handler).  */

    return;
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    exec_PreTaskHook                                    PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function invokes the PreTaskHook routine whenever a task       */
/*    starts provided PreTaskHook is defined.                             */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    OSEK internal code                                                  */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
static void  exec_PreTaskHook(void)
{

UINT           save_op_mode;

   if (Application->pretask_hook_handler != TX_NULL)
   {
       /* Set up the mode.  */
       save_op_mode = osek_wrapper_operation_mode;
       osek_wrapper_operation_mode = PRETASKHOOK_MODE;

       /* Call the Pretask hook.  */
       (Application->pretask_hook_handler)();

       /* Restore mode.  */
       osek_wrapper_operation_mode = save_op_mode;

   }  /* end  if (Application->PretaskHook_handler).  */

    return;
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    exec_PostTaskHook                                    PORTABLE C     */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function invokes PostTaskHook routine whenever a task          */
/*    terminates provided PostTaskHook is defined.                        */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    OSEK internal code                                                  */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
static void  exec_PostTaskHook(void)
{

UINT           sav_op_mode;

   if (Application->posttask_hook_handler != TX_NULL)
   {
       /* Set up the mode.  */
       sav_op_mode = osek_wrapper_operation_mode;
       osek_wrapper_operation_mode = POSTTASKHOOK_MODE;

       /* Call the Posttask hook.  */
       (Application->posttask_hook_handler)();

       /* Restore mode.  */
       osek_wrapper_operation_mode = sav_op_mode;

    }  /* end  if (Application->PosttaskHook_handler).  */

    return;
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    add_task_to_table                                   PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function adds a ready task in the task queue.                  */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    *tcb_ptr              Pointer to the task to be added to the queue  */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    OSEK internal code                                                  */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
static void  add_task_to_table(OSEK_TCB *tcb_ptr)
{
TX_INTERRUPT_SAVE_AREA
UINT         priority;
UINT         i;

    TX_DISABLE

   /* Get the priority of this task.  */
   priority = tcb_ptr-> org_prio;

   for (i = 0u; i < TASK_QUEUE_DEPTH; i++)
   {
       /* Add this task to the a queue assigned for this task's priority level.  */
       /* Find next free entry in the queue.  */
       /* Oldest activated task is at the front of the queue, so this new entry.  */
       /* will go at the end of the queue.  */

       if (task_table[priority][i] == 0u)
       {
           task_table[priority][i] = (TaskType)tcb_ptr;
           break;
       }
   }

   if (i >= TASK_QUEUE_DEPTH)
   {
       osek_internal_error(SYSMGR_FATAL_ERROR);
   }

   TX_RESTORE

}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    push_task_to_table                                   PORTABLE C     */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function pushes a task at the front of the task queue.         */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    *tcb_ptr              Pointer to the task to be added to the queue  */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    OSEK internal code                                                  */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
static void   push_task_to_table(OSEK_TCB *tcb_ptr)
{
TX_INTERRUPT_SAVE_AREA
UINT    priority;
UINT    i;
UINT    k;

    TX_DISABLE

   priority = tcb_ptr->cur_threshold;

   i = (TASK_QUEUE_DEPTH - 2u);

   while (i != 0u)
   {
       /* Add this task to the queue (of for priority level supplied).  */
       /* Place the entry at the front of the queue and push back all entries by one */
       k = i + 1u;
       task_table[priority][k] = task_table[priority][i];
       i--;
   }

   task_table[priority][1u] = task_table[priority][0u];

   /* Now push the calling task's id  at the front of the queue.  */
   task_table[priority][0u] = (ULONG)tcb_ptr;

   TX_RESTORE
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    start_osek_tasks                                     PORTABLE C     */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function schedules the first task upon StatOS                  */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    Error Code                                                          */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    tx_thread_resume                                                    */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    osek_system_manager_entry                                           */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
static void start_osek_tasks(void)
{
TX_INTERRUPT_SAVE_AREA
TX_THREAD  *task_thread;
UINT       i;
UINT       j;
UINT       found;

    TX_DISABLE

   /* Start with the highest priority */
   j = OSEK_ISR1_PRIORITY;
   found = FALSE;

   while (found == FALSE)
   {
       for (i = 0u; i < TASK_QUEUE_DEPTH; i++)
       {
           /* Search for any ready but not waiting task within this priority level.  */
           if (( task_table[j][i] != 0u) && (((OSEK_TCB*)task_table[j][i] )->waiting == TX_FALSE))
           {
               /* Found it but check whether this task can be run,
                  This task must have higher priority than current task's ceiling priority
                  This task must have all needed Internal/External resources.  */
               task_thread = &((OSEK_TCB*)task_table[j][i])->task;
               found = check_task_to_run((OSEK_TCB*)task_table[j][i]);
               if (found == TRUE)
               {
                   break;
               }
           }

       }

       /* No ready task found for this priority level, check for next lower priority level
          but are we at the lowest priority level?  */
       if ((j == 0u) || (found == TRUE))
       {
           break;
       }

       j--;

   } /* End while.  */

   /* Reached here means either a ready Task is found or no task is READY.  */
   /* if found = 1, task is found.  */

   if (found == FALSE)
   {
       last_run_task = INVALID_TASK;
   }
   else
   {
       if (((OSEK_TCB*)task_thread)->osek_task_id == OSEK_ISR_ID)
       {
       /* If it is an ISR , set the op mode and no need to:
          call pre and post task hooks as well as change last_run_task data.  */
          osek_wrapper_operation_mode = ISR2_MODE;
       }
       else
       {
           osek_wrapper_operation_mode = NORMAL_EXECUTION_MODE;
           /* Check whether it is a fresh OS start, for fresh start no need to run pre & post task hooks.  */
           if (system_start == 0u)
           {
               /* If no preemption takes place , then no need to execute pre and post task hooks.  */
               if ((last_run_task != (ULONG)task_thread )|| (task_terminated == TX_TRUE))
               {
                   exec_PostTaskHook();

                   /* Update last run task data to reflect next task to run.  */
                   last_run_task = (ULONG)task_thread;

                   exec_PreTaskHook();
               }

           }

           last_run_task = (ULONG)task_thread;
       } /* End else. */

       tx_thread_resume(task_thread);

       system_start = TX_FALSE;

       task_terminated = TX_FALSE;

   } /* end of else part of if (!found).  */

   TX_RESTORE
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    check_task_to_run                                    PORTABLE C     */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function schedules the first task upon StatOS                  */
/*    This is called by system manager thread when StartOS is called.     */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    Error Code                                                          */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    tx_thread_resume                                                    */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    osek_system_manager_entry                                           */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
static UINT check_task_to_run (OSEK_TCB *tcb_ptr)
{
TX_INTERRUPT_SAVE_AREA
   UINT     status;

    TX_DISABLE

   if (tcb_ptr->osek_task_id != OSEK_TASK_ID)
   {
       /* if selection is an ISR,
          it can't be run if ISRs are suspended or any HOOK mode is ON.  */
       if ((suspend_ISR2 == TX_TRUE) ||
           (osek_wrapper_operation_mode == ERRORHOOK_MODE)      ||
           (osek_wrapper_operation_mode == PRETASKHOOK_MODE)    ||
           (osek_wrapper_operation_mode == POSTTASKHOOK_MODE)   ||
           (osek_wrapper_operation_mode == STARTUPHOOK_MODE)    ||
           (osek_wrapper_operation_mode == SHUTDOWNHOOK_MODE)   ||
           (osek_wrapper_operation_mode == ALARM_CALLBACK_MODE))
       {
           TX_RESTORE

           return (FALSE);
       }
   }

   if (tcb_ptr->internal_res != 0u)
   {
       status = get_internal_resource(tcb_ptr);

       if (status != E_OK)
       {
           TX_RESTORE

           return (FALSE);
       }
   }

   status = check_external_resource(tcb_ptr);
   if (status != E_OK)
   {
       TX_RESTORE

       return (FALSE);
   }

   /* Now check for NON scheduling policy.  */
   if (tcb_ptr->policy == NON)
   {
       /* First remove task from its current queue position.  */
       pop_task_from_table(tcb_ptr);

       tcb_ptr->cur_threshold = OSEK_NON_SCHEDULE_PRIORITY;

       push_task_to_table(tcb_ptr);
   }

   TX_RESTORE

   return (TRUE);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    pop_task_from_table                                 PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*    Removes a task from the table of active tasks.                      */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    id                           Id of the resource.                    */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*   Application Code                                                     */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
static void  pop_task_from_table(OSEK_TCB *tcb_ptr)
{
TX_INTERRUPT_SAVE_AREA
UINT         priority;
UINT         i;
UINT         j;
UINT         k;

    TX_DISABLE

   /* Get the priority of this task.  */
   priority = tcb_ptr-> cur_threshold;
   j = (TASK_QUEUE_DEPTH - 2u);
   for (i = 0u; i < j; i++)
   {
       /* Move N+1 th element to Nth location.  */
       /* Oldest task is at the bottom of the queue.  */
       k = i + 1u;
       task_table[priority][i] = task_table[priority][k];
   }

   /* Make the top most element in the queue NULL as the oldest task is removed from the bottom.  */
   j = (TASK_QUEUE_DEPTH) - 1u;
   task_table[priority][j] = 0u;

   TX_RESTORE
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    check_linked_resources                              PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*   Check if resources are linked                                        */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*   Application Code                                                     */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
static void        check_linked_resources(void)
{
TX_INTERRUPT_SAVE_AREA
ULONG              index;
OSEK_RESOURCE     *res_ptr;
OSEK_RESOURCE     *linked_res_ptr;

    TX_DISABLE

    /* Search the Resource from resource pool.  */
    for (index = 0u; index < OSEK_MAX_RES; index++)
    {

        res_ptr = &(osek_res_pool[index]);
        if ((res_ptr->res_in_use == TX_TRUE) && (res_ptr->type == LINKED))
        {
            /* Get the res linked to this resource.  */
            linked_res_ptr = (OSEK_RESOURCE *)(res_ptr->resolved_res);

            /* Make this resources's ceiling priority equal to the ceiling priority of linked resource.  */
            if ( res_ptr->c_priority < linked_res_ptr->c_priority)
            {
                res_ptr->c_priority = linked_res_ptr->c_priority;
            }
        }
    }

    TX_RESTORE
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    get_internal_resource                               PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*   This call serves to enter critical sections in the code that are     */
/*   assigned to the resource referenced by <ResID>. A critical section   */
/*   must always be left using ReleaseResource. Nested resource           */
/*   occupation is only allowed if the inner critical sections are        */
/*   completely executed within the surrounding critical section.         */
/*   Nested occupation of one and the same resource is also forbidden.    */
/*   Corresponding calls to GetResource and ReleaseResource should appear */
/*   within the same function on the same function level.                 */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    id                           Id of the resource.                    */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    E_OK                         If success                             */
/*    E_OS_CALLEVEL                Called from ISR                        */
/*    E_OS_ACCESS                  Attempt to get a resource which is     */
/*                                 already occupied by any task or ISR,   */
/*                                 or the statically assigned priority of */
/*                                 the calling task or interrupt routine  */
/*                                 is higher than the calculated ceiling  */
/*                                 priority,                              */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    osek_task_independent_area   See if called from task independent    */
/*                                 area                                   */
/*    tx_thread_identify           Identify the current thread            */
/*    osek_internal_error          Osek internal error                    */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*   Application Code                                                     */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
static StatusType get_internal_resource(OSEK_TCB  *tcb_ptr)
{
TX_INTERRUPT_SAVE_AREA
OSEK_RESOURCE  *osek_res;
UINT            res_prio;
UINT            index;


TX_DISABLE

   for (index = 0u; index < OSEK_MAX_INTERNAL_RES; index++)
   {

       if (tcb_ptr->internal_resource_list[index] == 0u)
       {
           break;   /* No Internal Resource in the list.  */
       }

       /* Get internal RES's control block.  */
       osek_res = (OSEK_RESOURCE *)tcb_ptr->internal_resource_list[index];

       /* Now check whether this resource is already occupied by other task.  */
       if (osek_res->taskid != 0u)
       {
           /* Some entry is there, is it occupied by any other task?  */
           if (osek_res->taskid != (TaskType)tcb_ptr)
           {
               TX_RESTORE

               return (E_OS_ACCESS);
           }
       }

       /* Take this resource.  */
       tcb_ptr->internal_resource_occuplied_list[index] = tcb_ptr->internal_resource_list[index];

       /* Save this task's id in the res's control block to indicate that this task is the owner of this res.  */
       osek_res->taskid = (TaskType)(tcb_ptr);

   }   /* End for (index..  */

   /* Now all internal resources are taken, this needs to change task's preemption
      to highest ceiling priority of internal resource occupied.  */

   /* First remove task from its current queue position.  */
   pop_task_from_table(tcb_ptr);

   /* Now need to change this task's preemption threshold to resource's ceiling priority.  */
   /* Assume task's original priority is the highest.  */
   if ((tcb_ptr->resource_scheduler != 0u) || (tcb_ptr->policy == NON))
   {
       tcb_ptr->cur_threshold = OSEK_NON_SCHEDULE_PRIORITY;
   }

   for (index = 0u; index < OSEK_MAX_INTERNAL_RES; index++)
   {
       if (tcb_ptr->internal_resource_occuplied_list[index] == 0u) {
           break;
       }

       res_prio = ((OSEK_RESOURCE *) (tcb_ptr->internal_resource_occuplied_list[index]))->c_priority;
       if  (tcb_ptr->cur_threshold < res_prio )
       {
           tcb_ptr->cur_threshold = res_prio;
       }
   }
   /* Now the task's current threshold reflect the highest of ceiling priority of the remaining
      resources held by this task, move this task to the front of that priority queue.  */
   push_task_to_table(tcb_ptr);

   TX_RESTORE

   return (E_OK);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    release_internal_resource                           PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*   This call releases any internal resources held by the calling task.  */
/*   It also changes the calling task's priority to reflect either its    */
/*   original priority, NON SCHEDULE priority or maximum ceiling          */
/*   priority of any any external resources held by this task.            */
/*   At the end this task is then moved to a queue appropriate to its new */
/*   ceiling priority.                                                    */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    id                           Task id.                               */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    E_OK                         Always                                 */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*   pop_task_from_table           Removes a task from its current queue  */
/*   push_task_to_table            Pushes a task at the front of a queue  */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*   Wrapper internal code (not available for application)                */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
static StatusType  release_internal_resource(OSEK_TCB  *tcb_ptr)
{
TX_INTERRUPT_SAVE_AREA
UINT           index;

    TX_DISABLE

    /* Release any internal resources held?  */
    for (index = 0u; index < OSEK_MAX_INTERNAL_RES; index++)
    {

        if (tcb_ptr->internal_resource_occuplied_list[index] == 0u)
        {
             break;
        }

        ((OSEK_RESOURCE *)(tcb_ptr->internal_resource_occuplied_list[index]))->taskid = 0u;

        tcb_ptr->internal_resource_occuplied_list[index] = 0u;
    }

    /* First remove task from its current queue position.  */
    pop_task_from_table(tcb_ptr);

    /* As all internal resources are released and no external resources are held
       this task must be reverted to its original design time priority.  */

    tcb_ptr->cur_threshold = tcb_ptr->org_prio;

    /* Now move this task to the front of that priority queue.  */
    push_task_to_table(tcb_ptr);

    TX_RESTORE

    return (E_OK);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    check_external_resource                             PORTABLE C      */
/*                                                           6.1.7        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    William E. Lamie, Microsoft Corporation                             */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*   This call serves to enter critical sections in the code that are     */
/*   assigned to the resource referenced by <ResID>. A critical section   */
/*   must always be left using releaseResource. Nested resource           */
/*   occupation is only allowed if the inner critical sections are        */
/*   completely executed within the surrounding critical section.         */
/*   Nested occupation of one and the same resource is also forbidden.    */
/*   Corresponding calls to GetResource and ReleaseResource should appear */
/*   within the same function on the same function level.                 */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    id                           Id of the resource.                    */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    E_OK                         If success                             */
/*    E_OS_CALLEVEL                Called from ISR                        */
/*    E_OS_ACCESS                  Attempt to get a resource which is     */
/*                                 already occupied by any task or ISR,   */
/*                                 or the statically assigned priority of */
/*                                 the calling task or interrupt routine  */
/*                                 is higher than the calculated ceiling  */
/*                                 priority.                              */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    osek_task_independent_area   See if called from task independent    */
/*                                 area                                   */
/*    tx_thread_identify           Identify the current thread            */
/*    osek_internal_error          OSEK internal error                    */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*   Application Code                                                     */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
/*                                                                        */
/**************************************************************************/
static StatusType      check_external_resource(OSEK_TCB *tcb_ptr)
{
TX_INTERRUPT_SAVE_AREA
OSEK_RESOURCE  *osek_res;
OSEK_RESOURCE  *osek_res1;
StatusType      status;
UINT            index;

   /* Check that all assigned external resources for this task are free.  */
   /* Here only availability of resources is checked, no resource will be taken.  */

    TX_DISABLE

   status = E_OK;       /* Assuming that everything is OK.  */
   for (index = 0u; index < OSEK_MAX_EXTERNAL_RES; index++)
   {

       if (tcb_ptr->external_resource_list[index] == 0u)
       {
           break;    /* No External Resource left in the list.  */
       }

       /* Get External RES's control block.  */
       osek_res = (OSEK_RESOURCE *)tcb_ptr->external_resource_list[index];

       /* Now check whether this resource is already occupied by other task.  */
       if (osek_res->taskid != 0u)
       {
           if (osek_res->taskid != (TaskType)tcb_ptr)
           {
               status = E_OS_ACCESS; /* Already occupied by any other task.  */
               break;
           }

       }

       if (osek_res->type == LINKED)
       {

           osek_res1 = (OSEK_RESOURCE *)(osek_res->resolved_res);

           if (osek_res1->taskid != 0u)
               {
               if (osek_res1->taskid != (TaskType)tcb_ptr)
               {
                   status = E_OS_ACCESS; /* Already occupied by any other task.  */
                   break;
               }
           }

       } /* End (osek_res->type == LINKED) */


   }   /* End for.  */

   TX_RESTORE

   return (status);
}


/***************************  END OF FILE ************************************/
