#ifndef _xmk_kernel_h_ #define _xmk_kernel_h_ /*---------------------------------------------------------------------------- ** SUMMARY: XMK Basic Kernel/Thead Interfaces (KRN) ** ** DESCRIPTION: ** This file provides the interface for the most basic kernel/threading ** operations. These methods represent the functionality of the smallest/ ** mimimal kernel implementation. ** ** SCHEDULING ** ---------- ** The default scheduler is simple, small and maps thread priorites to thread ** handles. The alternate scheduler is enable by using the switch ** USE_XMK_SCHPRI_SCHEDULER. This scheduler, known as the Priority Scheduler, ** allows multiple threads to have the same priority. ** ** INTERRUPTS ** ---------- ** There are two issues with respect to interrupts: one, multiplexing and/or ** nesting interrupts; and two, MCUs that support multiple priority levels ** with respect to enabling/disabling interrupts. XMK provides support for ** nested interrupts, but does not support multiple priority levels. If your ** application uses nesting interrupts (i.e. enabling interrupts while in an ** interrupt-service-routine), then XMK must be configured with the switch: ** USE_XMK_NESTED_INTERRUPTS. Note: while XMK does not support multiple ** priority levels, XMK can still be ported/run on a platform that has ** multiple levels as long the application always enables-all-interrupts ** and/or disables-all-interrupts. ** ** WAIT TIMEOUTS ** ------------- ** The default/standard interface for the wait() interface (thread-semaphore) ** does not have a timeout period associated with it. If the timeout ** functionality is needed, use the USE_XMK_WAIT_WITH_TIMEOUT configuration ** option. NOTE: The timeout feature has a noticeable larger ROM/RAM ** footprint as well as more CPU/Run-time overhead than the standard wait() ** interface. ** ** ** CONFIGURATION OPTION: USE_XMK_CORE_KERNEL ** ** OPTIONAL OPTIONS: USE_XMK_WAIT_WITH_TIMEOUT ** USE_XMK_SCHPRI_SCHEDULER ** USE_XMK_NESTED_INTERRUPTS ** ** DEPENDENCIES: ** To use this interface the following XMK service(s) MUST always be ** enabled/configured: ** USE_XMK_THREAD_xSLEEP (ONLY when using USE_XMK_WAIT_WITH_TIMEOUT) ** ** ** APPLICATION REQUIREMENTS: ** The application must provide definitions for the following symbols ** in its xmkcfg.h header file: ** PRJ_XMK_NTHREADS - Maximum number of threads that can be ** running at any on time. This ** symbol must always be defined. ** PRJ_XMK_MAX_PRIORITY_LEVELS - This is the total number of ** DIFFIRENT priorities that the ** application will be using (i.e. ** number of unique priorites). ** NOTE: This symbol ONLY needs to be ** defined if using the service: ** USE_XMK_SCHPRI_SCHEDULER ** ** NOTES: ** 1. For efficency/optimization some methods are 'inlined'. The inlining ** is done by using the preprocessor/macros. The application should ** treat all methods as function calls and not rely on the fact they may ** be currently defined as a macro. ** ----------------------------------------------------------------------------*/ #include "xmkcfg.h" /* For: Project/Application kernel configuraiton */ #ifdef __cplusplus extern "C" { #endif /*-------------- MAGIC CONSTANTS -------------------------------------------*/ /** The following are intial states to be used when initializing threads. */ #define XMK_THREADSTATE_WAITING _XMK_THREADSTATE_WAITING #define XMK_THREADSTATE_READY _XMK_THREADSTATE_READY #define XMK_THREADSTATE_READY_SIGNALED _XMK_THREADSTATE_READY_SIGNALED /** Higheset Priority usable by the application */ #define XMK_HIGHEST_PRIORITY _XMK_HIGHEST_PRIORITY /** Lowest Priority usable by the application. */ #define XMK_LOWEST_PRIORITY _XMK_LOWEST_PRIORITY /** NULL Thread Handle */ #define XMK_NULL_THREADHDL _XMK_NULL_THREADHDL /** Infinite timeout period (aka no timeout) */ #define XMK_WAIT_NO_TIMEOUT _XMK_WAIT_NO_TIMEOUT /** Start of Application Fatal Error Codes */ #define XMK_ERRFATAL_START_OF_APPERRORS _XMK_ERRFATAL_START_OF_APPERRORS /* ** ERROR CODES */ /** Undiagnosed Kernel error. This is the catch-all bucket for error. This error code is used when, for whatever reason, a specific error is "not available". Obviously, there is at least one scenerio or this error code would not exists (I know it's a Hack). */ #define XMK_ERRFATAL_UNDIAGNOSED _XMK_ERRFATAL_UNDIAGNOSED /*-------------- MACROS ----------------------------------------------------*/ /** This macro calculates the address of the 'top-of-the-stack'. It takes a pointer to the starting address and size of the block of memory pre-allocated for the stack. It is highly recommended that this macro be used instead of 'manually' calculating the top-of-the-stack, since it adapts to the project's platform and if the stack uses a pre or post decrement paradigm. */ #define XMK_TOP_OF_STACK(startingAddressOfBlock,sizeOfBlock) _XMK_TOP_OF_STACK(startingAddressOfBlock,sizeOfBlock) /*-------------- PUBLIC/PUBLISHED API --------------------------------------*/ /** This method initializes the kernel prior to any kernel calls being made. NOTES: o This method must be called before any/all other Xmk_xx() calls. o This method can only be called once. o Interrupts are disabled when this method is called AND stay disabled until Xmk_start() is called. o The C/C++ start-up code has been run and all uninitialized static/global variables (BSS segment) have been set to zero as per the C/C++ standard. Prototype: void Xmk_initialize(void); */ #define Xmk_initialize() _Xmk_initialize() /** This method creates a thread. The thread's entry method will not be run until 1) Xmk_start() has been called AND 2) the thread is the 'ready' state. The method returns the handle of the newly created thread.
DETAILS:
--------
Call Restrictions:
This method can ONLY be called BEFORE Xmk_start() and it can never be
called from an interrupt service routine.
Priority:
Priorities range from 0 to N-1 where N is the number of threads and/or
priorities levels. Zero is the highest priority, N-1 is the lowest.
When using the basic scheduler, a thread's priority is also the
thread's handle.
Entry Function:
The entry function must have the following function signature:
void myEntryFunction(void* args);
Thread Arguments:
Data and/or parameter(s) can be passed to a thread when it is
created through the 'args' function argument. 'Args' is a
pointer to 'something', which is defined by the application.
If no thread parameters are needed, set 'args' to zero.
Stack memory:
What does 'top-of-the-stack-memory' mean? Top-of-Stack means a
pointer to the last element pushed. When creating a thread, the
application must supply a pointer to the top of the block of memory to
be used as thread's stack - this usually means a pointer to end of the
block memory reserved for the stack. It is recommended that you
use the XMK_TOP_OF_STACK() macro when specifing the topOfStackMemory
parameter.
Initial states:
READY - The thread will run once the kernel has been
started AND it is the highest priority thread
ready to run.
READY/SIGNALED - The same as READY except that the FIRST time
the thread calls Xmk_wait(), the thread will
NOT block.
WAITING - The thread will run once the kernel has been
started AND it is externally signaled.
Maximum Number of Threads
The maximum number of threads that can be created is limited by two
parameters. One, the amount of RAM the application is willing to
allocate for threads (i.e. the PRJ_XMK_NTHREADS configuration
parameter). And two, the size of the XMK_THREADHDL data type.
Assuming infinite RAM, then the maximum number of threads is limited
to: (2^n)-2, where n is the number of bits in the XMK_THREADHDL data
type. For example:
If XMK_THREADHDL is defined as an unsigned char, then maximum
number of threads would be: (2^8)-2 = 254.
Prototype:
XMK_THREADHDL Xmk_createThread
(
XMK_THREADPRIORITY priority,
XMK_ENTRYFUNC start,
void* args,
void* topOfStackMemory,
XMK_BYTE initialState
);
*/
#define Xmk_createThread(p,f,a,m,i) _Xmk_createThread(p,f,a,m,i)
/** This method is used to pass the thead-of-control to the kernel/scheduler
and begin multi-threading. Starting the kernel enables interrupts.
The application is responsible for suppling the stack memory used for
all interrupt processing.
NOTES:
o Use the XMK_TOP_OF_STACK() macro when specificing the
topOfIsrStackMemory parameter.
o This method nevers returns.
o The boot-up stack (i.e. the stack of the caller) is used
for the Idle thread.
Prototype:
void Xmk_start(void* topOfIsrStackMemory);
*/
#define Xmk_start(m) _Xmk_start(m)
/** This method returns non-zero (true) if the kernel is running, i.e.
Xmk_start() has been called. This method can be called any time,
including before Xmk_initialize().
NOTES:
o This method can not be called from interrupt service
routine. It also makes no sense to call this method
from an ISR, since by definition interrupts are only
enabled AFTER the kernel has been started.
Prototype:
XMK_BOOL Xmk_isKernelRunning(void);
*/
#define Xmk_isKernelRunning() _Xmk_isKernelRunning()
/** This method causes the current thread to yield control of the CPU and
wait till the thread is signaled.
NOTES:
o This method can ONLY be called from a thread context.
Prototype:
void Xmk_wait(void);
*/
#define Xmk_wait() _Xmk_wait()
/** This method is the same as Xmk_wait(), except the method will timeout
and/or return after the specified time interval if the thread was
not signaled. The method normally returns non-zero (true). It only
returns 0 (false) if the thread 'waited' on the thread-semaphore and
the timeout period expired before the thread was signaled.
NOTES:
o This method is ONLY available if the configuration option
USE_XMK_WAIT_WITH_TIMEOUT is used.
o This method can ONLY be called from a thread context.
o If XMK_WAIT_NO_TIMEOUT is specified as the timeout period,
the method behaves exactly the same as Xmk_wait(), i.e. nevers
times-out.
o The longest timeout period is XMK_SLEEP_MAX_DELAY-1 sleep ticks.
o If 0 is specified as the timout period, then the call acts
as a 'polled' operation on the thread-semaphore in that it will
never block even if the thread-semaphore is not currently signaled
when called.
o CAUTION: Do not assume that since the method returned false due to
a time-out, that the thread-semaphore is not signaled (i.e. its
count is zero). It is possible that the thread is/was signaled
after the 'time-out', BUT before the application has an opportunity
to check the return code.
Prototype:
XMK_BOOL Xmk_waitTimeout( XMK_SLEEPTICKS maxwait )
*/
#define Xmk_waitTimeout(t) _Xmk_waitTimeout(t)
/** This method causes the signaled thread to become unblocked and/or ready
to run. Note: This method can NOT be called from an interrupt service
routine.
Prototype:
void Xmk_signal( XMK_THREADHDL threadToSignal );
*/
#define Xmk_signal(t) _Xmk_signal(t)
/** This method is same as Xmk_signal(), except that it can ONLY be called
from the context of an interrupt service routine.
Prototype:
void Xmk_isr_signal( XMK_THREADHDL threadToSignal );
*/
#define Xmk_isr_signal(t) _Xmk_isr_signal(t)
/** This method returns the handle of the currently running thread. If
called from an interrupt service routine, then it returns the handle
of the thread that was running when the interrupt occurred (which is
not necessarily the thread that will be running on exit from the ISR).
Prototype:
XMK_THREADHDL Xmk_getCurrentThread(void);
*/
#define Xmk_getCurrentThread() _Xmk_getCurrentThread()
/** This method returns the priority of the specified thread.
NOTE: If XMK is configured for dynamic threads, beware of stale
thread handles. If using dynamic threads you should
use Xmk_getThreadInfo() to get a thread's priority.
Prototype:
XMK_THREADPRIORITY Xmk_getThreadPriority( XMK_THREADHDL thread );
*/
#define Xmk_getThreadPriority(t) _Xmk_getThreadPriority(t)
/*-------------- PUBLIC/PUBLISHED API --------------------------------------*/
/** This method disables interrupts. This method can be called from a thread
context as well as an interrupt service routine.
NOTES:
o BE VERY CAREFUL when using disable/enable interrupts as a form
of mutual exclusion. Most XMK methods require that interrupts are
enabled when called. One of the reasons for this restriction is
that calling a XMK method can lead to a context switch EVEN
if interrupts are disabled. When a context switch occurs,
interrupts will be enabled when the new/next thread is run. This
behavior prevents the use of disable/enable interrupts as a
form of MX when the code it is attempting to protect, makes a
XMK system call.
Prototype:
void Xmk_disableInts(void);
*/
#define Xmk_disableInts() _Xmk_disableInts()
/** This method enables interrupts. This method can be called from a thread
context as well as an interrupt service routine.
Prototype:
void Xmk_enableInts(void);
*/
#define Xmk_enableInts() _Xmk_enableInts()
/** This method returns non-zero (true) if interrupts are currently
enabled. This method can be called from a thread context as well as
an interrupt service routine.
Prototype:
XMK_BOOL Xmk_areInterruptsEnabled(void);
*/
#define Xmk_areInterruptsEnabled() _Xmk_areInterruptsEnabled()
/*-------------- PUBLIC/PUBLISHED API --------------------------------------*/
/** This method is used to report/handle fatal errors that are detected by
the kernel. This is a callback into the application since ONLY it has
the knowledge on what to do with errors.
The application is allowed to call this method. The application can also
define its own error codes starting with XMK_ERRFATAL_START_OF_APPERRORS.
The default implementation, which can be overridden by the application,
just locks up the CPU and if the system has a watch-dog operating, it will
eventually cause a reboot.
NOTE: The semantics of this method is that it NEVER returns!
Prototype:
void Xmk_fatalError(XMK_BYTE errorCode);
*/
#define Xmk_fatalError(e) _Xmk_fatalError(e)
#ifdef __cplusplus
}
#endif
/*--------------------------------------------------------------------------*/
#endif /* end _xmk_kernel_h_ */