// CrossWorks Tasking Library.
//
// Copyright (c) 2004, 2006 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
//
// Task Support
//
// Enumeration of set of task states
enum
{
CTL_STATE_RUNNABLE = 0x00, // Task can run
CTL_STATE_TIMER_WAIT = 0x01, // Task is waiting for a time value
CTL_STATE_EVENT_WAIT = 0x02, // Task is waiting for events to be set
CTL_STATE_EVENT_ANY_NOT_ALL = 0x04, // Task is waiting for any rather than all events to be set
CTL_STATE_EVENT_AUTO_CLEAR = 0x08, // Auto clear events on wait completion
CTL_STATE_SEMAPHORE_WAIT = 0x10, // Task is waiting for a semaphore
CTL_STATE_MESSAGE_QUEUE_POST_WAIT = 0x20, // Task is waiting to post to a message queue
CTL_STATE_MESSAGE_QUEUE_RECEIVE_WAIT = 0x40 // Task is waiting to receive from a message queue
};
// 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;
// Interrupt ISR function type.
typedef void (*CTL_ISR_FN_t)(void);
// The Task structure should only be modified via the API functions
typedef struct CTL_TASK_s CTL_TASK_t;
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; // wait timeout value - when state & CTL_STATE_TIMER_WAIT
// and timeslice value when the task executing
union
{
void *wait_object; // the event set to wait on - when state & CTL_STATE_EVENT_WAIT
// the semaphore to wait on - when state & CTL_STATE_SEMAPHORE_WAIT
// the message queue to wait on - when (state & CTL_STATE_MESSAGE_QUEUE_POST_WAIT) || (state & CTL_STATE_MESSAGE_QUEUE_RECEIVE_WAIT)
unsigned timeout_occured; // 1 if a wait timed out otherwise 0 - when state == CTL_RUNNABLE
}
v;
union
{
CTL_EVENT_SET_t wait_events; // the events to wait for - when state & CTL_STATE_EVENT_WAIT,
// the event set value prior to autoclear - when state == CTL_RUNNABLE
void *temp_message; // the message to post/receive - a temporary
unsigned char temp_byte; // the byte to post/receive - a temporary
}
u;
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,
unsigned call_size_in_words); // optional parameter if call stack is seperate from data stack
// Remove an existing task from the task list and do scheduling
void ctl_task_remove(CTL_TASK_t *);
// Remove the executing task from the list.
void ctl_task_die(void);
// Change the priority of the task and do scheduling
void ctl_task_set_priority(CTL_TASK_t *,
unsigned char priority);
// Cause a reschedule
void ctl_task_reschedule(void);
//
// Timer support
//
// Start the timer ticking - which will call timerFn on timeout
// For example ctl_start_timer(ctl_increment_tick_from_isr);
void ctl_start_timer(CTL_ISR_FN_t timerFn);
// return the number of timer ticks per second
unsigned long ctl_get_ticks_per_second(void);
// Atomically get the current value of the timer
CTL_TIME_t ctl_get_current_time(void);
// Wait for the timer to be timeout - note that this is not a delay
void ctl_timeout_wait(CTL_TIME_t timeout);
// 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);
// Enumeration to specify the type of timeout for a blocking function call
typedef enum
{
CTL_TIMEOUT_NONE, // no timeout - block indefinitely
CTL_TIMEOUT_ABSOLUTE, // the timeout is an absolute time
CTL_TIMEOUT_DELAY // the timeout is a delay
} CTL_TIMEOUT_t;
//
// Event support
//
// Initialise an event set
void ctl_events_init(CTL_EVENT_SET_t *e,
CTL_EVENT_SET_t set);
// Set and clear the specified events in the eventSet and do scheduling.
// The operation is *e = (*e | set) & ~clear
void ctl_events_set_clear(CTL_EVENT_SET_t *e,
CTL_EVENT_SET_t set,
CTL_EVENT_SET_t clear);
typedef enum
{
CTL_EVENT_WAIT_ANY_EVENTS = CTL_STATE_EVENT_WAIT | CTL_STATE_EVENT_ANY_NOT_ALL,
CTL_EVENT_WAIT_ANY_EVENTS_WITH_AUTO_CLEAR = CTL_STATE_EVENT_WAIT | CTL_STATE_EVENT_ANY_NOT_ALL | CTL_STATE_EVENT_AUTO_CLEAR,
CTL_EVENT_WAIT_ALL_EVENTS = CTL_STATE_EVENT_WAIT,
CTL_EVENT_WAIT_ALL_EVENTS_WITH_AUTO_CLEAR = CTL_STATE_EVENT_WAIT | CTL_STATE_EVENT_AUTO_CLEAR
}
CTL_EVENT_WAIT_TYPE_t;
// Wait on the specified events in the event set and do scheduling.
// Returns the eventSet prior to auto clearing, 0 on timeout.
unsigned ctl_events_wait(CTL_EVENT_WAIT_TYPE_t type,
CTL_EVENT_SET_t *eventSet,
CTL_EVENT_SET_t events,
CTL_TIMEOUT_t t,
CTL_TIME_t timeout);
//
// Semaphore support
//
// Semaphore's are word sized - 16 or 32 depending on the machine.
typedef unsigned CTL_SEMAPHORE_t;
// Initialise a semaphore
void ctl_semaphore_init(CTL_SEMAPHORE_t *s,
unsigned value);
// Signal a semaphore and do scheduling.
void ctl_semaphore_signal(CTL_SEMAPHORE_t *s);
// Wait on a semaphore and do scheduling.
// Return 1 on success, 0 on timeout
unsigned ctl_semaphore_wait(CTL_SEMAPHORE_t *s,
CTL_TIMEOUT_t t,
CTL_TIME_t timeout);
//
// Message queue support.
//
typedef struct {
void **q; // pointer to array of objects
unsigned s; // size of array q;
unsigned front; // the next element to leave the q
unsigned n; // the number of elements in the q
} CTL_MESSAGE_QUEUE_t;
// Initialise a message queue structure.
void ctl_message_queue_init(CTL_MESSAGE_QUEUE_t *m, // message queue pointer
void **queue, // pointer to the queue
unsigned queue_size); // the number of elements in the queue
// Post a message to a message queue and do scheduling.
// Return 1 on success, 0 on timeout.
unsigned ctl_message_queue_post(CTL_MESSAGE_QUEUE_t *m, // message queue pointer
void *message, // the message to post
CTL_TIMEOUT_t t, // type of timeout
CTL_TIME_t timeout); // timeout
// Post a message to a message queue and do scheduling.
// Return 1 on success, 0 if message queue is full.
unsigned ctl_message_queue_post_nb(CTL_MESSAGE_QUEUE_t *m, // message queue pointer
void *message); // the message to post
// Receive a message from a message queue and do scheduling.
// Return 1 on success, 0 on timeout.
unsigned ctl_message_queue_receive(CTL_MESSAGE_QUEUE_t *m, // message queue pointer
void **message, // pointer to message receiver
CTL_TIMEOUT_t t, // type of timeout
CTL_TIME_t timeout); // timeout
// Receive a message from a message queue and do scheduling.
// Return 1 on success, 0 if message queue is empty
unsigned ctl_message_queue_receive_nb(CTL_MESSAGE_QUEUE_t *m, // message queue pointer
void **message); // pointer to message receiver
//
// Byte queue support - same as message queue but specialised for bytes
//
typedef struct {
unsigned char *q; // pointer to array of objects
unsigned s; // size of array q;
unsigned front; // the next element to leave the q
unsigned n; // the number of elements in the q
} CTL_BYTE_QUEUE_t;
// Initialise a byte queue structure.
void ctl_byte_queue_init(CTL_BYTE_QUEUE_t *m, // byte queue pointer
unsigned char *queue, // pointer to the queue
unsigned queue_size); // the number of bytes in the queue
// Post a message to a byte queue and do scheduling.
// Return 1 on success, 0 on timeout.
unsigned ctl_byte_queue_post(CTL_BYTE_QUEUE_t *m, // byte queue pointer
unsigned char b, // the byte to post
CTL_TIMEOUT_t t, // type of timeout
CTL_TIME_t timeout); // timeout
// Post a byte to a byte queue and do scheduling.
// Return 1 on success, 0 if byte queue is full.
unsigned ctl_byte_queue_post_nb(CTL_BYTE_QUEUE_t *m, // byte queue pointer
unsigned char b); // the byte to post
// Receive a message from a byte queue and do scheduling.
// Return 1 on success, 0 on timeout.
unsigned ctl_byte_queue_receive(CTL_BYTE_QUEUE_t *m, // byte queue pointer
unsigned char *b, // pointer to byte receiver
CTL_TIMEOUT_t t, // type of timeout
CTL_TIME_t timeout); // timeout
// Receive a message from a byte queue and do scheduling.
// Return 1 on success, 0 if byte queue is empty
unsigned ctl_byte_queue_receive_nb(CTL_BYTE_QUEUE_t *m, // byte queue pointer
unsigned char *b); // pointer to byte receiver
//
// Global interrupts support
//
// Set global interrupt enables (1 enabled, 0 disabled).
// Returns the previous global interrupt enables state.
int ctl_global_interrupts_set(int enabled);
#define ctl_global_interrupts_disable() ctl_global_interrupts_set(0)
#define ctl_global_interrupts_enable() ctl_global_interrupts_set(1)
// 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_global_interrupts_un_re_enable_from_isr before the ISR exits.
void ctl_global_interrupts_re_enable_from_isr(void);
// Disable interrupts from within an ISR.
void ctl_global_interrupts_un_re_enable_from_isr(void);
// 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);
//
// Programmable interrupt controller support
//
// 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;
// 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);
//
// Error handling
//
typedef enum
{
CTL_ERROR_NO_TASKS_TO_RUN,
CTL_UNSUPPORTED_CALL_FROM_ISR,
CTL_UNSPECIFIED_ERROR
}
CTL_ERROR_CODE_t;
// This function is called if something goes wrong with your application.
// You must supply this function
void ctl_handle_error(CTL_ERROR_CODE_t);
//
// Memory area support
//
typedef unsigned *CTL_MEMORY_AREA_t;
// Initialise a memory area
void ctl_memory_area_init(CTL_MEMORY_AREA_t *memory_area, // pointer to the memory area
unsigned *memory, // should be block_size_in_words * num_blocks in length
unsigned block_size_in_words, // size of the memory block in words
unsigned num_blocks); // the number of blocks
// Allocate a free memory block
// Returns the block or 0
unsigned *ctl_memory_area_allocate(CTL_MEMORY_AREA_t *memory_area);
// Return a memory block
void ctl_memory_area_free(CTL_MEMORY_AREA_t *memory_area,
unsigned *block);
//
// 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 char 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
extern CTL_TIME_t ctl_timeslice_period; // time slice period or zero for no timeslicing
// 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;
//
// Board specific functions
//
// Initialise the board
void ctl_board_init(void);
// Set/Clear the leds on the board
void ctl_board_set_leds(unsigned set);
// Set a function to be called when a button is pressed
void ctl_board_on_button_pressed(CTL_ISR_FN_t buttonFn);
#ifdef __cplusplus
}
#endif
#endif