// CrossWorks Tasking Library.
//
// Copyright (c) 2004 Rowley Associates Limited.
//
// This file may be distributed under the terms of the License Agreement
// provided with this software.
//
// THIS FILE IS PROVIDED AS IS WITH NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.

#ifndef CrossWorks_Tasking_Library
#define CrossWorks_Tasking_Library

#ifdef __cplusplus
extern "C" {
#endif

// Enumeration of set of task states
enum
{
  CTL_STATE_RUNNABLE          = 0,   // Task can run
  CTL_STATE_TIMER_WAIT        = 1,   // Task is waiting for a time value
  CTL_STATE_EVENT_WAIT        = 2,   // Task is waiting for events to be set
  CTL_STATE_EVENT_ANY_NOT_ALL = 4,   // Task is waiting for any rather than all events to be set
  CTL_STATE_EVENT_AUTO_CLEAR  = 8,   // Auto clear events on wait completion
  CTL_STATE_FINISHED          = 128  // Task has finished
}; 

// Enumeration of interrupt trigger types
typedef enum
{
  CTL_ISR_TRIGGER_FIXED,
  CTL_ISR_TRIGGER_LOW_LEVEL,
  CTL_ISR_TRIGGER_HIGH_LEVEL,
  CTL_ISR_TRIGGER_NEGATIVE_EDGE,
  CTL_ISR_TRIGGER_POSITIVE_EDGE,
  CTL_ISR_TRIGGER_DUAL_EDGE
} 
CTL_ISR_TRIGGER_t;

// 32bit timer
typedef unsigned long CTL_TIME_t;

// Event Set's are word sized - 16 or 32 depending on the machine
typedef unsigned CTL_EVENT_SET_t;
typedef struct CTL_TASK_s CTL_TASK_t;

// The Task structure should only be modified via the API functions
struct CTL_TASK_s 
{
  unsigned *stack_pointer;              // to saved registers - don't move this - assembly code knows about it
  unsigned char priority;               // higher numbers denote higher priority
  unsigned char state;                  // state of task
  CTL_TASK_t *next;                     // next pointer for wait queue

  CTL_TIME_t timeout;                   // timeout value - defined when state & CTL_STATE_TIMER_WAIT
  CTL_EVENT_SET_t *wait_event_set;      // the event set to wait on - defined when state & CTL_STATE_EVENT_WAIT
  CTL_EVENT_SET_t wait_events;          // the events to wait for - defined when state & CTL_STATE_EVENT_WAIT                

  int errno;                            // thread specific errno 

  char *name;                           // a name for the debugger to display
};

// Turn main into a task - this must be called first
void 
ctl_task_init(CTL_TASK_t *,
              unsigned char priority,
              char *name);

// Add a new task to task list and do scheduling
void 
ctl_task_run(CTL_TASK_t *,                                     
             unsigned char priority,
             void (*entrypoint)(void *),     // entrypoint the task starts executing - parameter is passed to it
             void *parameter,                // parameter to pass to entrypoint
             char *name,                  
             unsigned stack_size_in_words,   // note that the stack should be allocated in words not bytes        
             unsigned *stack);    

// Remove an existing task from the task list and do scheduling
void 
ctl_task_remove(CTL_TASK_t *);

// Change the priority of the task and do scheduling
void 
ctl_task_set_priority(CTL_TASK_t *,
                      unsigned char priority);
                  
// Wait for something to happen and do scheduling.
// waitType can be one of the following combinations
// TaskStateTimerWait | TaskStateEventWait
// TaskStateEventAnyNotAll | TaskStateEventAutoClear
// or 0 if a cooperative reschedule is required
// Returns the eventSet prior to auto clearing
//         or 0 if timeout occured.
unsigned 
ctl_task_wait(unsigned waitType,
              CTL_TIME_t timeout,
              CTL_EVENT_SET_t *eventSet,
              CTL_EVENT_SET_t events);

// Set and Clear the specified events in the eventSet and do scheduling
// The operation is *e = (*e | set) & ~clear
void 
ctl_set_clear_events(CTL_EVENT_SET_t *e,
                     CTL_EVENT_SET_t set,
                     CTL_EVENT_SET_t clear);

// Turn off interrupts.
// Returns the previous interrupt enabled state (1 enabled, 0 disabled).
int 
ctl_disable_interrupts(void);

// Turn on interrupts.
// Returns the previous interrupt enabled state (1 enabled, 0 disabled).
int
ctl_enable_interrupts(void);

// Set interrupts enabled (1 enabled, 0 disabled).
void 
ctl_set_interrupts(int enabled);

// increment the timer tick and do scheduling
// this must be called from an interrupt handler
// interrupts must be disabled when this is called
void 
ctl_increment_tick_from_isr(void);

// Interrupt ISR function type.
typedef void (*CTL_ISR_FN_t)(void);

// Install a new interrupt handler.
int 
ctl_set_isr(unsigned int vector, 
            unsigned int priority, 
            CTL_ISR_TRIGGER_t trigger, 
            CTL_ISR_FN_t isr, 
            CTL_ISR_FN_t *oldisr);

// Unmask an interrupt source.
int 
ctl_unmask_isr(unsigned int vector);

// Mask an interrupt source.
int 
ctl_mask_isr(unsigned int vector);

// Low-level ISR support - only need to use this if
// no programmable interrupt support. 
// Jump to this on exit from an IRQ - it will not return.
// savedRegisters must point to the saved user registers.
// interrupts must be disabled when this is called.
void 
ctl_exit_isr(void *savedRegisters);

// Re-enable interrupts from within an ISR in order to allow higher priority
// interrupts to execute. A call to this function must be accompanied with a 
// call to ctl_isr_disable_interrupts before the ISR exits.
void
ctl_isr_enable_interrupts(void);

// Disable interrupts from within an ISR.
void
ctl_isr_disable_interrupts(void);

typedef enum
{
  CTL_ERROR_NO_TASKS_TO_RUN,
  CTL_WAIT_CALLED_FROM_ISR
} 
CTL_ERROR_CODE_t;

// this function is called if something goes wrong with your application.
void 
ctl_handle_error(CTL_ERROR_CODE_t);

// System state
extern CTL_TASK_t *ctl_task_list;             // list of waiting tasks sorted by priority
extern CTL_TASK_t *ctl_task_executing;        // the task that is currently executing
extern unsigned ctl_interrupt_count;          // the nested interrupt count 
extern CTL_TIME_t ctl_current_time;           // the current time
extern CTL_EVENT_SET_t ctl_libc_mutex;        // event set used to serialise access to the C library

// Enumeration of the event bits contained in the ctl_libc_mutex
typedef enum
{
  CTL_LIBC_MUTEX_HEAP = (1<<0),
  CTL_LIBC_MUTEX_PRINTF = (1<<1),
  CTL_LIBC_MUTEX_SCANF = (1<<2),
  CTL_LIBC_MUTEX_DEBUG_IO = (1<<3)
}
CTL_LIBC_MUTEX_BITS;

#ifdef __cplusplus
}
#endif

#endif
