// 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 = 0x30 // 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