+
+/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
+all the API functions to use the MPU wrappers. That should only be done when
+task.h is included from an application file. */
+#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
+
+#include "FreeRTOS.h"
+#include "task.h"
+#include "croutine.h"
+
+#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
+
+/*-----------------------------------------------------------
+ * PUBLIC LIST API documented in list.h
+ *----------------------------------------------------------*/
+
+/* Constants used with the cRxLock and cTxLock structure members. */
+#define queueUNLOCKED ( ( signed portBASE_TYPE ) -1 )
+#define queueLOCKED_UNMODIFIED ( ( signed portBASE_TYPE ) 0 )
+
+#define queueERRONEOUS_UNBLOCK ( -1 )
+
+/* For internal use only. */
+#define queueSEND_TO_BACK ( 0 )
+#define queueSEND_TO_FRONT ( 1 )
+
+/* Effectively make a union out of the xQUEUE structure. */
+#define pxMutexHolder pcTail
+#define uxQueueType pcHead
+#define uxRecursiveCallCount pcReadFrom
+#define queueQUEUE_IS_MUTEX NULL
+
+/* Semaphores do not actually store or copy data, so have an items size of
+zero. */
+#define queueSEMAPHORE_QUEUE_ITEM_LENGTH ( 0 )
+#define queueDONT_BLOCK ( ( portTickType ) 0 )
+#define queueMUTEX_GIVE_BLOCK_TIME ( ( portTickType ) 0 )
+
+/*
+ * Definition of the queue used by the scheduler.
+ * Items are queued by copy, not reference.
+ */
+typedef struct QueueDefinition
+{
+ signed char *pcHead; /*< Points to the beginning of the queue storage area. */
+ signed char *pcTail; /*< Points to the byte at the end of the queue storage area. Once more byte is allocated than necessary to store the queue items, this is used as a marker. */
+
+ signed char *pcWriteTo; /*< Points to the free next place in the storage area. */
+ signed char *pcReadFrom; /*< Points to the last place that a queued item was read from. */
+
+ xList xTasksWaitingToSend; /*< List of tasks that are blocked waiting to post onto this queue. Stored in priority order. */
+ xList xTasksWaitingToReceive; /*< List of tasks that are blocked waiting to read from this queue. Stored in priority order. */
+
+ volatile unsigned portBASE_TYPE uxMessagesWaiting;/*< The number of items currently in the queue. */
+ unsigned portBASE_TYPE uxLength; /*< The length of the queue defined as the number of items it will hold, not the number of bytes. */
+ unsigned portBASE_TYPE uxItemSize; /*< The size of each items that the queue will hold. */
+
+ signed portBASE_TYPE xRxLock; /*< Stores the number of items received from the queue (removed from the queue) while the queue was locked. Set to queueUNLOCKED when the queue is not locked. */
+ signed portBASE_TYPE xTxLock; /*< Stores the number of items transmitted to the queue (added to the queue) while the queue was locked. Set to queueUNLOCKED when the queue is not locked. */
+
+} xQUEUE;
+/*-----------------------------------------------------------*/
+
+/*
+ * Inside this file xQueueHandle is a pointer to a xQUEUE structure.
+ * To keep the definition private the API header file defines it as a
+ * pointer to void.
+ */
+typedef xQUEUE * xQueueHandle;
+
+/*
+ * Prototypes for public functions are included here so we don't have to
+ * include the API header file (as it defines xQueueHandle differently). These
+ * functions are documented in the API header file.
+ */
+xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize ) PRIVILEGED_FUNCTION;
+signed portBASE_TYPE xQueueGenericSend( xQueueHandle xQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition ) PRIVILEGED_FUNCTION;
+unsigned portBASE_TYPE uxQueueMessagesWaiting( const xQueueHandle pxQueue ) PRIVILEGED_FUNCTION;
+void vQueueDelete( xQueueHandle xQueue ) PRIVILEGED_FUNCTION;
+signed portBASE_TYPE xQueueGenericSendFromISR( xQueueHandle pxQueue, const void * const pvItemToQueue, signed portBASE_TYPE *pxHigherPriorityTaskWoken, portBASE_TYPE xCopyPosition ) PRIVILEGED_FUNCTION;
+signed portBASE_TYPE xQueueGenericReceive( xQueueHandle pxQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking ) PRIVILEGED_FUNCTION;
+signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, void * const pvBuffer, signed portBASE_TYPE *pxTaskWoken ) PRIVILEGED_FUNCTION;
+xQueueHandle xQueueCreateMutex( void ) PRIVILEGED_FUNCTION;
+xQueueHandle xQueueCreateCountingSemaphore( unsigned portBASE_TYPE uxCountValue, unsigned portBASE_TYPE uxInitialCount ) PRIVILEGED_FUNCTION;
+portBASE_TYPE xQueueTakeMutexRecursive( xQueueHandle xMutex, portTickType xBlockTime ) PRIVILEGED_FUNCTION;
+portBASE_TYPE xQueueGiveMutexRecursive( xQueueHandle xMutex ) PRIVILEGED_FUNCTION;
+signed portBASE_TYPE xQueueAltGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition ) PRIVILEGED_FUNCTION;
+signed portBASE_TYPE xQueueAltGenericReceive( xQueueHandle pxQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking ) PRIVILEGED_FUNCTION;
+signed portBASE_TYPE xQueueIsQueueEmptyFromISR( const xQueueHandle pxQueue ) PRIVILEGED_FUNCTION;
+signed portBASE_TYPE xQueueIsQueueFullFromISR( const xQueueHandle pxQueue ) PRIVILEGED_FUNCTION;
+unsigned portBASE_TYPE uxQueueMessagesWaitingFromISR( const xQueueHandle pxQueue ) PRIVILEGED_FUNCTION;
+void vQueueWaitForMessageRestricted( xQueueHandle pxQueue, portTickType xTicksToWait ) PRIVILEGED_FUNCTION;
+
+/*
+ * Co-routine queue functions differ from task queue functions. Co-routines are
+ * an optional component.
+ */
+#if configUSE_CO_ROUTINES == 1
+ signed portBASE_TYPE xQueueCRSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xCoRoutinePreviouslyWoken ) PRIVILEGED_FUNCTION;
+ signed portBASE_TYPE xQueueCRReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxTaskWoken ) PRIVILEGED_FUNCTION;
+ signed portBASE_TYPE xQueueCRSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait ) PRIVILEGED_FUNCTION;
+ signed portBASE_TYPE xQueueCRReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait ) PRIVILEGED_FUNCTION;
+#endif
+
+/*
+ * The queue registry is just a means for kernel aware debuggers to locate
+ * queue structures. It has no other purpose so is an optional component.
+ */
+#if configQUEUE_REGISTRY_SIZE > 0
+
+ /* The type stored within the queue registry array. This allows a name
+ to be assigned to each queue making kernel aware debugging a little
+ more user friendly. */
+ typedef struct QUEUE_REGISTRY_ITEM
+ {
+ signed char *pcQueueName;
+ xQueueHandle xHandle;
+ } xQueueRegistryItem;
+
+ /* The queue registry is simply an array of xQueueRegistryItem structures.
+ The pcQueueName member of a structure being NULL is indicative of the
+ array position being vacant. */
+ xQueueRegistryItem xQueueRegistry[ configQUEUE_REGISTRY_SIZE ];
+
+ /* Removes a queue from the registry by simply setting the pcQueueName
+ member to NULL. */
+ static void vQueueUnregisterQueue( xQueueHandle xQueue ) PRIVILEGED_FUNCTION;
+ void vQueueAddToRegistry( xQueueHandle xQueue, signed char *pcQueueName ) PRIVILEGED_FUNCTION;
+#endif
+
+/*
+ * Unlocks a queue locked by a call to prvLockQueue. Locking a queue does not
+ * prevent an ISR from adding or removing items to the queue, but does prevent
+ * an ISR from removing tasks from the queue event lists. If an ISR finds a
+ * queue is locked it will instead increment the appropriate queue lock count
+ * to indicate that a task may require unblocking. When the queue in unlocked
+ * these lock counts are inspected, and the appropriate action taken.
+ */
+static void prvUnlockQueue( xQueueHandle pxQueue ) PRIVILEGED_FUNCTION;
+
+/*
+ * Uses a critical section to determine if there is any data in a queue.
+ *
+ * @return pdTRUE if the queue contains no items, otherwise pdFALSE.
+ */
+static signed portBASE_TYPE prvIsQueueEmpty( const xQueueHandle pxQueue ) PRIVILEGED_FUNCTION;
+
+/*
+ * Uses a critical section to determine if there is any space in a queue.
+ *
+ * @return pdTRUE if there is no space, otherwise pdFALSE;
+ */
+static signed portBASE_TYPE prvIsQueueFull( const xQueueHandle pxQueue ) PRIVILEGED_FUNCTION;
+
+/*
+ * Copies an item into the queue, either at the front of the queue or the
+ * back of the queue.
+ */
+static void prvCopyDataToQueue( xQUEUE *pxQueue, const void *pvItemToQueue, portBASE_TYPE xPosition ) PRIVILEGED_FUNCTION;
+
+/*
+ * Copies an item out of a queue.
+ */
+static void prvCopyDataFromQueue( xQUEUE * const pxQueue, const void *pvBuffer ) PRIVILEGED_FUNCTION;
+/*-----------------------------------------------------------*/
+
+/*
+ * Macro to mark a queue as locked. Locking a queue prevents an ISR from
+ * accessing the queue event lists.
+ */
+#define prvLockQueue( pxQueue ) \
+ taskENTER_CRITICAL(); \
+ { \
+ if( ( pxQueue )->xRxLock == queueUNLOCKED ) \
+ { \
+ ( pxQueue )->xRxLock = queueLOCKED_UNMODIFIED; \
+ } \
+ if( ( pxQueue )->xTxLock == queueUNLOCKED ) \
+ { \
+ ( pxQueue )->xTxLock = queueLOCKED_UNMODIFIED; \
+ } \
+ } \
+ taskEXIT_CRITICAL()
+/*-----------------------------------------------------------*/
+
+
+/*-----------------------------------------------------------
+ * PUBLIC QUEUE MANAGEMENT API documented in queue.h
+ *----------------------------------------------------------*/
+
+xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize )
+{
+xQUEUE *pxNewQueue;
+size_t xQueueSizeInBytes;
+xQueueHandle xReturn = NULL;
+
+ /* Allocate the new queue structure. */
+ if( uxQueueLength > ( unsigned portBASE_TYPE ) 0 )
+ {
+ pxNewQueue = ( xQUEUE * ) pvPortMalloc( sizeof( xQUEUE ) );
+ if( pxNewQueue != NULL )
+ {
+ /* Create the list of pointers to queue items. The queue is one byte
+ longer than asked for to make wrap checking easier/faster. */
+ xQueueSizeInBytes = ( size_t ) ( uxQueueLength * uxItemSize ) + ( size_t ) 1;
+
+ pxNewQueue->pcHead = ( signed char * ) pvPortMalloc( xQueueSizeInBytes );
+ if( pxNewQueue->pcHead != NULL )
+ {
+ /* Initialise the queue members as described above where the
+ queue type is defined. */
+ pxNewQueue->pcTail = pxNewQueue->pcHead + ( uxQueueLength * uxItemSize );
+ pxNewQueue->uxMessagesWaiting = ( unsigned portBASE_TYPE ) 0U;
+ pxNewQueue->pcWriteTo = pxNewQueue->pcHead;
+ pxNewQueue->pcReadFrom = pxNewQueue->pcHead + ( ( uxQueueLength - ( unsigned portBASE_TYPE ) 1U ) * uxItemSize );
+ pxNewQueue->uxLength = uxQueueLength;
+ pxNewQueue->uxItemSize = uxItemSize;
+ pxNewQueue->xRxLock = queueUNLOCKED;
+ pxNewQueue->xTxLock = queueUNLOCKED;
+
+ /* Likewise ensure the event queues start with the correct state. */
+ vListInitialise( &( pxNewQueue->xTasksWaitingToSend ) );
+ vListInitialise( &( pxNewQueue->xTasksWaitingToReceive ) );
+
+ traceQUEUE_CREATE( pxNewQueue );
+ xReturn = pxNewQueue;
+ }
+ else
+ {
+ traceQUEUE_CREATE_FAILED();
+ vPortFree( pxNewQueue );
+ }
+ }
+ }
+
+ configASSERT( xReturn );
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+#if ( configUSE_MUTEXES == 1 )
+
+ xQueueHandle xQueueCreateMutex( void )
+ {
+ xQUEUE *pxNewQueue;
+
+ /* Allocate the new queue structure. */
+ pxNewQueue = ( xQUEUE * ) pvPortMalloc( sizeof( xQUEUE ) );
+ if( pxNewQueue != NULL )
+ {
+ /* Information required for priority inheritance. */
+ pxNewQueue->pxMutexHolder = NULL;
+ pxNewQueue->uxQueueType = queueQUEUE_IS_MUTEX;
+
+ /* Queues used as a mutex no data is actually copied into or out
+ of the queue. */
+ pxNewQueue->pcWriteTo = NULL;
+ pxNewQueue->pcReadFrom = NULL;
+
+ /* Each mutex has a length of 1 (like a binary semaphore) and
+ an item size of 0 as nothing is actually copied into or out
+ of the mutex. */
+ pxNewQueue->uxMessagesWaiting = ( unsigned portBASE_TYPE ) 0U;
+ pxNewQueue->uxLength = ( unsigned portBASE_TYPE ) 1U;
+ pxNewQueue->uxItemSize = ( unsigned portBASE_TYPE ) 0U;
+ pxNewQueue->xRxLock = queueUNLOCKED;
+ pxNewQueue->xTxLock = queueUNLOCKED;
+
+ /* Ensure the event queues start with the correct state. */
+ vListInitialise( &( pxNewQueue->xTasksWaitingToSend ) );
+ vListInitialise( &( pxNewQueue->xTasksWaitingToReceive ) );
+
+ /* Start with the semaphore in the expected state. */
+ xQueueGenericSend( pxNewQueue, NULL, ( portTickType ) 0U, queueSEND_TO_BACK );
+
+ traceCREATE_MUTEX( pxNewQueue );
+ }
+ else
+ {
+ traceCREATE_MUTEX_FAILED();
+ }
+
+ configASSERT( pxNewQueue );
+ return pxNewQueue;
+ }
+
+#endif /* configUSE_MUTEXES */
+/*-----------------------------------------------------------*/
+
+#if configUSE_RECURSIVE_MUTEXES == 1
+
+ portBASE_TYPE xQueueGiveMutexRecursive( xQueueHandle pxMutex )
+ {
+ portBASE_TYPE xReturn;
+
+ configASSERT( pxMutex );
+
+ /* If this is the task that holds the mutex then pxMutexHolder will not
+ change outside of this task. If this task does not hold the mutex then
+ pxMutexHolder can never coincidentally equal the tasks handle, and as
+ this is the only condition we are interested in it does not matter if
+ pxMutexHolder is accessed simultaneously by another task. Therefore no
+ mutual exclusion is required to test the pxMutexHolder variable. */
+ if( pxMutex->pxMutexHolder == xTaskGetCurrentTaskHandle() )
+ {
+ traceGIVE_MUTEX_RECURSIVE( pxMutex );
+
+ /* uxRecursiveCallCount cannot be zero if pxMutexHolder is equal to
+ the task handle, therefore no underflow check is required. Also,
+ uxRecursiveCallCount is only modified by the mutex holder, and as
+ there can only be one, no mutual exclusion is required to modify the
+ uxRecursiveCallCount member. */
+ ( pxMutex->uxRecursiveCallCount )--;
+
+ /* Have we unwound the call count? */
+ if( pxMutex->uxRecursiveCallCount == 0 )
+ {
+ /* Return the mutex. This will automatically unblock any other
+ task that might be waiting to access the mutex. */
+ xQueueGenericSend( pxMutex, NULL, queueMUTEX_GIVE_BLOCK_TIME, queueSEND_TO_BACK );
+ }
+
+ xReturn = pdPASS;
+ }
+ else
+ {
+ /* We cannot give the mutex because we are not the holder. */
+ xReturn = pdFAIL;
+
+ traceGIVE_MUTEX_RECURSIVE_FAILED( pxMutex );
+ }
+
+ return xReturn;
+ }
+
+#endif /* configUSE_RECURSIVE_MUTEXES */
+/*-----------------------------------------------------------*/
+
+#if configUSE_RECURSIVE_MUTEXES == 1
+
+ portBASE_TYPE xQueueTakeMutexRecursive( xQueueHandle pxMutex, portTickType xBlockTime )
+ {
+ portBASE_TYPE xReturn;
+
+ configASSERT( pxMutex );
+
+ /* Comments regarding mutual exclusion as per those within
+ xQueueGiveMutexRecursive(). */
+
+ traceTAKE_MUTEX_RECURSIVE( pxMutex );
+
+ if( pxMutex->pxMutexHolder == xTaskGetCurrentTaskHandle() )
+ {
+ ( pxMutex->uxRecursiveCallCount )++;
+ xReturn = pdPASS;
+ }
+ else
+ {
+ xReturn = xQueueGenericReceive( pxMutex, NULL, xBlockTime, pdFALSE );
+
+ /* pdPASS will only be returned if we successfully obtained the mutex,
+ we may have blocked to reach here. */
+ if( xReturn == pdPASS )
+ {
+ ( pxMutex->uxRecursiveCallCount )++;
+ }
+ else
+ {
+ traceTAKE_MUTEX_RECURSIVE_FAILED( pxMutex );
+ }
+ }
+
+ return xReturn;
+ }
+
+#endif /* configUSE_RECURSIVE_MUTEXES */
+/*-----------------------------------------------------------*/
+
+#if configUSE_COUNTING_SEMAPHORES == 1
+
+ xQueueHandle xQueueCreateCountingSemaphore( unsigned portBASE_TYPE uxCountValue, unsigned portBASE_TYPE uxInitialCount )
+ {
+ xQueueHandle pxHandle;
+
+ pxHandle = xQueueCreate( ( unsigned portBASE_TYPE ) uxCountValue, queueSEMAPHORE_QUEUE_ITEM_LENGTH );
+
+ if( pxHandle != NULL )
+ {
+ pxHandle->uxMessagesWaiting = uxInitialCount;
+
+ traceCREATE_COUNTING_SEMAPHORE();
+ }
+ else
+ {
+ traceCREATE_COUNTING_SEMAPHORE_FAILED();
+ }
+
+ configASSERT( pxHandle );
+ return pxHandle;
+ }
+
+#endif /* configUSE_COUNTING_SEMAPHORES */
+/*-----------------------------------------------------------*/
+
+signed portBASE_TYPE xQueueGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition )
+{
+signed portBASE_TYPE xEntryTimeSet = pdFALSE;
+xTimeOutType xTimeOut;
+
+ configASSERT( pxQueue );
+ configASSERT( !( ( pvItemToQueue == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) );
+
+ /* This function relaxes the coding standard somewhat to allow return
+ statements within the function itself. This is done in the interest
+ of execution time efficiency. */
+ for( ;; )
+ {
+ taskENTER_CRITICAL();
+ {
+ /* Is there room on the queue now? To be running we must be
+ the highest priority task wanting to access the queue. */
+ if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
+ {
+ traceQUEUE_SEND( pxQueue );
+ prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );
+
+ /* If there was a task waiting for data to arrive on the
+ queue then unblock it now. */
+ if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
+ {
+ if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) == pdTRUE )
+ {
+ /* The unblocked task has a priority higher than
+ our own so yield immediately. Yes it is ok to do
+ this from within the critical section - the kernel
+ takes care of that. */
+ portYIELD_WITHIN_API();
+ }
+ }
+
+ taskEXIT_CRITICAL();
+
+ /* Return to the original privilege level before exiting the
+ function. */
+ return pdPASS;
+ }
+ else
+ {
+ if( xTicksToWait == ( portTickType ) 0 )
+ {
+ /* The queue was full and no block time is specified (or
+ the block time has expired) so leave now. */
+ taskEXIT_CRITICAL();
+
+ /* Return to the original privilege level before exiting
+ the function. */
+ traceQUEUE_SEND_FAILED( pxQueue );
+ return errQUEUE_FULL;
+ }
+ else if( xEntryTimeSet == pdFALSE )
+ {
+ /* The queue was full and a block time was specified so
+ configure the timeout structure. */
+ vTaskSetTimeOutState( &xTimeOut );
+ xEntryTimeSet = pdTRUE;
+ }
+ }
+ }
+ taskEXIT_CRITICAL();
+
+ /* Interrupts and other tasks can send to and receive from the queue
+ now the critical section has been exited. */
+
+ vTaskSuspendAll();
+ prvLockQueue( pxQueue );
+
+ /* Update the timeout state to see if it has expired yet. */
+ if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
+ {
+ if( prvIsQueueFull( pxQueue ) )
+ {
+ traceBLOCKING_ON_QUEUE_SEND( pxQueue );
+ vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait );
+
+ /* Unlocking the queue means queue events can effect the
+ event list. It is possible that interrupts occurring now
+ remove this task from the event list again - but as the
+ scheduler is suspended the task will go onto the pending
+ ready last instead of the actual ready list. */
+ prvUnlockQueue( pxQueue );
+
+ /* Resuming the scheduler will move tasks from the pending
+ ready list into the ready list - so it is feasible that this
+ task is already in a ready list before it yields - in which
+ case the yield will not cause a context switch unless there
+ is also a higher priority task in the pending ready list. */
+ if( !xTaskResumeAll() )
+ {
+ portYIELD_WITHIN_API();
+ }
+ }
+ else
+ {
+ /* Try again. */
+ prvUnlockQueue( pxQueue );
+ ( void ) xTaskResumeAll();
+ }
+ }
+ else
+ {
+ /* The timeout has expired. */
+ prvUnlockQueue( pxQueue );
+ ( void ) xTaskResumeAll();
+
+ /* Return to the original privilege level before exiting the
+ function. */
+ traceQUEUE_SEND_FAILED( pxQueue );
+ return errQUEUE_FULL;
+ }
+ }
+}
+/*-----------------------------------------------------------*/
+
+#if configUSE_ALTERNATIVE_API == 1
+
+ signed portBASE_TYPE xQueueAltGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition )
+ {
+ signed portBASE_TYPE xEntryTimeSet = pdFALSE;
+ xTimeOutType xTimeOut;
+
+ configASSERT( pxQueue );
+ configASSERT( !( ( pvItemToQueue == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) );
+
+ for( ;; )
+ {
+ taskENTER_CRITICAL();
+ {
+ /* Is there room on the queue now? To be running we must be
+ the highest priority task wanting to access the queue. */
+ if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
+ {
+ traceQUEUE_SEND( pxQueue );
+ prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );
+
+ /* If there was a task waiting for data to arrive on the
+ queue then unblock it now. */
+ if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
+ {
+ if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) == pdTRUE )
+ {
+ /* The unblocked task has a priority higher than
+ our own so yield immediately. */
+ portYIELD_WITHIN_API();
+ }
+ }
+
+ taskEXIT_CRITICAL();
+ return pdPASS;
+ }
+ else
+ {
+ if( xTicksToWait == ( portTickType ) 0 )
+ {
+ taskEXIT_CRITICAL();
+ return errQUEUE_FULL;
+ }
+ else if( xEntryTimeSet == pdFALSE )
+ {
+ vTaskSetTimeOutState( &xTimeOut );
+ xEntryTimeSet = pdTRUE;
+ }
+ }
+ }
+ taskEXIT_CRITICAL();
+
+ taskENTER_CRITICAL();
+ {
+ if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
+ {
+ if( prvIsQueueFull( pxQueue ) )
+ {
+ traceBLOCKING_ON_QUEUE_SEND( pxQueue );
+ vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait );
+ portYIELD_WITHIN_API();
+ }
+ }
+ else
+ {
+ taskEXIT_CRITICAL();
+ traceQUEUE_SEND_FAILED( pxQueue );
+ return errQUEUE_FULL;
+ }
+ }
+ taskEXIT_CRITICAL();
+ }
+ }
+
+#endif /* configUSE_ALTERNATIVE_API */
+/*-----------------------------------------------------------*/
+
+#if configUSE_ALTERNATIVE_API == 1
+
+ signed portBASE_TYPE xQueueAltGenericReceive( xQueueHandle pxQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking )
+ {
+ signed portBASE_TYPE xEntryTimeSet = pdFALSE;
+ xTimeOutType xTimeOut;
+ signed char *pcOriginalReadPosition;
+
+ configASSERT( pxQueue );
+ configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) );
+
+ for( ;; )
+ {
+ taskENTER_CRITICAL();
+ {
+ if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )
+ {
+ /* Remember our read position in case we are just peeking. */
+ pcOriginalReadPosition = pxQueue->pcReadFrom;
+
+ prvCopyDataFromQueue( pxQueue, pvBuffer );
+
+ if( xJustPeeking == pdFALSE )
+ {
+ traceQUEUE_RECEIVE( pxQueue );
+
+ /* We are actually removing data. */
+ --( pxQueue->uxMessagesWaiting );
+
+ #if ( configUSE_MUTEXES == 1 )
+ {
+ if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
+ {
+ /* Record the information required to implement
+ priority inheritance should it become necessary. */
+ pxQueue->pxMutexHolder = xTaskGetCurrentTaskHandle();
+ }
+ }
+ #endif
+
+ if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )
+ {
+ if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) == pdTRUE )
+ {
+ portYIELD_WITHIN_API();
+ }
+ }
+ }
+ else
+ {
+ traceQUEUE_PEEK( pxQueue );
+
+ /* We are not removing the data, so reset our read
+ pointer. */
+ pxQueue->pcReadFrom = pcOriginalReadPosition;
+
+ /* The data is being left in the queue, so see if there are
+ any other tasks waiting for the data. */
+ if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
+ {
+ /* Tasks that are removed from the event list will get added to
+ the pending ready list as the scheduler is still suspended. */
+ if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
+ {
+ /* The task waiting has a higher priority than this task. */
+ portYIELD_WITHIN_API();
+ }
+ }
+
+ }
+
+ taskEXIT_CRITICAL();
+ return pdPASS;
+ }
+ else
+ {
+ if( xTicksToWait == ( portTickType ) 0 )
+ {
+ taskEXIT_CRITICAL();
+ traceQUEUE_RECEIVE_FAILED( pxQueue );
+ return errQUEUE_EMPTY;
+ }
+ else if( xEntryTimeSet == pdFALSE )
+ {
+ vTaskSetTimeOutState( &xTimeOut );
+ xEntryTimeSet = pdTRUE;
+ }
+ }
+ }
+ taskEXIT_CRITICAL();
+
+ taskENTER_CRITICAL();
+ {
+ if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
+ {
+ if( prvIsQueueEmpty( pxQueue ) )
+ {
+ traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );
+
+ #if ( configUSE_MUTEXES == 1 )
+ {
+ if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
+ {
+ portENTER_CRITICAL();
+ vTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder );
+ portEXIT_CRITICAL();
+ }
+ }
+ #endif
+
+ vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
+ portYIELD_WITHIN_API();
+ }
+ }
+ else
+ {
+ taskEXIT_CRITICAL();
+ traceQUEUE_RECEIVE_FAILED( pxQueue );
+ return errQUEUE_EMPTY;
+ }
+ }
+ taskEXIT_CRITICAL();
+ }
+ }
+
+
+#endif /* configUSE_ALTERNATIVE_API */
+/*-----------------------------------------------------------*/
+
+signed portBASE_TYPE xQueueGenericSendFromISR( xQueueHandle pxQueue, const void * const pvItemToQueue, signed portBASE_TYPE *pxHigherPriorityTaskWoken, portBASE_TYPE xCopyPosition )
+{
+signed portBASE_TYPE xReturn;
+unsigned portBASE_TYPE uxSavedInterruptStatus;
+
+ configASSERT( pxQueue );
+ configASSERT( pxHigherPriorityTaskWoken );
+ configASSERT( !( ( pvItemToQueue == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) );
+
+ /* Similar to xQueueGenericSend, except we don't block if there is no room
+ in the queue. Also we don't directly wake a task that was blocked on a
+ queue read, instead we return a flag to say whether a context switch is
+ required or not (i.e. has a task with a higher priority than us been woken
+ by this post). */
+ uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
+ {
+ if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
+ {
+ traceQUEUE_SEND_FROM_ISR( pxQueue );
+
+ prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );
+
+ /* If the queue is locked we do not alter the event list. This will
+ be done when the queue is unlocked later. */
+ if( pxQueue->xTxLock == queueUNLOCKED )
+ {
+ if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
+ {
+ if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
+ {
+ /* The task waiting has a higher priority so record that a
+ context switch is required. */
+ *pxHigherPriorityTaskWoken = pdTRUE;
+ }
+ }
+ }
+ else
+ {
+ /* Increment the lock count so the task that unlocks the queue
+ knows that data was posted while it was locked. */
+ ++( pxQueue->xTxLock );
+ }
+
+ xReturn = pdPASS;
+ }
+ else
+ {
+ traceQUEUE_SEND_FROM_ISR_FAILED( pxQueue );
+ xReturn = errQUEUE_FULL;
+ }
+ }
+ portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+signed portBASE_TYPE xQueueGenericReceive( xQueueHandle pxQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking )
+{
+signed portBASE_TYPE xEntryTimeSet = pdFALSE;
+xTimeOutType xTimeOut;
+signed char *pcOriginalReadPosition;
+
+ configASSERT( pxQueue );
+ configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) );
+
+ /* This function relaxes the coding standard somewhat to allow return
+ statements within the function itself. This is done in the interest
+ of execution time efficiency. */
+
+ for( ;; )
+ {
+ taskENTER_CRITICAL();
+ {
+ /* Is there data in the queue now? To be running we must be
+ the highest priority task wanting to access the queue. */
+ if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )
+ {
+ /* Remember our read position in case we are just peeking. */
+ pcOriginalReadPosition = pxQueue->pcReadFrom;
+
+ prvCopyDataFromQueue( pxQueue, pvBuffer );
+
+ if( xJustPeeking == pdFALSE )
+ {
+ traceQUEUE_RECEIVE( pxQueue );
+
+ /* We are actually removing data. */
+ --( pxQueue->uxMessagesWaiting );
+
+ #if ( configUSE_MUTEXES == 1 )
+ {
+ if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
+ {
+ /* Record the information required to implement
+ priority inheritance should it become necessary. */
+ pxQueue->pxMutexHolder = xTaskGetCurrentTaskHandle();
+ }
+ }
+ #endif
+
+ if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )
+ {
+ if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) == pdTRUE )
+ {
+ portYIELD_WITHIN_API();
+ }
+ }
+ }
+ else
+ {
+ traceQUEUE_PEEK( pxQueue );
+
+ /* We are not removing the data, so reset our read
+ pointer. */
+ pxQueue->pcReadFrom = pcOriginalReadPosition;
+
+ /* The data is being left in the queue, so see if there are
+ any other tasks waiting for the data. */
+ if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
+ {
+ /* Tasks that are removed from the event list will get added to
+ the pending ready list as the scheduler is still suspended. */
+ if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
+ {
+ /* The task waiting has a higher priority than this task. */
+ portYIELD_WITHIN_API();
+ }
+ }
+
+ }
+
+ taskEXIT_CRITICAL();
+ return pdPASS;
+ }
+ else
+ {
+ if( xTicksToWait == ( portTickType ) 0 )
+ {
+ /* The queue was empty and no block time is specified (or
+ the block time has expired) so leave now. */
+ taskEXIT_CRITICAL();
+ traceQUEUE_RECEIVE_FAILED( pxQueue );
+ return errQUEUE_EMPTY;
+ }
+ else if( xEntryTimeSet == pdFALSE )
+ {
+ /* The queue was empty and a block time was specified so
+ configure the timeout structure. */
+ vTaskSetTimeOutState( &xTimeOut );
+ xEntryTimeSet = pdTRUE;
+ }
+ }
+ }
+ taskEXIT_CRITICAL();
+
+ /* Interrupts and other tasks can send to and receive from the queue
+ now the critical section has been exited. */
+
+ vTaskSuspendAll();
+ prvLockQueue( pxQueue );
+
+ /* Update the timeout state to see if it has expired yet. */
+ if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
+ {
+ if( prvIsQueueEmpty( pxQueue ) )
+ {
+ traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );
+
+ #if ( configUSE_MUTEXES == 1 )
+ {
+ if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
+ {
+ portENTER_CRITICAL();
+ {
+ vTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder );
+ }
+ portEXIT_CRITICAL();
+ }
+ }
+ #endif
+
+ vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
+ prvUnlockQueue( pxQueue );
+ if( !xTaskResumeAll() )
+ {
+ portYIELD_WITHIN_API();
+ }
+ }
+ else
+ {
+ /* Try again. */
+ prvUnlockQueue( pxQueue );
+ ( void ) xTaskResumeAll();
+ }
+ }
+ else
+ {
+ prvUnlockQueue( pxQueue );
+ ( void ) xTaskResumeAll();
+ traceQUEUE_RECEIVE_FAILED( pxQueue );
+ return errQUEUE_EMPTY;
+ }
+ }
+}
+/*-----------------------------------------------------------*/
+
+signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, void * const pvBuffer, signed portBASE_TYPE *pxTaskWoken )
+{
+signed portBASE_TYPE xReturn;
+unsigned portBASE_TYPE uxSavedInterruptStatus;
+
+ configASSERT( pxQueue );
+ configASSERT( pxTaskWoken );
+ configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) );
+
+ uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
+ {
+ /* We cannot block from an ISR, so check there is data available. */
+ if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )
+ {
+ traceQUEUE_RECEIVE_FROM_ISR( pxQueue );
+
+ prvCopyDataFromQueue( pxQueue, pvBuffer );
+ --( pxQueue->uxMessagesWaiting );
+
+ /* If the queue is locked we will not modify the event list. Instead
+ we update the lock count so the task that unlocks the queue will know
+ that an ISR has removed data while the queue was locked. */
+ if( pxQueue->xRxLock == queueUNLOCKED )
+ {
+ if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )
+ {
+ if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
+ {
+ /* The task waiting has a higher priority than us so
+ force a context switch. */
+ *pxTaskWoken = pdTRUE;
+ }
+ }
+ }
+ else
+ {
+ /* Increment the lock count so the task that unlocks the queue
+ knows that data was removed while it was locked. */
+ ++( pxQueue->xRxLock );
+ }
+
+ xReturn = pdPASS;
+ }
+ else
+ {
+ xReturn = pdFAIL;
+ traceQUEUE_RECEIVE_FROM_ISR_FAILED( pxQueue );
+ }
+ }
+ portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+unsigned portBASE_TYPE uxQueueMessagesWaiting( const xQueueHandle pxQueue )
+{
+unsigned portBASE_TYPE uxReturn;
+
+ configASSERT( pxQueue );
+
+ taskENTER_CRITICAL();
+ uxReturn = pxQueue->uxMessagesWaiting;
+ taskEXIT_CRITICAL();
+
+ return uxReturn;
+}
+/*-----------------------------------------------------------*/
+
+unsigned portBASE_TYPE uxQueueMessagesWaitingFromISR( const xQueueHandle pxQueue )
+{
+unsigned portBASE_TYPE uxReturn;
+
+ configASSERT( pxQueue );
+
+ uxReturn = pxQueue->uxMessagesWaiting;
+
+ return uxReturn;
+}
+/*-----------------------------------------------------------*/
+
+void vQueueDelete( xQueueHandle pxQueue )
+{
+ configASSERT( pxQueue );
+
+ traceQUEUE_DELETE( pxQueue );
+ vQueueUnregisterQueue( pxQueue );
+ vPortFree( pxQueue->pcHead );
+ vPortFree( pxQueue );
+}
+/*-----------------------------------------------------------*/
+
+static void prvCopyDataToQueue( xQUEUE *pxQueue, const void *pvItemToQueue, portBASE_TYPE xPosition )
+{
+ if( pxQueue->uxItemSize == ( unsigned portBASE_TYPE ) 0 )
+ {
+ #if ( configUSE_MUTEXES == 1 )
+ {
+ if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
+ {
+ /* The mutex is no longer being held. */
+ vTaskPriorityDisinherit( ( void * ) pxQueue->pxMutexHolder );
+ pxQueue->pxMutexHolder = NULL;
+ }
+ }
+ #endif
+ }
+ else if( xPosition == queueSEND_TO_BACK )
+ {
+ memcpy( ( void * ) pxQueue->pcWriteTo, pvItemToQueue, ( unsigned ) pxQueue->uxItemSize );
+ pxQueue->pcWriteTo += pxQueue->uxItemSize;
+ if( pxQueue->pcWriteTo >= pxQueue->pcTail )
+ {
+ pxQueue->pcWriteTo = pxQueue->pcHead;
+ }
+ }
+ else
+ {
+ memcpy( ( void * ) pxQueue->pcReadFrom, pvItemToQueue, ( unsigned ) pxQueue->uxItemSize );
+ pxQueue->pcReadFrom -= pxQueue->uxItemSize;
+ if( pxQueue->pcReadFrom < pxQueue->pcHead )
+ {
+ pxQueue->pcReadFrom = ( pxQueue->pcTail - pxQueue->uxItemSize );
+ }
+ }
+
+ ++( pxQueue->uxMessagesWaiting );
+}
+/*-----------------------------------------------------------*/
+
+static void prvCopyDataFromQueue( xQUEUE * const pxQueue, const void *pvBuffer )
+{
+ if( pxQueue->uxQueueType != queueQUEUE_IS_MUTEX )
+ {
+ pxQueue->pcReadFrom += pxQueue->uxItemSize;
+ if( pxQueue->pcReadFrom >= pxQueue->pcTail )
+ {
+ pxQueue->pcReadFrom = pxQueue->pcHead;
+ }
+ memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvUnlockQueue( xQueueHandle pxQueue )
+{
+ /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. */
+
+ /* The lock counts contains the number of extra data items placed or
+ removed from the queue while the queue was locked. When a queue is
+ locked items can be added or removed, but the event lists cannot be
+ updated. */
+ taskENTER_CRITICAL();
+ {
+ /* See if data was added to the queue while it was locked. */
+ while( pxQueue->xTxLock > queueLOCKED_UNMODIFIED )
+ {
+ /* Data was posted while the queue was locked. Are any tasks
+ blocked waiting for data to become available? */
+ if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
+ {
+ /* Tasks that are removed from the event list will get added to
+ the pending ready list as the scheduler is still suspended. */
+ if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
+ {
+ /* The task waiting has a higher priority so record that a
+ context switch is required. */
+ vTaskMissedYield();
+ }
+
+ --( pxQueue->xTxLock );
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ pxQueue->xTxLock = queueUNLOCKED;
+ }
+ taskEXIT_CRITICAL();
+
+ /* Do the same for the Rx lock. */
+ taskENTER_CRITICAL();
+ {
+ while( pxQueue->xRxLock > queueLOCKED_UNMODIFIED )
+ {
+ if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )
+ {
+ if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
+ {
+ vTaskMissedYield();
+ }
+
+ --( pxQueue->xRxLock );
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ pxQueue->xRxLock = queueUNLOCKED;
+ }
+ taskEXIT_CRITICAL();
+}
+/*-----------------------------------------------------------*/
+
+static signed portBASE_TYPE prvIsQueueEmpty( const xQueueHandle pxQueue )
+{
+signed portBASE_TYPE xReturn;
+
+ taskENTER_CRITICAL();
+ xReturn = ( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 );
+ taskEXIT_CRITICAL();
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+signed portBASE_TYPE xQueueIsQueueEmptyFromISR( const xQueueHandle pxQueue )
+{
+signed portBASE_TYPE xReturn;
+
+ configASSERT( pxQueue );
+ xReturn = ( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 );
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+static signed portBASE_TYPE prvIsQueueFull( const xQueueHandle pxQueue )
+{
+signed portBASE_TYPE xReturn;
+
+ taskENTER_CRITICAL();
+ xReturn = ( pxQueue->uxMessagesWaiting == pxQueue->uxLength );
+ taskEXIT_CRITICAL();
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+signed portBASE_TYPE xQueueIsQueueFullFromISR( const xQueueHandle pxQueue )
+{
+signed portBASE_TYPE xReturn;
+
+ configASSERT( pxQueue );
+ xReturn = ( pxQueue->uxMessagesWaiting == pxQueue->uxLength );
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+#if configUSE_CO_ROUTINES == 1
+signed portBASE_TYPE xQueueCRSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait )
+{
+signed portBASE_TYPE xReturn;
+
+ /* If the queue is already full we may have to block. A critical section
+ is required to prevent an interrupt removing something from the queue
+ between the check to see if the queue is full and blocking on the queue. */
+ portDISABLE_INTERRUPTS();
+ {
+ if( prvIsQueueFull( pxQueue ) )
+ {
+ /* The queue is full - do we want to block or just leave without
+ posting? */
+ if( xTicksToWait > ( portTickType ) 0 )
+ {
+ /* As this is called from a coroutine we cannot block directly, but
+ return indicating that we need to block. */
+ vCoRoutineAddToDelayedList( xTicksToWait, &( pxQueue->xTasksWaitingToSend ) );
+ portENABLE_INTERRUPTS();
+ return errQUEUE_BLOCKED;
+ }
+ else
+ {
+ portENABLE_INTERRUPTS();
+ return errQUEUE_FULL;
+ }
+ }
+ }
+ portENABLE_INTERRUPTS();
+
+ portNOP();
+
+ portDISABLE_INTERRUPTS();
+ {
+ if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
+ {
+ /* There is room in the queue, copy the data into the queue. */
+ prvCopyDataToQueue( pxQueue, pvItemToQueue, queueSEND_TO_BACK );
+ xReturn = pdPASS;
+
+ /* Were any co-routines waiting for data to become available? */
+ if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
+ {
+ /* In this instance the co-routine could be placed directly
+ into the ready list as we are within a critical section.
+ Instead the same pending ready list mechanism is used as if
+ the event were caused from within an interrupt. */
+ if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
+ {
+ /* The co-routine waiting has a higher priority so record
+ that a yield might be appropriate. */
+ xReturn = errQUEUE_YIELD;
+ }
+ }
+ }
+ else
+ {
+ xReturn = errQUEUE_FULL;
+ }
+ }
+ portENABLE_INTERRUPTS();
+
+ return xReturn;
+}
+#endif
+/*-----------------------------------------------------------*/
+
+#if configUSE_CO_ROUTINES == 1
+signed portBASE_TYPE xQueueCRReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait )
+{
+signed portBASE_TYPE xReturn;
+
+ /* If the queue is already empty we may have to block. A critical section
+ is required to prevent an interrupt adding something to the queue
+ between the check to see if the queue is empty and blocking on the queue. */
+ portDISABLE_INTERRUPTS();
+ {
+ if( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 )
+ {
+ /* There are no messages in the queue, do we want to block or just
+ leave with nothing? */
+ if( xTicksToWait > ( portTickType ) 0 )
+ {
+ /* As this is a co-routine we cannot block directly, but return
+ indicating that we need to block. */
+ vCoRoutineAddToDelayedList( xTicksToWait, &( pxQueue->xTasksWaitingToReceive ) );
+ portENABLE_INTERRUPTS();
+ return errQUEUE_BLOCKED;
+ }
+ else
+ {
+ portENABLE_INTERRUPTS();
+ return errQUEUE_FULL;
+ }
+ }
+ }
+ portENABLE_INTERRUPTS();
+
+ portNOP();
+
+ portDISABLE_INTERRUPTS();
+ {
+ if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )
+ {
+ /* Data is available from the queue. */
+ pxQueue->pcReadFrom += pxQueue->uxItemSize;
+ if( pxQueue->pcReadFrom >= pxQueue->pcTail )
+ {
+ pxQueue->pcReadFrom = pxQueue->pcHead;
+ }
+ --( pxQueue->uxMessagesWaiting );
+ memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );
+
+ xReturn = pdPASS;
+
+ /* Were any co-routines waiting for space to become available? */
+ if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )
+ {
+ /* In this instance the co-routine could be placed directly
+ into the ready list as we are within a critical section.
+ Instead the same pending ready list mechanism is used as if
+ the event were caused from within an interrupt. */
+ if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
+ {
+ xReturn = errQUEUE_YIELD;
+ }
+ }
+ }
+ else
+ {
+ xReturn = pdFAIL;
+ }
+ }
+ portENABLE_INTERRUPTS();
+
+ return xReturn;
+}
+#endif
+/*-----------------------------------------------------------*/
+
+
+
+#if configUSE_CO_ROUTINES == 1
+signed portBASE_TYPE xQueueCRSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xCoRoutinePreviouslyWoken )
+{
+ /* Cannot block within an ISR so if there is no space on the queue then
+ exit without doing anything. */
+ if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
+ {
+ prvCopyDataToQueue( pxQueue, pvItemToQueue, queueSEND_TO_BACK );
+
+ /* We only want to wake one co-routine per ISR, so check that a
+ co-routine has not already been woken. */
+ if( !xCoRoutinePreviouslyWoken )
+ {
+ if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
+ {
+ if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
+ {
+ return pdTRUE;
+ }
+ }
+ }
+ }
+
+ return xCoRoutinePreviouslyWoken;
+}
+#endif
+/*-----------------------------------------------------------*/
+
+#if configUSE_CO_ROUTINES == 1
+signed portBASE_TYPE xQueueCRReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxCoRoutineWoken )
+{
+signed portBASE_TYPE xReturn;
+
+ /* We cannot block from an ISR, so check there is data available. If
+ not then just leave without doing anything. */
+ if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )
+ {
+ /* Copy the data from the queue. */
+ pxQueue->pcReadFrom += pxQueue->uxItemSize;
+ if( pxQueue->pcReadFrom >= pxQueue->pcTail )
+ {
+ pxQueue->pcReadFrom = pxQueue->pcHead;
+ }
+ --( pxQueue->uxMessagesWaiting );
+ memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );
+
+ if( !( *pxCoRoutineWoken ) )
+ {
+ if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )
+ {
+ if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
+ {
+ *pxCoRoutineWoken = pdTRUE;
+ }
+ }
+ }
+
+ xReturn = pdPASS;
+ }
+ else
+ {
+ xReturn = pdFAIL;
+ }
+
+ return xReturn;
+}
+#endif
+/*-----------------------------------------------------------*/
+
+#if configQUEUE_REGISTRY_SIZE > 0
+
+ void vQueueAddToRegistry( xQueueHandle xQueue, signed char *pcQueueName )
+ {
+ unsigned portBASE_TYPE ux;
+
+ /* See if there is an empty space in the registry. A NULL name denotes
+ a free slot. */
+ for( ux = ( unsigned portBASE_TYPE ) 0U; ux < configQUEUE_REGISTRY_SIZE; ux++ )
+ {
+ if( xQueueRegistry[ ux ].pcQueueName == NULL )
+ {
+ /* Store the information on this queue. */
+ xQueueRegistry[ ux ].pcQueueName = pcQueueName;
+ xQueueRegistry[ ux ].xHandle = xQueue;
+ break;
+ }
+ }
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+#if configQUEUE_REGISTRY_SIZE > 0
+
+ static void vQueueUnregisterQueue( xQueueHandle xQueue )
+ {
+ unsigned portBASE_TYPE ux;
+
+ /* See if the handle of the queue being unregistered in actually in the
+ registry. */
+ for( ux = ( unsigned portBASE_TYPE ) 0U; ux < configQUEUE_REGISTRY_SIZE; ux++ )
+ {
+ if( xQueueRegistry[ ux ].xHandle == xQueue )
+ {
+ /* Set the name to NULL to show that this slot if free again. */
+ xQueueRegistry[ ux ].pcQueueName = NULL;
+ break;
+ }
+ }
+
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+#if configUSE_TIMERS == 1
+
+ void vQueueWaitForMessageRestricted( xQueueHandle pxQueue, portTickType xTicksToWait )
+ {
+ /* This function should not be called by application code hence the
+ 'Restricted' in its name. It is not part of the public API. It is
+ designed for use by kernel code, and has special calling requirements.
+ It can result in vListInsert() being called on a list that can only
+ possibly ever have one item in it, so the list will be fast, but even
+ so it should be called with the scheduler locked and not from a critical
+ section. */
+
+ /* Only do anything if there are no messages in the queue. This function
+ will not actually cause the task to block, just place it on a blocked
+ list. It will not block until the scheduler is unlocked - at which
+ time a yield will be performed. If an item is added to the queue while
+ the queue is locked, and the calling task blocks on the queue, then the
+ calling task will be immediately unblocked when the queue is unlocked. */
+ prvLockQueue( pxQueue );
+ if( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0U )
+ {
+ /* There is nothing in the queue, block for the specified period. */
+ vTaskPlaceOnEventListRestricted( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
+ }
+ prvUnlockQueue( pxQueue );
+ }
+
+#endif
+
diff --git a/Libmaple/libmaple/libraries/FreeRTOS/utility/queue.h b/Libmaple/libmaple/libraries/FreeRTOS/utility/queue.h
index 47add266..9a6c86a0 100644
--- a/Libmaple/libmaple/libraries/FreeRTOS/utility/queue.h
+++ b/Libmaple/libmaple/libraries/FreeRTOS/utility/queue.h
@@ -1,1270 +1,1270 @@
-/*
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.
-
-
- FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:
- Atollic AB - Atollic provides professional embedded systems development
- tools for C/C++ development, code analysis and test automation.
- See http://www.atollic.com
-
-
- ***************************************************************************
- * *
- * FreeRTOS tutorial books are available in pdf and paperback. *
- * Complete, revised, and edited pdf reference manuals are also *
- * available. *
- * *
- * Purchasing FreeRTOS documentation will not only help you, by *
- * ensuring you get running as quickly as possible and with an *
- * in-depth knowledge of how to use FreeRTOS, it will also help *
- * the FreeRTOS project to continue with its mission of providing *
- * professional grade, cross platform, de facto standard solutions *
- * for microcontrollers - completely free of charge! *
- * *
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
- * *
- * Thank you for using FreeRTOS, and thank you for your support! *
- * *
- ***************************************************************************
-
-
- This file is part of the FreeRTOS distribution.
-
- FreeRTOS is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License (version 2) as published by the
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
- >>>NOTE<<< The modification to the GPL is included to allow you to
- distribute a combined work that includes FreeRTOS without being obliged to
- provide the source code for proprietary components outside of the FreeRTOS
- kernel. FreeRTOS is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- more details. You should have received a copy of the GNU General Public
- License and the FreeRTOS license exception along with FreeRTOS; if not it
- can be viewed here: http://www.freertos.org/a00114.html and also obtained
- by writing to Richard Barry, contact details for whom are available on the
- FreeRTOS WEB site.
-
- 1 tab == 4 spaces!
-
- http://www.FreeRTOS.org - Documentation, latest information, license and
- contact details.
-
- http://www.SafeRTOS.com - A version that is certified for use in safety
- critical systems.
-
- http://www.OpenRTOS.com - Commercial support, development, porting,
- licensing and training services.
-*/
-
-
-#ifndef QUEUE_H
-#define QUEUE_H
-
-#ifndef INC_FREERTOS_H
- #error "#include FreeRTOS.h" must appear in source files before "#include queue.h"
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-#include "mpu_wrappers.h"
-
-/**
- * Type by which queues are referenced. For example, a call to xQueueCreate
- * returns (via a pointer parameter) an xQueueHandle variable that can then
- * be used as a parameter to xQueueSend(), xQueueReceive(), etc.
- */
-typedef void * xQueueHandle;
-
-
-/* For internal use only. */
-#define queueSEND_TO_BACK ( 0 )
-#define queueSEND_TO_FRONT ( 1 )
-
-
-/**
- * queue. h
- *
- xQueueHandle xQueueCreate(
- unsigned portBASE_TYPE uxQueueLength,
- unsigned portBASE_TYPE uxItemSize
- );
- *
- *
- * Creates a new queue instance. This allocates the storage required by the
- * new queue and returns a handle for the queue.
- *
- * @param uxQueueLength The maximum number of items that the queue can contain.
- *
- * @param uxItemSize The number of bytes each item in the queue will require.
- * Items are queued by copy, not by reference, so this is the number of bytes
- * that will be copied for each posted item. Each item on the queue must be
- * the same size.
- *
- * @return If the queue is successfully create then a handle to the newly
- * created queue is returned. If the queue cannot be created then 0 is
- * returned.
- *
- * Example usage:
-
- struct AMessage
- {
- char ucMessageID;
- char ucData[ 20 ];
- };
-
- void vATask( void *pvParameters )
- {
- xQueueHandle xQueue1, xQueue2;
-
- // Create a queue capable of containing 10 unsigned long values.
- xQueue1 = xQueueCreate( 10, sizeof( unsigned long ) );
- if( xQueue1 == 0 )
- {
- // Queue was not created and must not be used.
- }
-
- // Create a queue capable of containing 10 pointers to AMessage structures.
- // These should be passed by pointer as they contain a lot of data.
- xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );
- if( xQueue2 == 0 )
- {
- // Queue was not created and must not be used.
- }
-
- // ... Rest of task code.
- }
-
- * \defgroup xQueueCreate xQueueCreate
- * \ingroup QueueManagement
- */
-xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize );
-
-/**
- * queue. h
- *
- portBASE_TYPE xQueueSendToToFront(
- xQueueHandle xQueue,
- const void * pvItemToQueue,
- portTickType xTicksToWait
- );
- *
- *
- * This is a macro that calls xQueueGenericSend().
- *
- * Post an item to the front of a queue. The item is queued by copy, not by
- * reference. This function must not be called from an interrupt service
- * routine. See xQueueSendFromISR () for an alternative which may be used
- * in an ISR.
- *
- * @param xQueue The handle to the queue on which the item is to be posted.
- *
- * @param pvItemToQueue A pointer to the item that is to be placed on the
- * queue. The size of the items the queue will hold was defined when the
- * queue was created, so this many bytes will be copied from pvItemToQueue
- * into the queue storage area.
- *
- * @param xTicksToWait The maximum amount of time the task should block
- * waiting for space to become available on the queue, should it already
- * be full. The call will return immediately if this is set to 0 and the
- * queue is full. The time is defined in tick periods so the constant
- * portTICK_RATE_MS should be used to convert to real time if this is required.
- *
- * @return pdTRUE if the item was successfully posted, otherwise errQUEUE_FULL.
- *
- * Example usage:
-
- struct AMessage
- {
- char ucMessageID;
- char ucData[ 20 ];
- } xMessage;
-
- unsigned long ulVar = 10UL;
-
- void vATask( void *pvParameters )
- {
- xQueueHandle xQueue1, xQueue2;
- struct AMessage *pxMessage;
-
- // Create a queue capable of containing 10 unsigned long values.
- xQueue1 = xQueueCreate( 10, sizeof( unsigned long ) );
-
- // Create a queue capable of containing 10 pointers to AMessage structures.
- // These should be passed by pointer as they contain a lot of data.
- xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );
-
- // ...
-
- if( xQueue1 != 0 )
- {
- // Send an unsigned long. Wait for 10 ticks for space to become
- // available if necessary.
- if( xQueueSendToFront( xQueue1, ( void * ) &ulVar, ( portTickType ) 10 ) != pdPASS )
- {
- // Failed to post the message, even after 10 ticks.
- }
- }
-
- if( xQueue2 != 0 )
- {
- // Send a pointer to a struct AMessage object. Don't block if the
- // queue is already full.
- pxMessage = & xMessage;
- xQueueSendToFront( xQueue2, ( void * ) &pxMessage, ( portTickType ) 0 );
- }
-
- // ... Rest of task code.
- }
-
- * \defgroup xQueueSend xQueueSend
- * \ingroup QueueManagement
- */
-#define xQueueSendToFront( xQueue, pvItemToQueue, xTicksToWait ) xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_FRONT )
-
-/**
- * queue. h
- *
- portBASE_TYPE xQueueSendToBack(
- xQueueHandle xQueue,
- const void * pvItemToQueue,
- portTickType xTicksToWait
- );
- *
- *
- * This is a macro that calls xQueueGenericSend().
- *
- * Post an item to the back of a queue. The item is queued by copy, not by
- * reference. This function must not be called from an interrupt service
- * routine. See xQueueSendFromISR () for an alternative which may be used
- * in an ISR.
- *
- * @param xQueue The handle to the queue on which the item is to be posted.
- *
- * @param pvItemToQueue A pointer to the item that is to be placed on the
- * queue. The size of the items the queue will hold was defined when the
- * queue was created, so this many bytes will be copied from pvItemToQueue
- * into the queue storage area.
- *
- * @param xTicksToWait The maximum amount of time the task should block
- * waiting for space to become available on the queue, should it already
- * be full. The call will return immediately if this is set to 0 and the queue
- * is full. The time is defined in tick periods so the constant
- * portTICK_RATE_MS should be used to convert to real time if this is required.
- *
- * @return pdTRUE if the item was successfully posted, otherwise errQUEUE_FULL.
- *
- * Example usage:
-
- struct AMessage
- {
- char ucMessageID;
- char ucData[ 20 ];
- } xMessage;
-
- unsigned long ulVar = 10UL;
-
- void vATask( void *pvParameters )
- {
- xQueueHandle xQueue1, xQueue2;
- struct AMessage *pxMessage;
-
- // Create a queue capable of containing 10 unsigned long values.
- xQueue1 = xQueueCreate( 10, sizeof( unsigned long ) );
-
- // Create a queue capable of containing 10 pointers to AMessage structures.
- // These should be passed by pointer as they contain a lot of data.
- xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );
-
- // ...
-
- if( xQueue1 != 0 )
- {
- // Send an unsigned long. Wait for 10 ticks for space to become
- // available if necessary.
- if( xQueueSendToBack( xQueue1, ( void * ) &ulVar, ( portTickType ) 10 ) != pdPASS )
- {
- // Failed to post the message, even after 10 ticks.
- }
- }
-
- if( xQueue2 != 0 )
- {
- // Send a pointer to a struct AMessage object. Don't block if the
- // queue is already full.
- pxMessage = & xMessage;
- xQueueSendToBack( xQueue2, ( void * ) &pxMessage, ( portTickType ) 0 );
- }
-
- // ... Rest of task code.
- }
-
- * \defgroup xQueueSend xQueueSend
- * \ingroup QueueManagement
- */
-#define xQueueSendToBack( xQueue, pvItemToQueue, xTicksToWait ) xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK )
-
-/**
- * queue. h
- *
- portBASE_TYPE xQueueSend(
- xQueueHandle xQueue,
- const void * pvItemToQueue,
- portTickType xTicksToWait
- );
- *
- *
- * This is a macro that calls xQueueGenericSend(). It is included for
- * backward compatibility with versions of FreeRTOS.org that did not
- * include the xQueueSendToFront() and xQueueSendToBack() macros. It is
- * equivalent to xQueueSendToBack().
- *
- * Post an item on a queue. The item is queued by copy, not by reference.
- * This function must not be called from an interrupt service routine.
- * See xQueueSendFromISR () for an alternative which may be used in an ISR.
- *
- * @param xQueue The handle to the queue on which the item is to be posted.
- *
- * @param pvItemToQueue A pointer to the item that is to be placed on the
- * queue. The size of the items the queue will hold was defined when the
- * queue was created, so this many bytes will be copied from pvItemToQueue
- * into the queue storage area.
- *
- * @param xTicksToWait The maximum amount of time the task should block
- * waiting for space to become available on the queue, should it already
- * be full. The call will return immediately if this is set to 0 and the
- * queue is full. The time is defined in tick periods so the constant
- * portTICK_RATE_MS should be used to convert to real time if this is required.
- *
- * @return pdTRUE if the item was successfully posted, otherwise errQUEUE_FULL.
- *
- * Example usage:
-
- struct AMessage
- {
- char ucMessageID;
- char ucData[ 20 ];
- } xMessage;
-
- unsigned long ulVar = 10UL;
-
- void vATask( void *pvParameters )
- {
- xQueueHandle xQueue1, xQueue2;
- struct AMessage *pxMessage;
-
- // Create a queue capable of containing 10 unsigned long values.
- xQueue1 = xQueueCreate( 10, sizeof( unsigned long ) );
-
- // Create a queue capable of containing 10 pointers to AMessage structures.
- // These should be passed by pointer as they contain a lot of data.
- xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );
-
- // ...
-
- if( xQueue1 != 0 )
- {
- // Send an unsigned long. Wait for 10 ticks for space to become
- // available if necessary.
- if( xQueueSend( xQueue1, ( void * ) &ulVar, ( portTickType ) 10 ) != pdPASS )
- {
- // Failed to post the message, even after 10 ticks.
- }
- }
-
- if( xQueue2 != 0 )
- {
- // Send a pointer to a struct AMessage object. Don't block if the
- // queue is already full.
- pxMessage = & xMessage;
- xQueueSend( xQueue2, ( void * ) &pxMessage, ( portTickType ) 0 );
- }
-
- // ... Rest of task code.
- }
-
- * \defgroup xQueueSend xQueueSend
- * \ingroup QueueManagement
- */
-#define xQueueSend( xQueue, pvItemToQueue, xTicksToWait ) xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK )
-
-
-/**
- * queue. h
- *
- portBASE_TYPE xQueueGenericSend(
- xQueueHandle xQueue,
- const void * pvItemToQueue,
- portTickType xTicksToWait
- portBASE_TYPE xCopyPosition
- );
- *
- *
- * It is preferred that the macros xQueueSend(), xQueueSendToFront() and
- * xQueueSendToBack() are used in place of calling this function directly.
- *
- * Post an item on a queue. The item is queued by copy, not by reference.
- * This function must not be called from an interrupt service routine.
- * See xQueueSendFromISR () for an alternative which may be used in an ISR.
- *
- * @param xQueue The handle to the queue on which the item is to be posted.
- *
- * @param pvItemToQueue A pointer to the item that is to be placed on the
- * queue. The size of the items the queue will hold was defined when the
- * queue was created, so this many bytes will be copied from pvItemToQueue
- * into the queue storage area.
- *
- * @param xTicksToWait The maximum amount of time the task should block
- * waiting for space to become available on the queue, should it already
- * be full. The call will return immediately if this is set to 0 and the
- * queue is full. The time is defined in tick periods so the constant
- * portTICK_RATE_MS should be used to convert to real time if this is required.
- *
- * @param xCopyPosition Can take the value queueSEND_TO_BACK to place the
- * item at the back of the queue, or queueSEND_TO_FRONT to place the item
- * at the front of the queue (for high priority messages).
- *
- * @return pdTRUE if the item was successfully posted, otherwise errQUEUE_FULL.
- *
- * Example usage:
-
- struct AMessage
- {
- char ucMessageID;
- char ucData[ 20 ];
- } xMessage;
-
- unsigned long ulVar = 10UL;
-
- void vATask( void *pvParameters )
- {
- xQueueHandle xQueue1, xQueue2;
- struct AMessage *pxMessage;
-
- // Create a queue capable of containing 10 unsigned long values.
- xQueue1 = xQueueCreate( 10, sizeof( unsigned long ) );
-
- // Create a queue capable of containing 10 pointers to AMessage structures.
- // These should be passed by pointer as they contain a lot of data.
- xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );
-
- // ...
-
- if( xQueue1 != 0 )
- {
- // Send an unsigned long. Wait for 10 ticks for space to become
- // available if necessary.
- if( xQueueGenericSend( xQueue1, ( void * ) &ulVar, ( portTickType ) 10, queueSEND_TO_BACK ) != pdPASS )
- {
- // Failed to post the message, even after 10 ticks.
- }
- }
-
- if( xQueue2 != 0 )
- {
- // Send a pointer to a struct AMessage object. Don't block if the
- // queue is already full.
- pxMessage = & xMessage;
- xQueueGenericSend( xQueue2, ( void * ) &pxMessage, ( portTickType ) 0, queueSEND_TO_BACK );
- }
-
- // ... Rest of task code.
- }
-
- * \defgroup xQueueSend xQueueSend
- * \ingroup QueueManagement
- */
-signed portBASE_TYPE xQueueGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition );
-
-/**
- * queue. h
- *
- portBASE_TYPE xQueuePeek(
- xQueueHandle xQueue,
- void *pvBuffer,
- portTickType xTicksToWait
- );
- *
- * This is a macro that calls the xQueueGenericReceive() function.
- *
- * Receive an item from a queue without removing the item from the queue.
- * The item is received by copy so a buffer of adequate size must be
- * provided. The number of bytes copied into the buffer was defined when
- * the queue was created.
- *
- * Successfully received items remain on the queue so will be returned again
- * by the next call, or a call to xQueueReceive().
- *
- * This macro must not be used in an interrupt service routine.
- *
- * @param pxQueue The handle to the queue from which the item is to be
- * received.
- *
- * @param pvBuffer Pointer to the buffer into which the received item will
- * be copied.
- *
- * @param xTicksToWait The maximum amount of time the task should block
- * waiting for an item to receive should the queue be empty at the time
- * of the call. The time is defined in tick periods so the constant
- * portTICK_RATE_MS should be used to convert to real time if this is required.
- * xQueuePeek() will return immediately if xTicksToWait is 0 and the queue
- * is empty.
- *
- * @return pdTRUE if an item was successfully received from the queue,
- * otherwise pdFALSE.
- *
- * Example usage:
-
- struct AMessage
- {
- char ucMessageID;
- char ucData[ 20 ];
- } xMessage;
-
- xQueueHandle xQueue;
-
- // Task to create a queue and post a value.
- void vATask( void *pvParameters )
- {
- struct AMessage *pxMessage;
-
- // Create a queue capable of containing 10 pointers to AMessage structures.
- // These should be passed by pointer as they contain a lot of data.
- xQueue = xQueueCreate( 10, sizeof( struct AMessage * ) );
- if( xQueue == 0 )
- {
- // Failed to create the queue.
- }
-
- // ...
-
- // Send a pointer to a struct AMessage object. Don't block if the
- // queue is already full.
- pxMessage = & xMessage;
- xQueueSend( xQueue, ( void * ) &pxMessage, ( portTickType ) 0 );
-
- // ... Rest of task code.
- }
-
- // Task to peek the data from the queue.
- void vADifferentTask( void *pvParameters )
- {
- struct AMessage *pxRxedMessage;
-
- if( xQueue != 0 )
- {
- // Peek a message on the created queue. Block for 10 ticks if a
- // message is not immediately available.
- if( xQueuePeek( xQueue, &( pxRxedMessage ), ( portTickType ) 10 ) )
- {
- // pcRxedMessage now points to the struct AMessage variable posted
- // by vATask, but the item still remains on the queue.
- }
- }
-
- // ... Rest of task code.
- }
-
- * \defgroup xQueueReceive xQueueReceive
- * \ingroup QueueManagement
- */
-#define xQueuePeek( xQueue, pvBuffer, xTicksToWait ) xQueueGenericReceive( ( xQueue ), ( pvBuffer ), ( xTicksToWait ), pdTRUE )
-
-/**
- * queue. h
- *
- portBASE_TYPE xQueueReceive(
- xQueueHandle xQueue,
- void *pvBuffer,
- portTickType xTicksToWait
- );
- *
- * This is a macro that calls the xQueueGenericReceive() function.
- *
- * Receive an item from a queue. The item is received by copy so a buffer of
- * adequate size must be provided. The number of bytes copied into the buffer
- * was defined when the queue was created.
- *
- * Successfully received items are removed from the queue.
- *
- * This function must not be used in an interrupt service routine. See
- * xQueueReceiveFromISR for an alternative that can.
- *
- * @param pxQueue The handle to the queue from which the item is to be
- * received.
- *
- * @param pvBuffer Pointer to the buffer into which the received item will
- * be copied.
- *
- * @param xTicksToWait The maximum amount of time the task should block
- * waiting for an item to receive should the queue be empty at the time
- * of the call. xQueueReceive() will return immediately if xTicksToWait
- * is zero and the queue is empty. The time is defined in tick periods so the
- * constant portTICK_RATE_MS should be used to convert to real time if this is
- * required.
- *
- * @return pdTRUE if an item was successfully received from the queue,
- * otherwise pdFALSE.
- *
- * Example usage:
-
- struct AMessage
- {
- char ucMessageID;
- char ucData[ 20 ];
- } xMessage;
-
- xQueueHandle xQueue;
-
- // Task to create a queue and post a value.
- void vATask( void *pvParameters )
- {
- struct AMessage *pxMessage;
-
- // Create a queue capable of containing 10 pointers to AMessage structures.
- // These should be passed by pointer as they contain a lot of data.
- xQueue = xQueueCreate( 10, sizeof( struct AMessage * ) );
- if( xQueue == 0 )
- {
- // Failed to create the queue.
- }
-
- // ...
-
- // Send a pointer to a struct AMessage object. Don't block if the
- // queue is already full.
- pxMessage = & xMessage;
- xQueueSend( xQueue, ( void * ) &pxMessage, ( portTickType ) 0 );
-
- // ... Rest of task code.
- }
-
- // Task to receive from the queue.
- void vADifferentTask( void *pvParameters )
- {
- struct AMessage *pxRxedMessage;
-
- if( xQueue != 0 )
- {
- // Receive a message on the created queue. Block for 10 ticks if a
- // message is not immediately available.
- if( xQueueReceive( xQueue, &( pxRxedMessage ), ( portTickType ) 10 ) )
- {
- // pcRxedMessage now points to the struct AMessage variable posted
- // by vATask.
- }
- }
-
- // ... Rest of task code.
- }
-
- * \defgroup xQueueReceive xQueueReceive
- * \ingroup QueueManagement
- */
-#define xQueueReceive( xQueue, pvBuffer, xTicksToWait ) xQueueGenericReceive( ( xQueue ), ( pvBuffer ), ( xTicksToWait ), pdFALSE )
-
-
-/**
- * queue. h
- *
- portBASE_TYPE xQueueGenericReceive(
- xQueueHandle xQueue,
- void *pvBuffer,
- portTickType xTicksToWait
- portBASE_TYPE xJustPeek
- );
- *
- * It is preferred that the macro xQueueReceive() be used rather than calling
- * this function directly.
- *
- * Receive an item from a queue. The item is received by copy so a buffer of
- * adequate size must be provided. The number of bytes copied into the buffer
- * was defined when the queue was created.
- *
- * This function must not be used in an interrupt service routine. See
- * xQueueReceiveFromISR for an alternative that can.
- *
- * @param pxQueue The handle to the queue from which the item is to be
- * received.
- *
- * @param pvBuffer Pointer to the buffer into which the received item will
- * be copied.
- *
- * @param xTicksToWait The maximum amount of time the task should block
- * waiting for an item to receive should the queue be empty at the time
- * of the call. The time is defined in tick periods so the constant
- * portTICK_RATE_MS should be used to convert to real time if this is required.
- * xQueueGenericReceive() will return immediately if the queue is empty and
- * xTicksToWait is 0.
- *
- * @param xJustPeek When set to true, the item received from the queue is not
- * actually removed from the queue - meaning a subsequent call to
- * xQueueReceive() will return the same item. When set to false, the item
- * being received from the queue is also removed from the queue.
- *
- * @return pdTRUE if an item was successfully received from the queue,
- * otherwise pdFALSE.
- *
- * Example usage:
-
- struct AMessage
- {
- char ucMessageID;
- char ucData[ 20 ];
- } xMessage;
-
- xQueueHandle xQueue;
-
- // Task to create a queue and post a value.
- void vATask( void *pvParameters )
- {
- struct AMessage *pxMessage;
-
- // Create a queue capable of containing 10 pointers to AMessage structures.
- // These should be passed by pointer as they contain a lot of data.
- xQueue = xQueueCreate( 10, sizeof( struct AMessage * ) );
- if( xQueue == 0 )
- {
- // Failed to create the queue.
- }
-
- // ...
-
- // Send a pointer to a struct AMessage object. Don't block if the
- // queue is already full.
- pxMessage = & xMessage;
- xQueueSend( xQueue, ( void * ) &pxMessage, ( portTickType ) 0 );
-
- // ... Rest of task code.
- }
-
- // Task to receive from the queue.
- void vADifferentTask( void *pvParameters )
- {
- struct AMessage *pxRxedMessage;
-
- if( xQueue != 0 )
- {
- // Receive a message on the created queue. Block for 10 ticks if a
- // message is not immediately available.
- if( xQueueGenericReceive( xQueue, &( pxRxedMessage ), ( portTickType ) 10 ) )
- {
- // pcRxedMessage now points to the struct AMessage variable posted
- // by vATask.
- }
- }
-
- // ... Rest of task code.
- }
-
- * \defgroup xQueueReceive xQueueReceive
- * \ingroup QueueManagement
- */
-signed portBASE_TYPE xQueueGenericReceive( xQueueHandle xQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeek );
-
-/**
- * queue. h
- * unsigned portBASE_TYPE uxQueueMessagesWaiting( const xQueueHandle xQueue );
- *
- * Return the number of messages stored in a queue.
- *
- * @param xQueue A handle to the queue being queried.
- *
- * @return The number of messages available in the queue.
- *
- * \page uxQueueMessagesWaiting uxQueueMessagesWaiting
- * \ingroup QueueManagement
- */
-unsigned portBASE_TYPE uxQueueMessagesWaiting( const xQueueHandle xQueue );
-
-/**
- * queue. h
- * void vQueueDelete( xQueueHandle xQueue );
- *
- * Delete a queue - freeing all the memory allocated for storing of items
- * placed on the queue.
- *
- * @param xQueue A handle to the queue to be deleted.
- *
- * \page vQueueDelete vQueueDelete
- * \ingroup QueueManagement
- */
-void vQueueDelete( xQueueHandle pxQueue );
-
-/**
- * queue. h
- *
- portBASE_TYPE xQueueSendToFrontFromISR(
- xQueueHandle pxQueue,
- const void *pvItemToQueue,
- portBASE_TYPE *pxHigherPriorityTaskWoken
- );
-
- *
- * This is a macro that calls xQueueGenericSendFromISR().
- *
- * Post an item to the front of a queue. It is safe to use this macro from
- * within an interrupt service routine.
- *
- * Items are queued by copy not reference so it is preferable to only
- * queue small items, especially when called from an ISR. In most cases
- * it would be preferable to store a pointer to the item being queued.
- *
- * @param xQueue The handle to the queue on which the item is to be posted.
- *
- * @param pvItemToQueue A pointer to the item that is to be placed on the
- * queue. The size of the items the queue will hold was defined when the
- * queue was created, so this many bytes will be copied from pvItemToQueue
- * into the queue storage area.
- *
- * @param pxHigherPriorityTaskWoken xQueueSendToFrontFromISR() will set
- * *pxHigherPriorityTaskWoken to pdTRUE if sending to the queue caused a task
- * to unblock, and the unblocked task has a priority higher than the currently
- * running task. If xQueueSendToFromFromISR() sets this value to pdTRUE then
- * a context switch should be requested before the interrupt is exited.
- *
- * @return pdTRUE if the data was successfully sent to the queue, otherwise
- * errQUEUE_FULL.
- *
- * Example usage for buffered IO (where the ISR can obtain more than one value
- * per call):
-
- void vBufferISR( void )
- {
- char cIn;
- portBASE_TYPE xHigherPrioritTaskWoken;
-
- // We have not woken a task at the start of the ISR.
- xHigherPriorityTaskWoken = pdFALSE;
-
- // Loop until the buffer is empty.
- do
- {
- // Obtain a byte from the buffer.
- cIn = portINPUT_BYTE( RX_REGISTER_ADDRESS );
-
- // Post the byte.
- xQueueSendToFrontFromISR( xRxQueue, &cIn, &xHigherPriorityTaskWoken );
-
- } while( portINPUT_BYTE( BUFFER_COUNT ) );
-
- // Now the buffer is empty we can switch context if necessary.
- if( xHigherPriorityTaskWoken )
- {
- taskYIELD ();
- }
- }
-
- *
- * \defgroup xQueueSendFromISR xQueueSendFromISR
- * \ingroup QueueManagement
- */
-#define xQueueSendToFrontFromISR( pxQueue, pvItemToQueue, pxHigherPriorityTaskWoken ) xQueueGenericSendFromISR( ( pxQueue ), ( pvItemToQueue ), ( pxHigherPriorityTaskWoken ), queueSEND_TO_FRONT )
-
-
-/**
- * queue. h
- *
- portBASE_TYPE xQueueSendToBackFromISR(
- xQueueHandle pxQueue,
- const void *pvItemToQueue,
- portBASE_TYPE *pxHigherPriorityTaskWoken
- );
-
- *
- * This is a macro that calls xQueueGenericSendFromISR().
- *
- * Post an item to the back of a queue. It is safe to use this macro from
- * within an interrupt service routine.
- *
- * Items are queued by copy not reference so it is preferable to only
- * queue small items, especially when called from an ISR. In most cases
- * it would be preferable to store a pointer to the item being queued.
- *
- * @param xQueue The handle to the queue on which the item is to be posted.
- *
- * @param pvItemToQueue A pointer to the item that is to be placed on the
- * queue. The size of the items the queue will hold was defined when the
- * queue was created, so this many bytes will be copied from pvItemToQueue
- * into the queue storage area.
- *
- * @param pxHigherPriorityTaskWoken xQueueSendToBackFromISR() will set
- * *pxHigherPriorityTaskWoken to pdTRUE if sending to the queue caused a task
- * to unblock, and the unblocked task has a priority higher than the currently
- * running task. If xQueueSendToBackFromISR() sets this value to pdTRUE then
- * a context switch should be requested before the interrupt is exited.
- *
- * @return pdTRUE if the data was successfully sent to the queue, otherwise
- * errQUEUE_FULL.
- *
- * Example usage for buffered IO (where the ISR can obtain more than one value
- * per call):
-
- void vBufferISR( void )
- {
- char cIn;
- portBASE_TYPE xHigherPriorityTaskWoken;
-
- // We have not woken a task at the start of the ISR.
- xHigherPriorityTaskWoken = pdFALSE;
-
- // Loop until the buffer is empty.
- do
- {
- // Obtain a byte from the buffer.
- cIn = portINPUT_BYTE( RX_REGISTER_ADDRESS );
-
- // Post the byte.
- xQueueSendToBackFromISR( xRxQueue, &cIn, &xHigherPriorityTaskWoken );
-
- } while( portINPUT_BYTE( BUFFER_COUNT ) );
-
- // Now the buffer is empty we can switch context if necessary.
- if( xHigherPriorityTaskWoken )
- {
- taskYIELD ();
- }
- }
-
- *
- * \defgroup xQueueSendFromISR xQueueSendFromISR
- * \ingroup QueueManagement
- */
-#define xQueueSendToBackFromISR( pxQueue, pvItemToQueue, pxHigherPriorityTaskWoken ) xQueueGenericSendFromISR( ( pxQueue ), ( pvItemToQueue ), ( pxHigherPriorityTaskWoken ), queueSEND_TO_BACK )
-
-/**
- * queue. h
- *
- portBASE_TYPE xQueueSendFromISR(
- xQueueHandle pxQueue,
- const void *pvItemToQueue,
- portBASE_TYPE *pxHigherPriorityTaskWoken
- );
-
- *
- * This is a macro that calls xQueueGenericSendFromISR(). It is included
- * for backward compatibility with versions of FreeRTOS.org that did not
- * include the xQueueSendToBackFromISR() and xQueueSendToFrontFromISR()
- * macros.
- *
- * Post an item to the back of a queue. It is safe to use this function from
- * within an interrupt service routine.
- *
- * Items are queued by copy not reference so it is preferable to only
- * queue small items, especially when called from an ISR. In most cases
- * it would be preferable to store a pointer to the item being queued.
- *
- * @param xQueue The handle to the queue on which the item is to be posted.
- *
- * @param pvItemToQueue A pointer to the item that is to be placed on the
- * queue. The size of the items the queue will hold was defined when the
- * queue was created, so this many bytes will be copied from pvItemToQueue
- * into the queue storage area.
- *
- * @param pxHigherPriorityTaskWoken xQueueSendFromISR() will set
- * *pxHigherPriorityTaskWoken to pdTRUE if sending to the queue caused a task
- * to unblock, and the unblocked task has a priority higher than the currently
- * running task. If xQueueSendFromISR() sets this value to pdTRUE then
- * a context switch should be requested before the interrupt is exited.
- *
- * @return pdTRUE if the data was successfully sent to the queue, otherwise
- * errQUEUE_FULL.
- *
- * Example usage for buffered IO (where the ISR can obtain more than one value
- * per call):
-
- void vBufferISR( void )
- {
- char cIn;
- portBASE_TYPE xHigherPriorityTaskWoken;
-
- // We have not woken a task at the start of the ISR.
- xHigherPriorityTaskWoken = pdFALSE;
-
- // Loop until the buffer is empty.
- do
- {
- // Obtain a byte from the buffer.
- cIn = portINPUT_BYTE( RX_REGISTER_ADDRESS );
-
- // Post the byte.
- xQueueSendFromISR( xRxQueue, &cIn, &xHigherPriorityTaskWoken );
-
- } while( portINPUT_BYTE( BUFFER_COUNT ) );
-
- // Now the buffer is empty we can switch context if necessary.
- if( xHigherPriorityTaskWoken )
- {
- // Actual macro used here is port specific.
- taskYIELD_FROM_ISR ();
- }
- }
-
- *
- * \defgroup xQueueSendFromISR xQueueSendFromISR
- * \ingroup QueueManagement
- */
-#define xQueueSendFromISR( pxQueue, pvItemToQueue, pxHigherPriorityTaskWoken ) xQueueGenericSendFromISR( ( pxQueue ), ( pvItemToQueue ), ( pxHigherPriorityTaskWoken ), queueSEND_TO_BACK )
-
-/**
- * queue. h
- *
- portBASE_TYPE xQueueGenericSendFromISR(
- xQueueHandle pxQueue,
- const void *pvItemToQueue,
- portBASE_TYPE *pxHigherPriorityTaskWoken,
- portBASE_TYPE xCopyPosition
- );
-
- *
- * It is preferred that the macros xQueueSendFromISR(),
- * xQueueSendToFrontFromISR() and xQueueSendToBackFromISR() be used in place
- * of calling this function directly.
- *
- * Post an item on a queue. It is safe to use this function from within an
- * interrupt service routine.
- *
- * Items are queued by copy not reference so it is preferable to only
- * queue small items, especially when called from an ISR. In most cases
- * it would be preferable to store a pointer to the item being queued.
- *
- * @param xQueue The handle to the queue on which the item is to be posted.
- *
- * @param pvItemToQueue A pointer to the item that is to be placed on the
- * queue. The size of the items the queue will hold was defined when the
- * queue was created, so this many bytes will be copied from pvItemToQueue
- * into the queue storage area.
- *
- * @param pxHigherPriorityTaskWoken xQueueGenericSendFromISR() will set
- * *pxHigherPriorityTaskWoken to pdTRUE if sending to the queue caused a task
- * to unblock, and the unblocked task has a priority higher than the currently
- * running task. If xQueueGenericSendFromISR() sets this value to pdTRUE then
- * a context switch should be requested before the interrupt is exited.
- *
- * @param xCopyPosition Can take the value queueSEND_TO_BACK to place the
- * item at the back of the queue, or queueSEND_TO_FRONT to place the item
- * at the front of the queue (for high priority messages).
- *
- * @return pdTRUE if the data was successfully sent to the queue, otherwise
- * errQUEUE_FULL.
- *
- * Example usage for buffered IO (where the ISR can obtain more than one value
- * per call):
-
- void vBufferISR( void )
- {
- char cIn;
- portBASE_TYPE xHigherPriorityTaskWokenByPost;
-
- // We have not woken a task at the start of the ISR.
- xHigherPriorityTaskWokenByPost = pdFALSE;
-
- // Loop until the buffer is empty.
- do
- {
- // Obtain a byte from the buffer.
- cIn = portINPUT_BYTE( RX_REGISTER_ADDRESS );
-
- // Post each byte.
- xQueueGenericSendFromISR( xRxQueue, &cIn, &xHigherPriorityTaskWokenByPost, queueSEND_TO_BACK );
-
- } while( portINPUT_BYTE( BUFFER_COUNT ) );
-
- // Now the buffer is empty we can switch context if necessary. Note that the
- // name of the yield function required is port specific.
- if( xHigherPriorityTaskWokenByPost )
- {
- taskYIELD_YIELD_FROM_ISR();
- }
- }
-
- *
- * \defgroup xQueueSendFromISR xQueueSendFromISR
- * \ingroup QueueManagement
- */
-signed portBASE_TYPE xQueueGenericSendFromISR( xQueueHandle pxQueue, const void * const pvItemToQueue, signed portBASE_TYPE *pxHigherPriorityTaskWoken, portBASE_TYPE xCopyPosition );
-
-/**
- * queue. h
- *
- portBASE_TYPE xQueueReceiveFromISR(
- xQueueHandle pxQueue,
- void *pvBuffer,
- portBASE_TYPE *pxTaskWoken
- );
- *
- *
- * Receive an item from a queue. It is safe to use this function from within an
- * interrupt service routine.
- *
- * @param pxQueue The handle to the queue from which the item is to be
- * received.
- *
- * @param pvBuffer Pointer to the buffer into which the received item will
- * be copied.
- *
- * @param pxTaskWoken A task may be blocked waiting for space to become
- * available on the queue. If xQueueReceiveFromISR causes such a task to
- * unblock *pxTaskWoken will get set to pdTRUE, otherwise *pxTaskWoken will
- * remain unchanged.
- *
- * @return pdTRUE if an item was successfully received from the queue,
- * otherwise pdFALSE.
- *
- * Example usage:
-
-
- xQueueHandle xQueue;
-
- // Function to create a queue and post some values.
- void vAFunction( void *pvParameters )
- {
- char cValueToPost;
- const portTickType xBlockTime = ( portTickType )0xff;
-
- // Create a queue capable of containing 10 characters.
- xQueue = xQueueCreate( 10, sizeof( char ) );
- if( xQueue == 0 )
- {
- // Failed to create the queue.
- }
-
- // ...
-
- // Post some characters that will be used within an ISR. If the queue
- // is full then this task will block for xBlockTime ticks.
- cValueToPost = 'a';
- xQueueSend( xQueue, ( void * ) &cValueToPost, xBlockTime );
- cValueToPost = 'b';
- xQueueSend( xQueue, ( void * ) &cValueToPost, xBlockTime );
-
- // ... keep posting characters ... this task may block when the queue
- // becomes full.
-
- cValueToPost = 'c';
- xQueueSend( xQueue, ( void * ) &cValueToPost, xBlockTime );
- }
-
- // ISR that outputs all the characters received on the queue.
- void vISR_Routine( void )
- {
- portBASE_TYPE xTaskWokenByReceive = pdFALSE;
- char cRxedChar;
-
- while( xQueueReceiveFromISR( xQueue, ( void * ) &cRxedChar, &xTaskWokenByReceive) )
- {
- // A character was received. Output the character now.
- vOutputCharacter( cRxedChar );
-
- // If removing the character from the queue woke the task that was
- // posting onto the queue cTaskWokenByReceive will have been set to
- // pdTRUE. No matter how many times this loop iterates only one
- // task will be woken.
- }
-
- if( cTaskWokenByPost != ( char ) pdFALSE;
- {
- taskYIELD ();
- }
- }
-
- * \defgroup xQueueReceiveFromISR xQueueReceiveFromISR
- * \ingroup QueueManagement
- */
-signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, void * const pvBuffer, signed portBASE_TYPE *pxTaskWoken );
-
-/*
- * Utilities to query queue that are safe to use from an ISR. These utilities
- * should be used only from witin an ISR, or within a critical section.
- */
-signed portBASE_TYPE xQueueIsQueueEmptyFromISR( const xQueueHandle pxQueue );
-signed portBASE_TYPE xQueueIsQueueFullFromISR( const xQueueHandle pxQueue );
-unsigned portBASE_TYPE uxQueueMessagesWaitingFromISR( const xQueueHandle pxQueue );
-
-
-/*
- * xQueueAltGenericSend() is an alternative version of xQueueGenericSend().
- * Likewise xQueueAltGenericReceive() is an alternative version of
- * xQueueGenericReceive().
- *
- * The source code that implements the alternative (Alt) API is much
- * simpler because it executes everything from within a critical section.
- * This is the approach taken by many other RTOSes, but FreeRTOS.org has the
- * preferred fully featured API too. The fully featured API has more
- * complex code that takes longer to execute, but makes much less use of
- * critical sections. Therefore the alternative API sacrifices interrupt
- * responsiveness to gain execution speed, whereas the fully featured API
- * sacrifices execution speed to ensure better interrupt responsiveness.
- */
-signed portBASE_TYPE xQueueAltGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition );
-signed portBASE_TYPE xQueueAltGenericReceive( xQueueHandle pxQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking );
-#define xQueueAltSendToFront( xQueue, pvItemToQueue, xTicksToWait ) xQueueAltGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_FRONT )
-#define xQueueAltSendToBack( xQueue, pvItemToQueue, xTicksToWait ) xQueueAltGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK )
-#define xQueueAltReceive( xQueue, pvBuffer, xTicksToWait ) xQueueAltGenericReceive( ( xQueue ), ( pvBuffer ), ( xTicksToWait ), pdFALSE )
-#define xQueueAltPeek( xQueue, pvBuffer, xTicksToWait ) xQueueAltGenericReceive( ( xQueue ), ( pvBuffer ), ( xTicksToWait ), pdTRUE )
-
-/*
- * The functions defined above are for passing data to and from tasks. The
- * functions below are the equivalents for passing data to and from
- * co-routines.
- *
- * These functions are called from the co-routine macro implementation and
- * should not be called directly from application code. Instead use the macro
- * wrappers defined within croutine.h.
- */
-signed portBASE_TYPE xQueueCRSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xCoRoutinePreviouslyWoken );
-signed portBASE_TYPE xQueueCRReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxTaskWoken );
-signed portBASE_TYPE xQueueCRSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait );
-signed portBASE_TYPE xQueueCRReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait );
-
-/*
- * For internal use only. Use xSemaphoreCreateMutex() or
- * xSemaphoreCreateCounting() instead of calling these functions directly.
- */
-xQueueHandle xQueueCreateMutex( void );
-xQueueHandle xQueueCreateCountingSemaphore( unsigned portBASE_TYPE uxCountValue, unsigned portBASE_TYPE uxInitialCount );
-
-/*
- * For internal use only. Use xSemaphoreTakeMutexRecursive() or
- * xSemaphoreGiveMutexRecursive() instead of calling these functions directly.
- */
-portBASE_TYPE xQueueTakeMutexRecursive( xQueueHandle pxMutex, portTickType xBlockTime );
-portBASE_TYPE xQueueGiveMutexRecursive( xQueueHandle pxMutex );
-
-/*
- * The registry is provided as a means for kernel aware debuggers to
- * locate queues, semaphores and mutexes. Call vQueueAddToRegistry() add
- * a queue, semaphore or mutex handle to the registry if you want the handle
- * to be available to a kernel aware debugger. If you are not using a kernel
- * aware debugger then this function can be ignored.
- *
- * configQUEUE_REGISTRY_SIZE defines the maximum number of handles the
- * registry can hold. configQUEUE_REGISTRY_SIZE must be greater than 0
- * within FreeRTOSConfig.h for the registry to be available. Its value
- * does not effect the number of queues, semaphores and mutexes that can be
- * created - just the number that the registry can hold.
- *
- * @param xQueue The handle of the queue being added to the registry. This
- * is the handle returned by a call to xQueueCreate(). Semaphore and mutex
- * handles can also be passed in here.
- *
- * @param pcName The name to be associated with the handle. This is the
- * name that the kernel aware debugger will display.
- */
-#if configQUEUE_REGISTRY_SIZE > 0U
- void vQueueAddToRegistry( xQueueHandle xQueue, signed char *pcName );
-#endif
-
-/* Not a public API function, hence the 'Restricted' in the name. */
-void vQueueWaitForMessageRestricted( xQueueHandle pxQueue, portTickType xTicksToWait );
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* QUEUE_H */
-
+/*
+ FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.
+
+
+ FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:
+ Atollic AB - Atollic provides professional embedded systems development
+ tools for C/C++ development, code analysis and test automation.
+ See http://www.atollic.com
+
+
+ ***************************************************************************
+ * *
+ * FreeRTOS tutorial books are available in pdf and paperback. *
+ * Complete, revised, and edited pdf reference manuals are also *
+ * available. *
+ * *
+ * Purchasing FreeRTOS documentation will not only help you, by *
+ * ensuring you get running as quickly as possible and with an *
+ * in-depth knowledge of how to use FreeRTOS, it will also help *
+ * the FreeRTOS project to continue with its mission of providing *
+ * professional grade, cross platform, de facto standard solutions *
+ * for microcontrollers - completely free of charge! *
+ * *
+ * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
+ * *
+ * Thank you for using FreeRTOS, and thank you for your support! *
+ * *
+ ***************************************************************************
+
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
+ >>>NOTE<<< The modification to the GPL is included to allow you to
+ distribute a combined work that includes FreeRTOS without being obliged to
+ provide the source code for proprietary components outside of the FreeRTOS
+ kernel. FreeRTOS is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details. You should have received a copy of the GNU General Public
+ License and the FreeRTOS license exception along with FreeRTOS; if not it
+ can be viewed here: http://www.freertos.org/a00114.html and also obtained
+ by writing to Richard Barry, contact details for whom are available on the
+ FreeRTOS WEB site.
+
+ 1 tab == 4 spaces!
+
+ http://www.FreeRTOS.org - Documentation, latest information, license and
+ contact details.
+
+ http://www.SafeRTOS.com - A version that is certified for use in safety
+ critical systems.
+
+ http://www.OpenRTOS.com - Commercial support, development, porting,
+ licensing and training services.
+*/
+
+
+#ifndef QUEUE_H
+#define QUEUE_H
+
+#ifndef INC_FREERTOS_H
+ #error "#include FreeRTOS.h" must appear in source files before "#include queue.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#include "mpu_wrappers.h"
+
+/**
+ * Type by which queues are referenced. For example, a call to xQueueCreate
+ * returns (via a pointer parameter) an xQueueHandle variable that can then
+ * be used as a parameter to xQueueSend(), xQueueReceive(), etc.
+ */
+typedef void * xQueueHandle;
+
+
+/* For internal use only. */
+#define queueSEND_TO_BACK ( 0 )
+#define queueSEND_TO_FRONT ( 1 )
+
+
+/**
+ * queue. h
+ *
+ xQueueHandle xQueueCreate(
+ unsigned portBASE_TYPE uxQueueLength,
+ unsigned portBASE_TYPE uxItemSize
+ );
+ *
+ *
+ * Creates a new queue instance. This allocates the storage required by the
+ * new queue and returns a handle for the queue.
+ *
+ * @param uxQueueLength The maximum number of items that the queue can contain.
+ *
+ * @param uxItemSize The number of bytes each item in the queue will require.
+ * Items are queued by copy, not by reference, so this is the number of bytes
+ * that will be copied for each posted item. Each item on the queue must be
+ * the same size.
+ *
+ * @return If the queue is successfully create then a handle to the newly
+ * created queue is returned. If the queue cannot be created then 0 is
+ * returned.
+ *
+ * Example usage:
+
+ struct AMessage
+ {
+ char ucMessageID;
+ char ucData[ 20 ];
+ };
+
+ void vATask( void *pvParameters )
+ {
+ xQueueHandle xQueue1, xQueue2;
+
+ // Create a queue capable of containing 10 unsigned long values.
+ xQueue1 = xQueueCreate( 10, sizeof( unsigned long ) );
+ if( xQueue1 == 0 )
+ {
+ // Queue was not created and must not be used.
+ }
+
+ // Create a queue capable of containing 10 pointers to AMessage structures.
+ // These should be passed by pointer as they contain a lot of data.
+ xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );
+ if( xQueue2 == 0 )
+ {
+ // Queue was not created and must not be used.
+ }
+
+ // ... Rest of task code.
+ }
+
+ * \defgroup xQueueCreate xQueueCreate
+ * \ingroup QueueManagement
+ */
+xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize );
+
+/**
+ * queue. h
+ *
+ portBASE_TYPE xQueueSendToToFront(
+ xQueueHandle xQueue,
+ const void * pvItemToQueue,
+ portTickType xTicksToWait
+ );
+ *
+ *
+ * This is a macro that calls xQueueGenericSend().
+ *
+ * Post an item to the front of a queue. The item is queued by copy, not by
+ * reference. This function must not be called from an interrupt service
+ * routine. See xQueueSendFromISR () for an alternative which may be used
+ * in an ISR.
+ *
+ * @param xQueue The handle to the queue on which the item is to be posted.
+ *
+ * @param pvItemToQueue A pointer to the item that is to be placed on the
+ * queue. The size of the items the queue will hold was defined when the
+ * queue was created, so this many bytes will be copied from pvItemToQueue
+ * into the queue storage area.
+ *
+ * @param xTicksToWait The maximum amount of time the task should block
+ * waiting for space to become available on the queue, should it already
+ * be full. The call will return immediately if this is set to 0 and the
+ * queue is full. The time is defined in tick periods so the constant
+ * portTICK_RATE_MS should be used to convert to real time if this is required.
+ *
+ * @return pdTRUE if the item was successfully posted, otherwise errQUEUE_FULL.
+ *
+ * Example usage:
+
+ struct AMessage
+ {
+ char ucMessageID;
+ char ucData[ 20 ];
+ } xMessage;
+
+ unsigned long ulVar = 10UL;
+
+ void vATask( void *pvParameters )
+ {
+ xQueueHandle xQueue1, xQueue2;
+ struct AMessage *pxMessage;
+
+ // Create a queue capable of containing 10 unsigned long values.
+ xQueue1 = xQueueCreate( 10, sizeof( unsigned long ) );
+
+ // Create a queue capable of containing 10 pointers to AMessage structures.
+ // These should be passed by pointer as they contain a lot of data.
+ xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );
+
+ // ...
+
+ if( xQueue1 != 0 )
+ {
+ // Send an unsigned long. Wait for 10 ticks for space to become
+ // available if necessary.
+ if( xQueueSendToFront( xQueue1, ( void * ) &ulVar, ( portTickType ) 10 ) != pdPASS )
+ {
+ // Failed to post the message, even after 10 ticks.
+ }
+ }
+
+ if( xQueue2 != 0 )
+ {
+ // Send a pointer to a struct AMessage object. Don't block if the
+ // queue is already full.
+ pxMessage = & xMessage;
+ xQueueSendToFront( xQueue2, ( void * ) &pxMessage, ( portTickType ) 0 );
+ }
+
+ // ... Rest of task code.
+ }
+
+ * \defgroup xQueueSend xQueueSend
+ * \ingroup QueueManagement
+ */
+#define xQueueSendToFront( xQueue, pvItemToQueue, xTicksToWait ) xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_FRONT )
+
+/**
+ * queue. h
+ *
+ portBASE_TYPE xQueueSendToBack(
+ xQueueHandle xQueue,
+ const void * pvItemToQueue,
+ portTickType xTicksToWait
+ );
+ *
+ *
+ * This is a macro that calls xQueueGenericSend().
+ *
+ * Post an item to the back of a queue. The item is queued by copy, not by
+ * reference. This function must not be called from an interrupt service
+ * routine. See xQueueSendFromISR () for an alternative which may be used
+ * in an ISR.
+ *
+ * @param xQueue The handle to the queue on which the item is to be posted.
+ *
+ * @param pvItemToQueue A pointer to the item that is to be placed on the
+ * queue. The size of the items the queue will hold was defined when the
+ * queue was created, so this many bytes will be copied from pvItemToQueue
+ * into the queue storage area.
+ *
+ * @param xTicksToWait The maximum amount of time the task should block
+ * waiting for space to become available on the queue, should it already
+ * be full. The call will return immediately if this is set to 0 and the queue
+ * is full. The time is defined in tick periods so the constant
+ * portTICK_RATE_MS should be used to convert to real time if this is required.
+ *
+ * @return pdTRUE if the item was successfully posted, otherwise errQUEUE_FULL.
+ *
+ * Example usage:
+
+ struct AMessage
+ {
+ char ucMessageID;
+ char ucData[ 20 ];
+ } xMessage;
+
+ unsigned long ulVar = 10UL;
+
+ void vATask( void *pvParameters )
+ {
+ xQueueHandle xQueue1, xQueue2;
+ struct AMessage *pxMessage;
+
+ // Create a queue capable of containing 10 unsigned long values.
+ xQueue1 = xQueueCreate( 10, sizeof( unsigned long ) );
+
+ // Create a queue capable of containing 10 pointers to AMessage structures.
+ // These should be passed by pointer as they contain a lot of data.
+ xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );
+
+ // ...
+
+ if( xQueue1 != 0 )
+ {
+ // Send an unsigned long. Wait for 10 ticks for space to become
+ // available if necessary.
+ if( xQueueSendToBack( xQueue1, ( void * ) &ulVar, ( portTickType ) 10 ) != pdPASS )
+ {
+ // Failed to post the message, even after 10 ticks.
+ }
+ }
+
+ if( xQueue2 != 0 )
+ {
+ // Send a pointer to a struct AMessage object. Don't block if the
+ // queue is already full.
+ pxMessage = & xMessage;
+ xQueueSendToBack( xQueue2, ( void * ) &pxMessage, ( portTickType ) 0 );
+ }
+
+ // ... Rest of task code.
+ }
+
+ * \defgroup xQueueSend xQueueSend
+ * \ingroup QueueManagement
+ */
+#define xQueueSendToBack( xQueue, pvItemToQueue, xTicksToWait ) xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK )
+
+/**
+ * queue. h
+ *
+ portBASE_TYPE xQueueSend(
+ xQueueHandle xQueue,
+ const void * pvItemToQueue,
+ portTickType xTicksToWait
+ );
+ *
+ *
+ * This is a macro that calls xQueueGenericSend(). It is included for
+ * backward compatibility with versions of FreeRTOS.org that did not
+ * include the xQueueSendToFront() and xQueueSendToBack() macros. It is
+ * equivalent to xQueueSendToBack().
+ *
+ * Post an item on a queue. The item is queued by copy, not by reference.
+ * This function must not be called from an interrupt service routine.
+ * See xQueueSendFromISR () for an alternative which may be used in an ISR.
+ *
+ * @param xQueue The handle to the queue on which the item is to be posted.
+ *
+ * @param pvItemToQueue A pointer to the item that is to be placed on the
+ * queue. The size of the items the queue will hold was defined when the
+ * queue was created, so this many bytes will be copied from pvItemToQueue
+ * into the queue storage area.
+ *
+ * @param xTicksToWait The maximum amount of time the task should block
+ * waiting for space to become available on the queue, should it already
+ * be full. The call will return immediately if this is set to 0 and the
+ * queue is full. The time is defined in tick periods so the constant
+ * portTICK_RATE_MS should be used to convert to real time if this is required.
+ *
+ * @return pdTRUE if the item was successfully posted, otherwise errQUEUE_FULL.
+ *
+ * Example usage:
+
+ struct AMessage
+ {
+ char ucMessageID;
+ char ucData[ 20 ];
+ } xMessage;
+
+ unsigned long ulVar = 10UL;
+
+ void vATask( void *pvParameters )
+ {
+ xQueueHandle xQueue1, xQueue2;
+ struct AMessage *pxMessage;
+
+ // Create a queue capable of containing 10 unsigned long values.
+ xQueue1 = xQueueCreate( 10, sizeof( unsigned long ) );
+
+ // Create a queue capable of containing 10 pointers to AMessage structures.
+ // These should be passed by pointer as they contain a lot of data.
+ xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );
+
+ // ...
+
+ if( xQueue1 != 0 )
+ {
+ // Send an unsigned long. Wait for 10 ticks for space to become
+ // available if necessary.
+ if( xQueueSend( xQueue1, ( void * ) &ulVar, ( portTickType ) 10 ) != pdPASS )
+ {
+ // Failed to post the message, even after 10 ticks.
+ }
+ }
+
+ if( xQueue2 != 0 )
+ {
+ // Send a pointer to a struct AMessage object. Don't block if the
+ // queue is already full.
+ pxMessage = & xMessage;
+ xQueueSend( xQueue2, ( void * ) &pxMessage, ( portTickType ) 0 );
+ }
+
+ // ... Rest of task code.
+ }
+
+ * \defgroup xQueueSend xQueueSend
+ * \ingroup QueueManagement
+ */
+#define xQueueSend( xQueue, pvItemToQueue, xTicksToWait ) xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK )
+
+
+/**
+ * queue. h
+ *
+ portBASE_TYPE xQueueGenericSend(
+ xQueueHandle xQueue,
+ const void * pvItemToQueue,
+ portTickType xTicksToWait
+ portBASE_TYPE xCopyPosition
+ );
+ *
+ *
+ * It is preferred that the macros xQueueSend(), xQueueSendToFront() and
+ * xQueueSendToBack() are used in place of calling this function directly.
+ *
+ * Post an item on a queue. The item is queued by copy, not by reference.
+ * This function must not be called from an interrupt service routine.
+ * See xQueueSendFromISR () for an alternative which may be used in an ISR.
+ *
+ * @param xQueue The handle to the queue on which the item is to be posted.
+ *
+ * @param pvItemToQueue A pointer to the item that is to be placed on the
+ * queue. The size of the items the queue will hold was defined when the
+ * queue was created, so this many bytes will be copied from pvItemToQueue
+ * into the queue storage area.
+ *
+ * @param xTicksToWait The maximum amount of time the task should block
+ * waiting for space to become available on the queue, should it already
+ * be full. The call will return immediately if this is set to 0 and the
+ * queue is full. The time is defined in tick periods so the constant
+ * portTICK_RATE_MS should be used to convert to real time if this is required.
+ *
+ * @param xCopyPosition Can take the value queueSEND_TO_BACK to place the
+ * item at the back of the queue, or queueSEND_TO_FRONT to place the item
+ * at the front of the queue (for high priority messages).
+ *
+ * @return pdTRUE if the item was successfully posted, otherwise errQUEUE_FULL.
+ *
+ * Example usage:
+
+ struct AMessage
+ {
+ char ucMessageID;
+ char ucData[ 20 ];
+ } xMessage;
+
+ unsigned long ulVar = 10UL;
+
+ void vATask( void *pvParameters )
+ {
+ xQueueHandle xQueue1, xQueue2;
+ struct AMessage *pxMessage;
+
+ // Create a queue capable of containing 10 unsigned long values.
+ xQueue1 = xQueueCreate( 10, sizeof( unsigned long ) );
+
+ // Create a queue capable of containing 10 pointers to AMessage structures.
+ // These should be passed by pointer as they contain a lot of data.
+ xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );
+
+ // ...
+
+ if( xQueue1 != 0 )
+ {
+ // Send an unsigned long. Wait for 10 ticks for space to become
+ // available if necessary.
+ if( xQueueGenericSend( xQueue1, ( void * ) &ulVar, ( portTickType ) 10, queueSEND_TO_BACK ) != pdPASS )
+ {
+ // Failed to post the message, even after 10 ticks.
+ }
+ }
+
+ if( xQueue2 != 0 )
+ {
+ // Send a pointer to a struct AMessage object. Don't block if the
+ // queue is already full.
+ pxMessage = & xMessage;
+ xQueueGenericSend( xQueue2, ( void * ) &pxMessage, ( portTickType ) 0, queueSEND_TO_BACK );
+ }
+
+ // ... Rest of task code.
+ }
+
+ * \defgroup xQueueSend xQueueSend
+ * \ingroup QueueManagement
+ */
+signed portBASE_TYPE xQueueGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition );
+
+/**
+ * queue. h
+ *
+ portBASE_TYPE xQueuePeek(
+ xQueueHandle xQueue,
+ void *pvBuffer,
+ portTickType xTicksToWait
+ );
+ *
+ * This is a macro that calls the xQueueGenericReceive() function.
+ *
+ * Receive an item from a queue without removing the item from the queue.
+ * The item is received by copy so a buffer of adequate size must be
+ * provided. The number of bytes copied into the buffer was defined when
+ * the queue was created.
+ *
+ * Successfully received items remain on the queue so will be returned again
+ * by the next call, or a call to xQueueReceive().
+ *
+ * This macro must not be used in an interrupt service routine.
+ *
+ * @param pxQueue The handle to the queue from which the item is to be
+ * received.
+ *
+ * @param pvBuffer Pointer to the buffer into which the received item will
+ * be copied.
+ *
+ * @param xTicksToWait The maximum amount of time the task should block
+ * waiting for an item to receive should the queue be empty at the time
+ * of the call. The time is defined in tick periods so the constant
+ * portTICK_RATE_MS should be used to convert to real time if this is required.
+ * xQueuePeek() will return immediately if xTicksToWait is 0 and the queue
+ * is empty.
+ *
+ * @return pdTRUE if an item was successfully received from the queue,
+ * otherwise pdFALSE.
+ *
+ * Example usage:
+
+ struct AMessage
+ {
+ char ucMessageID;
+ char ucData[ 20 ];
+ } xMessage;
+
+ xQueueHandle xQueue;
+
+ // Task to create a queue and post a value.
+ void vATask( void *pvParameters )
+ {
+ struct AMessage *pxMessage;
+
+ // Create a queue capable of containing 10 pointers to AMessage structures.
+ // These should be passed by pointer as they contain a lot of data.
+ xQueue = xQueueCreate( 10, sizeof( struct AMessage * ) );
+ if( xQueue == 0 )
+ {
+ // Failed to create the queue.
+ }
+
+ // ...
+
+ // Send a pointer to a struct AMessage object. Don't block if the
+ // queue is already full.
+ pxMessage = & xMessage;
+ xQueueSend( xQueue, ( void * ) &pxMessage, ( portTickType ) 0 );
+
+ // ... Rest of task code.
+ }
+
+ // Task to peek the data from the queue.
+ void vADifferentTask( void *pvParameters )
+ {
+ struct AMessage *pxRxedMessage;
+
+ if( xQueue != 0 )
+ {
+ // Peek a message on the created queue. Block for 10 ticks if a
+ // message is not immediately available.
+ if( xQueuePeek( xQueue, &( pxRxedMessage ), ( portTickType ) 10 ) )
+ {
+ // pcRxedMessage now points to the struct AMessage variable posted
+ // by vATask, but the item still remains on the queue.
+ }
+ }
+
+ // ... Rest of task code.
+ }
+
+ * \defgroup xQueueReceive xQueueReceive
+ * \ingroup QueueManagement
+ */
+#define xQueuePeek( xQueue, pvBuffer, xTicksToWait ) xQueueGenericReceive( ( xQueue ), ( pvBuffer ), ( xTicksToWait ), pdTRUE )
+
+/**
+ * queue. h
+ *
+ portBASE_TYPE xQueueReceive(
+ xQueueHandle xQueue,
+ void *pvBuffer,
+ portTickType xTicksToWait
+ );
+ *
+ * This is a macro that calls the xQueueGenericReceive() function.
+ *
+ * Receive an item from a queue. The item is received by copy so a buffer of
+ * adequate size must be provided. The number of bytes copied into the buffer
+ * was defined when the queue was created.
+ *
+ * Successfully received items are removed from the queue.
+ *
+ * This function must not be used in an interrupt service routine. See
+ * xQueueReceiveFromISR for an alternative that can.
+ *
+ * @param pxQueue The handle to the queue from which the item is to be
+ * received.
+ *
+ * @param pvBuffer Pointer to the buffer into which the received item will
+ * be copied.
+ *
+ * @param xTicksToWait The maximum amount of time the task should block
+ * waiting for an item to receive should the queue be empty at the time
+ * of the call. xQueueReceive() will return immediately if xTicksToWait
+ * is zero and the queue is empty. The time is defined in tick periods so the
+ * constant portTICK_RATE_MS should be used to convert to real time if this is
+ * required.
+ *
+ * @return pdTRUE if an item was successfully received from the queue,
+ * otherwise pdFALSE.
+ *
+ * Example usage:
+
+ struct AMessage
+ {
+ char ucMessageID;
+ char ucData[ 20 ];
+ } xMessage;
+
+ xQueueHandle xQueue;
+
+ // Task to create a queue and post a value.
+ void vATask( void *pvParameters )
+ {
+ struct AMessage *pxMessage;
+
+ // Create a queue capable of containing 10 pointers to AMessage structures.
+ // These should be passed by pointer as they contain a lot of data.
+ xQueue = xQueueCreate( 10, sizeof( struct AMessage * ) );
+ if( xQueue == 0 )
+ {
+ // Failed to create the queue.
+ }
+
+ // ...
+
+ // Send a pointer to a struct AMessage object. Don't block if the
+ // queue is already full.
+ pxMessage = & xMessage;
+ xQueueSend( xQueue, ( void * ) &pxMessage, ( portTickType ) 0 );
+
+ // ... Rest of task code.
+ }
+
+ // Task to receive from the queue.
+ void vADifferentTask( void *pvParameters )
+ {
+ struct AMessage *pxRxedMessage;
+
+ if( xQueue != 0 )
+ {
+ // Receive a message on the created queue. Block for 10 ticks if a
+ // message is not immediately available.
+ if( xQueueReceive( xQueue, &( pxRxedMessage ), ( portTickType ) 10 ) )
+ {
+ // pcRxedMessage now points to the struct AMessage variable posted
+ // by vATask.
+ }
+ }
+
+ // ... Rest of task code.
+ }
+
+ * \defgroup xQueueReceive xQueueReceive
+ * \ingroup QueueManagement
+ */
+#define xQueueReceive( xQueue, pvBuffer, xTicksToWait ) xQueueGenericReceive( ( xQueue ), ( pvBuffer ), ( xTicksToWait ), pdFALSE )
+
+
+/**
+ * queue. h
+ *
+ portBASE_TYPE xQueueGenericReceive(
+ xQueueHandle xQueue,
+ void *pvBuffer,
+ portTickType xTicksToWait
+ portBASE_TYPE xJustPeek
+ );
+ *
+ * It is preferred that the macro xQueueReceive() be used rather than calling
+ * this function directly.
+ *
+ * Receive an item from a queue. The item is received by copy so a buffer of
+ * adequate size must be provided. The number of bytes copied into the buffer
+ * was defined when the queue was created.
+ *
+ * This function must not be used in an interrupt service routine. See
+ * xQueueReceiveFromISR for an alternative that can.
+ *
+ * @param pxQueue The handle to the queue from which the item is to be
+ * received.
+ *
+ * @param pvBuffer Pointer to the buffer into which the received item will
+ * be copied.
+ *
+ * @param xTicksToWait The maximum amount of time the task should block
+ * waiting for an item to receive should the queue be empty at the time
+ * of the call. The time is defined in tick periods so the constant
+ * portTICK_RATE_MS should be used to convert to real time if this is required.
+ * xQueueGenericReceive() will return immediately if the queue is empty and
+ * xTicksToWait is 0.
+ *
+ * @param xJustPeek When set to true, the item received from the queue is not
+ * actually removed from the queue - meaning a subsequent call to
+ * xQueueReceive() will return the same item. When set to false, the item
+ * being received from the queue is also removed from the queue.
+ *
+ * @return pdTRUE if an item was successfully received from the queue,
+ * otherwise pdFALSE.
+ *
+ * Example usage:
+
+ struct AMessage
+ {
+ char ucMessageID;
+ char ucData[ 20 ];
+ } xMessage;
+
+ xQueueHandle xQueue;
+
+ // Task to create a queue and post a value.
+ void vATask( void *pvParameters )
+ {
+ struct AMessage *pxMessage;
+
+ // Create a queue capable of containing 10 pointers to AMessage structures.
+ // These should be passed by pointer as they contain a lot of data.
+ xQueue = xQueueCreate( 10, sizeof( struct AMessage * ) );
+ if( xQueue == 0 )
+ {
+ // Failed to create the queue.
+ }
+
+ // ...
+
+ // Send a pointer to a struct AMessage object. Don't block if the
+ // queue is already full.
+ pxMessage = & xMessage;
+ xQueueSend( xQueue, ( void * ) &pxMessage, ( portTickType ) 0 );
+
+ // ... Rest of task code.
+ }
+
+ // Task to receive from the queue.
+ void vADifferentTask( void *pvParameters )
+ {
+ struct AMessage *pxRxedMessage;
+
+ if( xQueue != 0 )
+ {
+ // Receive a message on the created queue. Block for 10 ticks if a
+ // message is not immediately available.
+ if( xQueueGenericReceive( xQueue, &( pxRxedMessage ), ( portTickType ) 10 ) )
+ {
+ // pcRxedMessage now points to the struct AMessage variable posted
+ // by vATask.
+ }
+ }
+
+ // ... Rest of task code.
+ }
+
+ * \defgroup xQueueReceive xQueueReceive
+ * \ingroup QueueManagement
+ */
+signed portBASE_TYPE xQueueGenericReceive( xQueueHandle xQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeek );
+
+/**
+ * queue. h
+ * unsigned portBASE_TYPE uxQueueMessagesWaiting( const xQueueHandle xQueue );
+ *
+ * Return the number of messages stored in a queue.
+ *
+ * @param xQueue A handle to the queue being queried.
+ *
+ * @return The number of messages available in the queue.
+ *
+ * \page uxQueueMessagesWaiting uxQueueMessagesWaiting
+ * \ingroup QueueManagement
+ */
+unsigned portBASE_TYPE uxQueueMessagesWaiting( const xQueueHandle xQueue );
+
+/**
+ * queue. h
+ * void vQueueDelete( xQueueHandle xQueue );
+ *
+ * Delete a queue - freeing all the memory allocated for storing of items
+ * placed on the queue.
+ *
+ * @param xQueue A handle to the queue to be deleted.
+ *
+ * \page vQueueDelete vQueueDelete
+ * \ingroup QueueManagement
+ */
+void vQueueDelete( xQueueHandle pxQueue );
+
+/**
+ * queue. h
+ *
+ portBASE_TYPE xQueueSendToFrontFromISR(
+ xQueueHandle pxQueue,
+ const void *pvItemToQueue,
+ portBASE_TYPE *pxHigherPriorityTaskWoken
+ );
+
+ *
+ * This is a macro that calls xQueueGenericSendFromISR().
+ *
+ * Post an item to the front of a queue. It is safe to use this macro from
+ * within an interrupt service routine.
+ *
+ * Items are queued by copy not reference so it is preferable to only
+ * queue small items, especially when called from an ISR. In most cases
+ * it would be preferable to store a pointer to the item being queued.
+ *
+ * @param xQueue The handle to the queue on which the item is to be posted.
+ *
+ * @param pvItemToQueue A pointer to the item that is to be placed on the
+ * queue. The size of the items the queue will hold was defined when the
+ * queue was created, so this many bytes will be copied from pvItemToQueue
+ * into the queue storage area.
+ *
+ * @param pxHigherPriorityTaskWoken xQueueSendToFrontFromISR() will set
+ * *pxHigherPriorityTaskWoken to pdTRUE if sending to the queue caused a task
+ * to unblock, and the unblocked task has a priority higher than the currently
+ * running task. If xQueueSendToFromFromISR() sets this value to pdTRUE then
+ * a context switch should be requested before the interrupt is exited.
+ *
+ * @return pdTRUE if the data was successfully sent to the queue, otherwise
+ * errQUEUE_FULL.
+ *
+ * Example usage for buffered IO (where the ISR can obtain more than one value
+ * per call):
+
+ void vBufferISR( void )
+ {
+ char cIn;
+ portBASE_TYPE xHigherPrioritTaskWoken;
+
+ // We have not woken a task at the start of the ISR.
+ xHigherPriorityTaskWoken = pdFALSE;
+
+ // Loop until the buffer is empty.
+ do
+ {
+ // Obtain a byte from the buffer.
+ cIn = portINPUT_BYTE( RX_REGISTER_ADDRESS );
+
+ // Post the byte.
+ xQueueSendToFrontFromISR( xRxQueue, &cIn, &xHigherPriorityTaskWoken );
+
+ } while( portINPUT_BYTE( BUFFER_COUNT ) );
+
+ // Now the buffer is empty we can switch context if necessary.
+ if( xHigherPriorityTaskWoken )
+ {
+ taskYIELD ();
+ }
+ }
+
+ *
+ * \defgroup xQueueSendFromISR xQueueSendFromISR
+ * \ingroup QueueManagement
+ */
+#define xQueueSendToFrontFromISR( pxQueue, pvItemToQueue, pxHigherPriorityTaskWoken ) xQueueGenericSendFromISR( ( pxQueue ), ( pvItemToQueue ), ( pxHigherPriorityTaskWoken ), queueSEND_TO_FRONT )
+
+
+/**
+ * queue. h
+ *
+ portBASE_TYPE xQueueSendToBackFromISR(
+ xQueueHandle pxQueue,
+ const void *pvItemToQueue,
+ portBASE_TYPE *pxHigherPriorityTaskWoken
+ );
+
+ *
+ * This is a macro that calls xQueueGenericSendFromISR().
+ *
+ * Post an item to the back of a queue. It is safe to use this macro from
+ * within an interrupt service routine.
+ *
+ * Items are queued by copy not reference so it is preferable to only
+ * queue small items, especially when called from an ISR. In most cases
+ * it would be preferable to store a pointer to the item being queued.
+ *
+ * @param xQueue The handle to the queue on which the item is to be posted.
+ *
+ * @param pvItemToQueue A pointer to the item that is to be placed on the
+ * queue. The size of the items the queue will hold was defined when the
+ * queue was created, so this many bytes will be copied from pvItemToQueue
+ * into the queue storage area.
+ *
+ * @param pxHigherPriorityTaskWoken xQueueSendToBackFromISR() will set
+ * *pxHigherPriorityTaskWoken to pdTRUE if sending to the queue caused a task
+ * to unblock, and the unblocked task has a priority higher than the currently
+ * running task. If xQueueSendToBackFromISR() sets this value to pdTRUE then
+ * a context switch should be requested before the interrupt is exited.
+ *
+ * @return pdTRUE if the data was successfully sent to the queue, otherwise
+ * errQUEUE_FULL.
+ *
+ * Example usage for buffered IO (where the ISR can obtain more than one value
+ * per call):
+
+ void vBufferISR( void )
+ {
+ char cIn;
+ portBASE_TYPE xHigherPriorityTaskWoken;
+
+ // We have not woken a task at the start of the ISR.
+ xHigherPriorityTaskWoken = pdFALSE;
+
+ // Loop until the buffer is empty.
+ do
+ {
+ // Obtain a byte from the buffer.
+ cIn = portINPUT_BYTE( RX_REGISTER_ADDRESS );
+
+ // Post the byte.
+ xQueueSendToBackFromISR( xRxQueue, &cIn, &xHigherPriorityTaskWoken );
+
+ } while( portINPUT_BYTE( BUFFER_COUNT ) );
+
+ // Now the buffer is empty we can switch context if necessary.
+ if( xHigherPriorityTaskWoken )
+ {
+ taskYIELD ();
+ }
+ }
+
+ *
+ * \defgroup xQueueSendFromISR xQueueSendFromISR
+ * \ingroup QueueManagement
+ */
+#define xQueueSendToBackFromISR( pxQueue, pvItemToQueue, pxHigherPriorityTaskWoken ) xQueueGenericSendFromISR( ( pxQueue ), ( pvItemToQueue ), ( pxHigherPriorityTaskWoken ), queueSEND_TO_BACK )
+
+/**
+ * queue. h
+ *
+ portBASE_TYPE xQueueSendFromISR(
+ xQueueHandle pxQueue,
+ const void *pvItemToQueue,
+ portBASE_TYPE *pxHigherPriorityTaskWoken
+ );
+
+ *
+ * This is a macro that calls xQueueGenericSendFromISR(). It is included
+ * for backward compatibility with versions of FreeRTOS.org that did not
+ * include the xQueueSendToBackFromISR() and xQueueSendToFrontFromISR()
+ * macros.
+ *
+ * Post an item to the back of a queue. It is safe to use this function from
+ * within an interrupt service routine.
+ *
+ * Items are queued by copy not reference so it is preferable to only
+ * queue small items, especially when called from an ISR. In most cases
+ * it would be preferable to store a pointer to the item being queued.
+ *
+ * @param xQueue The handle to the queue on which the item is to be posted.
+ *
+ * @param pvItemToQueue A pointer to the item that is to be placed on the
+ * queue. The size of the items the queue will hold was defined when the
+ * queue was created, so this many bytes will be copied from pvItemToQueue
+ * into the queue storage area.
+ *
+ * @param pxHigherPriorityTaskWoken xQueueSendFromISR() will set
+ * *pxHigherPriorityTaskWoken to pdTRUE if sending to the queue caused a task
+ * to unblock, and the unblocked task has a priority higher than the currently
+ * running task. If xQueueSendFromISR() sets this value to pdTRUE then
+ * a context switch should be requested before the interrupt is exited.
+ *
+ * @return pdTRUE if the data was successfully sent to the queue, otherwise
+ * errQUEUE_FULL.
+ *
+ * Example usage for buffered IO (where the ISR can obtain more than one value
+ * per call):
+
+ void vBufferISR( void )
+ {
+ char cIn;
+ portBASE_TYPE xHigherPriorityTaskWoken;
+
+ // We have not woken a task at the start of the ISR.
+ xHigherPriorityTaskWoken = pdFALSE;
+
+ // Loop until the buffer is empty.
+ do
+ {
+ // Obtain a byte from the buffer.
+ cIn = portINPUT_BYTE( RX_REGISTER_ADDRESS );
+
+ // Post the byte.
+ xQueueSendFromISR( xRxQueue, &cIn, &xHigherPriorityTaskWoken );
+
+ } while( portINPUT_BYTE( BUFFER_COUNT ) );
+
+ // Now the buffer is empty we can switch context if necessary.
+ if( xHigherPriorityTaskWoken )
+ {
+ // Actual macro used here is port specific.
+ taskYIELD_FROM_ISR ();
+ }
+ }
+
+ *
+ * \defgroup xQueueSendFromISR xQueueSendFromISR
+ * \ingroup QueueManagement
+ */
+#define xQueueSendFromISR( pxQueue, pvItemToQueue, pxHigherPriorityTaskWoken ) xQueueGenericSendFromISR( ( pxQueue ), ( pvItemToQueue ), ( pxHigherPriorityTaskWoken ), queueSEND_TO_BACK )
+
+/**
+ * queue. h
+ *
+ portBASE_TYPE xQueueGenericSendFromISR(
+ xQueueHandle pxQueue,
+ const void *pvItemToQueue,
+ portBASE_TYPE *pxHigherPriorityTaskWoken,
+ portBASE_TYPE xCopyPosition
+ );
+
+ *
+ * It is preferred that the macros xQueueSendFromISR(),
+ * xQueueSendToFrontFromISR() and xQueueSendToBackFromISR() be used in place
+ * of calling this function directly.
+ *
+ * Post an item on a queue. It is safe to use this function from within an
+ * interrupt service routine.
+ *
+ * Items are queued by copy not reference so it is preferable to only
+ * queue small items, especially when called from an ISR. In most cases
+ * it would be preferable to store a pointer to the item being queued.
+ *
+ * @param xQueue The handle to the queue on which the item is to be posted.
+ *
+ * @param pvItemToQueue A pointer to the item that is to be placed on the
+ * queue. The size of the items the queue will hold was defined when the
+ * queue was created, so this many bytes will be copied from pvItemToQueue
+ * into the queue storage area.
+ *
+ * @param pxHigherPriorityTaskWoken xQueueGenericSendFromISR() will set
+ * *pxHigherPriorityTaskWoken to pdTRUE if sending to the queue caused a task
+ * to unblock, and the unblocked task has a priority higher than the currently
+ * running task. If xQueueGenericSendFromISR() sets this value to pdTRUE then
+ * a context switch should be requested before the interrupt is exited.
+ *
+ * @param xCopyPosition Can take the value queueSEND_TO_BACK to place the
+ * item at the back of the queue, or queueSEND_TO_FRONT to place the item
+ * at the front of the queue (for high priority messages).
+ *
+ * @return pdTRUE if the data was successfully sent to the queue, otherwise
+ * errQUEUE_FULL.
+ *
+ * Example usage for buffered IO (where the ISR can obtain more than one value
+ * per call):
+
+ void vBufferISR( void )
+ {
+ char cIn;
+ portBASE_TYPE xHigherPriorityTaskWokenByPost;
+
+ // We have not woken a task at the start of the ISR.
+ xHigherPriorityTaskWokenByPost = pdFALSE;
+
+ // Loop until the buffer is empty.
+ do
+ {
+ // Obtain a byte from the buffer.
+ cIn = portINPUT_BYTE( RX_REGISTER_ADDRESS );
+
+ // Post each byte.
+ xQueueGenericSendFromISR( xRxQueue, &cIn, &xHigherPriorityTaskWokenByPost, queueSEND_TO_BACK );
+
+ } while( portINPUT_BYTE( BUFFER_COUNT ) );
+
+ // Now the buffer is empty we can switch context if necessary. Note that the
+ // name of the yield function required is port specific.
+ if( xHigherPriorityTaskWokenByPost )
+ {
+ taskYIELD_YIELD_FROM_ISR();
+ }
+ }
+
+ *
+ * \defgroup xQueueSendFromISR xQueueSendFromISR
+ * \ingroup QueueManagement
+ */
+signed portBASE_TYPE xQueueGenericSendFromISR( xQueueHandle pxQueue, const void * const pvItemToQueue, signed portBASE_TYPE *pxHigherPriorityTaskWoken, portBASE_TYPE xCopyPosition );
+
+/**
+ * queue. h
+ *
+ portBASE_TYPE xQueueReceiveFromISR(
+ xQueueHandle pxQueue,
+ void *pvBuffer,
+ portBASE_TYPE *pxTaskWoken
+ );
+ *
+ *
+ * Receive an item from a queue. It is safe to use this function from within an
+ * interrupt service routine.
+ *
+ * @param pxQueue The handle to the queue from which the item is to be
+ * received.
+ *
+ * @param pvBuffer Pointer to the buffer into which the received item will
+ * be copied.
+ *
+ * @param pxTaskWoken A task may be blocked waiting for space to become
+ * available on the queue. If xQueueReceiveFromISR causes such a task to
+ * unblock *pxTaskWoken will get set to pdTRUE, otherwise *pxTaskWoken will
+ * remain unchanged.
+ *
+ * @return pdTRUE if an item was successfully received from the queue,
+ * otherwise pdFALSE.
+ *
+ * Example usage:
+
+
+ xQueueHandle xQueue;
+
+ // Function to create a queue and post some values.
+ void vAFunction( void *pvParameters )
+ {
+ char cValueToPost;
+ const portTickType xBlockTime = ( portTickType )0xff;
+
+ // Create a queue capable of containing 10 characters.
+ xQueue = xQueueCreate( 10, sizeof( char ) );
+ if( xQueue == 0 )
+ {
+ // Failed to create the queue.
+ }
+
+ // ...
+
+ // Post some characters that will be used within an ISR. If the queue
+ // is full then this task will block for xBlockTime ticks.
+ cValueToPost = 'a';
+ xQueueSend( xQueue, ( void * ) &cValueToPost, xBlockTime );
+ cValueToPost = 'b';
+ xQueueSend( xQueue, ( void * ) &cValueToPost, xBlockTime );
+
+ // ... keep posting characters ... this task may block when the queue
+ // becomes full.
+
+ cValueToPost = 'c';
+ xQueueSend( xQueue, ( void * ) &cValueToPost, xBlockTime );
+ }
+
+ // ISR that outputs all the characters received on the queue.
+ void vISR_Routine( void )
+ {
+ portBASE_TYPE xTaskWokenByReceive = pdFALSE;
+ char cRxedChar;
+
+ while( xQueueReceiveFromISR( xQueue, ( void * ) &cRxedChar, &xTaskWokenByReceive) )
+ {
+ // A character was received. Output the character now.
+ vOutputCharacter( cRxedChar );
+
+ // If removing the character from the queue woke the task that was
+ // posting onto the queue cTaskWokenByReceive will have been set to
+ // pdTRUE. No matter how many times this loop iterates only one
+ // task will be woken.
+ }
+
+ if( cTaskWokenByPost != ( char ) pdFALSE;
+ {
+ taskYIELD ();
+ }
+ }
+
+ * \defgroup xQueueReceiveFromISR xQueueReceiveFromISR
+ * \ingroup QueueManagement
+ */
+signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, void * const pvBuffer, signed portBASE_TYPE *pxTaskWoken );
+
+/*
+ * Utilities to query queue that are safe to use from an ISR. These utilities
+ * should be used only from witin an ISR, or within a critical section.
+ */
+signed portBASE_TYPE xQueueIsQueueEmptyFromISR( const xQueueHandle pxQueue );
+signed portBASE_TYPE xQueueIsQueueFullFromISR( const xQueueHandle pxQueue );
+unsigned portBASE_TYPE uxQueueMessagesWaitingFromISR( const xQueueHandle pxQueue );
+
+
+/*
+ * xQueueAltGenericSend() is an alternative version of xQueueGenericSend().
+ * Likewise xQueueAltGenericReceive() is an alternative version of
+ * xQueueGenericReceive().
+ *
+ * The source code that implements the alternative (Alt) API is much
+ * simpler because it executes everything from within a critical section.
+ * This is the approach taken by many other RTOSes, but FreeRTOS.org has the
+ * preferred fully featured API too. The fully featured API has more
+ * complex code that takes longer to execute, but makes much less use of
+ * critical sections. Therefore the alternative API sacrifices interrupt
+ * responsiveness to gain execution speed, whereas the fully featured API
+ * sacrifices execution speed to ensure better interrupt responsiveness.
+ */
+signed portBASE_TYPE xQueueAltGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition );
+signed portBASE_TYPE xQueueAltGenericReceive( xQueueHandle pxQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking );
+#define xQueueAltSendToFront( xQueue, pvItemToQueue, xTicksToWait ) xQueueAltGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_FRONT )
+#define xQueueAltSendToBack( xQueue, pvItemToQueue, xTicksToWait ) xQueueAltGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK )
+#define xQueueAltReceive( xQueue, pvBuffer, xTicksToWait ) xQueueAltGenericReceive( ( xQueue ), ( pvBuffer ), ( xTicksToWait ), pdFALSE )
+#define xQueueAltPeek( xQueue, pvBuffer, xTicksToWait ) xQueueAltGenericReceive( ( xQueue ), ( pvBuffer ), ( xTicksToWait ), pdTRUE )
+
+/*
+ * The functions defined above are for passing data to and from tasks. The
+ * functions below are the equivalents for passing data to and from
+ * co-routines.
+ *
+ * These functions are called from the co-routine macro implementation and
+ * should not be called directly from application code. Instead use the macro
+ * wrappers defined within croutine.h.
+ */
+signed portBASE_TYPE xQueueCRSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xCoRoutinePreviouslyWoken );
+signed portBASE_TYPE xQueueCRReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxTaskWoken );
+signed portBASE_TYPE xQueueCRSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait );
+signed portBASE_TYPE xQueueCRReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait );
+
+/*
+ * For internal use only. Use xSemaphoreCreateMutex() or
+ * xSemaphoreCreateCounting() instead of calling these functions directly.
+ */
+xQueueHandle xQueueCreateMutex( void );
+xQueueHandle xQueueCreateCountingSemaphore( unsigned portBASE_TYPE uxCountValue, unsigned portBASE_TYPE uxInitialCount );
+
+/*
+ * For internal use only. Use xSemaphoreTakeMutexRecursive() or
+ * xSemaphoreGiveMutexRecursive() instead of calling these functions directly.
+ */
+portBASE_TYPE xQueueTakeMutexRecursive( xQueueHandle pxMutex, portTickType xBlockTime );
+portBASE_TYPE xQueueGiveMutexRecursive( xQueueHandle pxMutex );
+
+/*
+ * The registry is provided as a means for kernel aware debuggers to
+ * locate queues, semaphores and mutexes. Call vQueueAddToRegistry() add
+ * a queue, semaphore or mutex handle to the registry if you want the handle
+ * to be available to a kernel aware debugger. If you are not using a kernel
+ * aware debugger then this function can be ignored.
+ *
+ * configQUEUE_REGISTRY_SIZE defines the maximum number of handles the
+ * registry can hold. configQUEUE_REGISTRY_SIZE must be greater than 0
+ * within FreeRTOSConfig.h for the registry to be available. Its value
+ * does not effect the number of queues, semaphores and mutexes that can be
+ * created - just the number that the registry can hold.
+ *
+ * @param xQueue The handle of the queue being added to the registry. This
+ * is the handle returned by a call to xQueueCreate(). Semaphore and mutex
+ * handles can also be passed in here.
+ *
+ * @param pcName The name to be associated with the handle. This is the
+ * name that the kernel aware debugger will display.
+ */
+#if configQUEUE_REGISTRY_SIZE > 0U
+ void vQueueAddToRegistry( xQueueHandle xQueue, signed char *pcName );
+#endif
+
+/* Not a public API function, hence the 'Restricted' in the name. */
+void vQueueWaitForMessageRestricted( xQueueHandle pxQueue, portTickType xTicksToWait );
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* QUEUE_H */
+
diff --git a/Libmaple/libmaple/libraries/FreeRTOS/utility/semphr.h b/Libmaple/libmaple/libraries/FreeRTOS/utility/semphr.h
index 0130f1d7..7a9e83fa 100644
--- a/Libmaple/libmaple/libraries/FreeRTOS/utility/semphr.h
+++ b/Libmaple/libmaple/libraries/FreeRTOS/utility/semphr.h
@@ -1,717 +1,717 @@
-/*
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.
-
-
- FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:
- Atollic AB - Atollic provides professional embedded systems development
- tools for C/C++ development, code analysis and test automation.
- See http://www.atollic.com
-
-
- ***************************************************************************
- * *
- * FreeRTOS tutorial books are available in pdf and paperback. *
- * Complete, revised, and edited pdf reference manuals are also *
- * available. *
- * *
- * Purchasing FreeRTOS documentation will not only help you, by *
- * ensuring you get running as quickly as possible and with an *
- * in-depth knowledge of how to use FreeRTOS, it will also help *
- * the FreeRTOS project to continue with its mission of providing *
- * professional grade, cross platform, de facto standard solutions *
- * for microcontrollers - completely free of charge! *
- * *
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
- * *
- * Thank you for using FreeRTOS, and thank you for your support! *
- * *
- ***************************************************************************
-
-
- This file is part of the FreeRTOS distribution.
-
- FreeRTOS is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License (version 2) as published by the
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
- >>>NOTE<<< The modification to the GPL is included to allow you to
- distribute a combined work that includes FreeRTOS without being obliged to
- provide the source code for proprietary components outside of the FreeRTOS
- kernel. FreeRTOS is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- more details. You should have received a copy of the GNU General Public
- License and the FreeRTOS license exception along with FreeRTOS; if not it
- can be viewed here: http://www.freertos.org/a00114.html and also obtained
- by writing to Richard Barry, contact details for whom are available on the
- FreeRTOS WEB site.
-
- 1 tab == 4 spaces!
-
- http://www.FreeRTOS.org - Documentation, latest information, license and
- contact details.
-
- http://www.SafeRTOS.com - A version that is certified for use in safety
- critical systems.
-
- http://www.OpenRTOS.com - Commercial support, development, porting,
- licensing and training services.
-*/
-
-#ifndef SEMAPHORE_H
-#define SEMAPHORE_H
-
-#ifndef INC_FREERTOS_H
- #error "#include FreeRTOS.h" must appear in source files before "#include semphr.h"
-#endif
-
-#include "queue.h"
-
-typedef xQueueHandle xSemaphoreHandle;
-
-#define semBINARY_SEMAPHORE_QUEUE_LENGTH ( ( unsigned char ) 1U )
-#define semSEMAPHORE_QUEUE_ITEM_LENGTH ( ( unsigned char ) 0U )
-#define semGIVE_BLOCK_TIME ( ( portTickType ) 0U )
-
-
-/**
- * semphr. h
- * vSemaphoreCreateBinary( xSemaphoreHandle xSemaphore )
- *
- * Macro that implements a semaphore by using the existing queue mechanism.
- * The queue length is 1 as this is a binary semaphore. The data size is 0
- * as we don't want to actually store any data - we just want to know if the
- * queue is empty or full.
- *
- * This type of semaphore can be used for pure synchronisation between tasks or
- * between an interrupt and a task. The semaphore need not be given back once
- * obtained, so one task/interrupt can continuously 'give' the semaphore while
- * another continuously 'takes' the semaphore. For this reason this type of
- * semaphore does not use a priority inheritance mechanism. For an alternative
- * that does use priority inheritance see xSemaphoreCreateMutex().
- *
- * @param xSemaphore Handle to the created semaphore. Should be of type xSemaphoreHandle.
- *
- * Example usage:
-
- xSemaphoreHandle xSemaphore;
-
- void vATask( void * pvParameters )
- {
- // Semaphore cannot be used before a call to vSemaphoreCreateBinary ().
- // This is a macro so pass the variable in directly.
- vSemaphoreCreateBinary( xSemaphore );
-
- if( xSemaphore != NULL )
- {
- // The semaphore was created successfully.
- // The semaphore can now be used.
- }
- }
-
- * \defgroup vSemaphoreCreateBinary vSemaphoreCreateBinary
- * \ingroup Semaphores
- */
-#define vSemaphoreCreateBinary( xSemaphore ) { \
- ( xSemaphore ) = xQueueCreate( ( unsigned portBASE_TYPE ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH ); \
- if( ( xSemaphore ) != NULL ) \
- { \
- xSemaphoreGive( ( xSemaphore ) ); \
- } \
- }
-
-/**
- * semphr. h
- * xSemaphoreTake(
- * xSemaphoreHandle xSemaphore,
- * portTickType xBlockTime
- * )
- *
- * Macro to obtain a semaphore. The semaphore must have previously been
- * created with a call to vSemaphoreCreateBinary(), xSemaphoreCreateMutex() or
- * xSemaphoreCreateCounting().
- *
- * @param xSemaphore A handle to the semaphore being taken - obtained when
- * the semaphore was created.
- *
- * @param xBlockTime The time in ticks to wait for the semaphore to become
- * available. The macro portTICK_RATE_MS can be used to convert this to a
- * real time. A block time of zero can be used to poll the semaphore. A block
- * time of portMAX_DELAY can be used to block indefinitely (provided
- * INCLUDE_vTaskSuspend is set to 1 in FreeRTOSConfig.h).
- *
- * @return pdTRUE if the semaphore was obtained. pdFALSE
- * if xBlockTime expired without the semaphore becoming available.
- *
- * Example usage:
-
- xSemaphoreHandle xSemaphore = NULL;
-
- // A task that creates a semaphore.
- void vATask( void * pvParameters )
- {
- // Create the semaphore to guard a shared resource.
- vSemaphoreCreateBinary( xSemaphore );
- }
-
- // A task that uses the semaphore.
- void vAnotherTask( void * pvParameters )
- {
- // ... Do other things.
-
- if( xSemaphore != NULL )
- {
- // See if we can obtain the semaphore. If the semaphore is not available
- // wait 10 ticks to see if it becomes free.
- if( xSemaphoreTake( xSemaphore, ( portTickType ) 10 ) == pdTRUE )
- {
- // We were able to obtain the semaphore and can now access the
- // shared resource.
-
- // ...
-
- // We have finished accessing the shared resource. Release the
- // semaphore.
- xSemaphoreGive( xSemaphore );
- }
- else
- {
- // We could not obtain the semaphore and can therefore not access
- // the shared resource safely.
- }
- }
- }
-
- * \defgroup xSemaphoreTake xSemaphoreTake
- * \ingroup Semaphores
- */
-#define xSemaphoreTake( xSemaphore, xBlockTime ) xQueueGenericReceive( ( xQueueHandle ) ( xSemaphore ), NULL, ( xBlockTime ), pdFALSE )
-
-/**
- * semphr. h
- * xSemaphoreTakeRecursive(
- * xSemaphoreHandle xMutex,
- * portTickType xBlockTime
- * )
- *
- * Macro to recursively obtain, or 'take', a mutex type semaphore.
- * The mutex must have previously been created using a call to
- * xSemaphoreCreateRecursiveMutex();
- *
- * configUSE_RECURSIVE_MUTEXES must be set to 1 in FreeRTOSConfig.h for this
- * macro to be available.
- *
- * This macro must not be used on mutexes created using xSemaphoreCreateMutex().
- *
- * A mutex used recursively can be 'taken' repeatedly by the owner. The mutex
- * doesn't become available again until the owner has called
- * xSemaphoreGiveRecursive() for each successful 'take' request. For example,
- * if a task successfully 'takes' the same mutex 5 times then the mutex will
- * not be available to any other task until it has also 'given' the mutex back
- * exactly five times.
- *
- * @param xMutex A handle to the mutex being obtained. This is the
- * handle returned by xSemaphoreCreateRecursiveMutex();
- *
- * @param xBlockTime The time in ticks to wait for the semaphore to become
- * available. The macro portTICK_RATE_MS can be used to convert this to a
- * real time. A block time of zero can be used to poll the semaphore. If
- * the task already owns the semaphore then xSemaphoreTakeRecursive() will
- * return immediately no matter what the value of xBlockTime.
- *
- * @return pdTRUE if the semaphore was obtained. pdFALSE if xBlockTime
- * expired without the semaphore becoming available.
- *
- * Example usage:
-
- xSemaphoreHandle xMutex = NULL;
-
- // A task that creates a mutex.
- void vATask( void * pvParameters )
- {
- // Create the mutex to guard a shared resource.
- xMutex = xSemaphoreCreateRecursiveMutex();
- }
-
- // A task that uses the mutex.
- void vAnotherTask( void * pvParameters )
- {
- // ... Do other things.
-
- if( xMutex != NULL )
- {
- // See if we can obtain the mutex. If the mutex is not available
- // wait 10 ticks to see if it becomes free.
- if( xSemaphoreTakeRecursive( xSemaphore, ( portTickType ) 10 ) == pdTRUE )
- {
- // We were able to obtain the mutex and can now access the
- // shared resource.
-
- // ...
- // For some reason due to the nature of the code further calls to
- // xSemaphoreTakeRecursive() are made on the same mutex. In real
- // code these would not be just sequential calls as this would make
- // no sense. Instead the calls are likely to be buried inside
- // a more complex call structure.
- xSemaphoreTakeRecursive( xMutex, ( portTickType ) 10 );
- xSemaphoreTakeRecursive( xMutex, ( portTickType ) 10 );
-
- // The mutex has now been 'taken' three times, so will not be
- // available to another task until it has also been given back
- // three times. Again it is unlikely that real code would have
- // these calls sequentially, but instead buried in a more complex
- // call structure. This is just for illustrative purposes.
- xSemaphoreGiveRecursive( xMutex );
- xSemaphoreGiveRecursive( xMutex );
- xSemaphoreGiveRecursive( xMutex );
-
- // Now the mutex can be taken by other tasks.
- }
- else
- {
- // We could not obtain the mutex and can therefore not access
- // the shared resource safely.
- }
- }
- }
-
- * \defgroup xSemaphoreTakeRecursive xSemaphoreTakeRecursive
- * \ingroup Semaphores
- */
-#define xSemaphoreTakeRecursive( xMutex, xBlockTime ) xQueueTakeMutexRecursive( ( xMutex ), ( xBlockTime ) )
-
-
-/*
- * xSemaphoreAltTake() is an alternative version of xSemaphoreTake().
- *
- * The source code that implements the alternative (Alt) API is much
- * simpler because it executes everything from within a critical section.
- * This is the approach taken by many other RTOSes, but FreeRTOS.org has the
- * preferred fully featured API too. The fully featured API has more
- * complex code that takes longer to execute, but makes much less use of
- * critical sections. Therefore the alternative API sacrifices interrupt
- * responsiveness to gain execution speed, whereas the fully featured API
- * sacrifices execution speed to ensure better interrupt responsiveness.
- */
-#define xSemaphoreAltTake( xSemaphore, xBlockTime ) xQueueAltGenericReceive( ( xQueueHandle ) ( xSemaphore ), NULL, ( xBlockTime ), pdFALSE )
-
-/**
- * semphr. h
- * xSemaphoreGive( xSemaphoreHandle xSemaphore )
- *
- * Macro to release a semaphore. The semaphore must have previously been
- * created with a call to vSemaphoreCreateBinary(), xSemaphoreCreateMutex() or
- * xSemaphoreCreateCounting(). and obtained using sSemaphoreTake().
- *
- * This macro must not be used from an ISR. See xSemaphoreGiveFromISR () for
- * an alternative which can be used from an ISR.
- *
- * This macro must also not be used on semaphores created using
- * xSemaphoreCreateRecursiveMutex().
- *
- * @param xSemaphore A handle to the semaphore being released. This is the
- * handle returned when the semaphore was created.
- *
- * @return pdTRUE if the semaphore was released. pdFALSE if an error occurred.
- * Semaphores are implemented using queues. An error can occur if there is
- * no space on the queue to post a message - indicating that the
- * semaphore was not first obtained correctly.
- *
- * Example usage:
-
- xSemaphoreHandle xSemaphore = NULL;
-
- void vATask( void * pvParameters )
- {
- // Create the semaphore to guard a shared resource.
- vSemaphoreCreateBinary( xSemaphore );
-
- if( xSemaphore != NULL )
- {
- if( xSemaphoreGive( xSemaphore ) != pdTRUE )
- {
- // We would expect this call to fail because we cannot give
- // a semaphore without first "taking" it!
- }
-
- // Obtain the semaphore - don't block if the semaphore is not
- // immediately available.
- if( xSemaphoreTake( xSemaphore, ( portTickType ) 0 ) )
- {
- // We now have the semaphore and can access the shared resource.
-
- // ...
-
- // We have finished accessing the shared resource so can free the
- // semaphore.
- if( xSemaphoreGive( xSemaphore ) != pdTRUE )
- {
- // We would not expect this call to fail because we must have
- // obtained the semaphore to get here.
- }
- }
- }
- }
-
- * \defgroup xSemaphoreGive xSemaphoreGive
- * \ingroup Semaphores
- */
-#define xSemaphoreGive( xSemaphore ) xQueueGenericSend( ( xQueueHandle ) ( xSemaphore ), NULL, semGIVE_BLOCK_TIME, queueSEND_TO_BACK )
-
-/**
- * semphr. h
- * xSemaphoreGiveRecursive( xSemaphoreHandle xMutex )
- *
- * Macro to recursively release, or 'give', a mutex type semaphore.
- * The mutex must have previously been created using a call to
- * xSemaphoreCreateRecursiveMutex();
- *
- * configUSE_RECURSIVE_MUTEXES must be set to 1 in FreeRTOSConfig.h for this
- * macro to be available.
- *
- * This macro must not be used on mutexes created using xSemaphoreCreateMutex().
- *
- * A mutex used recursively can be 'taken' repeatedly by the owner. The mutex
- * doesn't become available again until the owner has called
- * xSemaphoreGiveRecursive() for each successful 'take' request. For example,
- * if a task successfully 'takes' the same mutex 5 times then the mutex will
- * not be available to any other task until it has also 'given' the mutex back
- * exactly five times.
- *
- * @param xMutex A handle to the mutex being released, or 'given'. This is the
- * handle returned by xSemaphoreCreateMutex();
- *
- * @return pdTRUE if the semaphore was given.
- *
- * Example usage:
-
- xSemaphoreHandle xMutex = NULL;
-
- // A task that creates a mutex.
- void vATask( void * pvParameters )
- {
- // Create the mutex to guard a shared resource.
- xMutex = xSemaphoreCreateRecursiveMutex();
- }
-
- // A task that uses the mutex.
- void vAnotherTask( void * pvParameters )
- {
- // ... Do other things.
-
- if( xMutex != NULL )
- {
- // See if we can obtain the mutex. If the mutex is not available
- // wait 10 ticks to see if it becomes free.
- if( xSemaphoreTakeRecursive( xMutex, ( portTickType ) 10 ) == pdTRUE )
- {
- // We were able to obtain the mutex and can now access the
- // shared resource.
-
- // ...
- // For some reason due to the nature of the code further calls to
- // xSemaphoreTakeRecursive() are made on the same mutex. In real
- // code these would not be just sequential calls as this would make
- // no sense. Instead the calls are likely to be buried inside
- // a more complex call structure.
- xSemaphoreTakeRecursive( xMutex, ( portTickType ) 10 );
- xSemaphoreTakeRecursive( xMutex, ( portTickType ) 10 );
-
- // The mutex has now been 'taken' three times, so will not be
- // available to another task until it has also been given back
- // three times. Again it is unlikely that real code would have
- // these calls sequentially, it would be more likely that the calls
- // to xSemaphoreGiveRecursive() would be called as a call stack
- // unwound. This is just for demonstrative purposes.
- xSemaphoreGiveRecursive( xMutex );
- xSemaphoreGiveRecursive( xMutex );
- xSemaphoreGiveRecursive( xMutex );
-
- // Now the mutex can be taken by other tasks.
- }
- else
- {
- // We could not obtain the mutex and can therefore not access
- // the shared resource safely.
- }
- }
- }
-
- * \defgroup xSemaphoreGiveRecursive xSemaphoreGiveRecursive
- * \ingroup Semaphores
- */
-#define xSemaphoreGiveRecursive( xMutex ) xQueueGiveMutexRecursive( ( xMutex ) )
-
-/*
- * xSemaphoreAltGive() is an alternative version of xSemaphoreGive().
- *
- * The source code that implements the alternative (Alt) API is much
- * simpler because it executes everything from within a critical section.
- * This is the approach taken by many other RTOSes, but FreeRTOS.org has the
- * preferred fully featured API too. The fully featured API has more
- * complex code that takes longer to execute, but makes much less use of
- * critical sections. Therefore the alternative API sacrifices interrupt
- * responsiveness to gain execution speed, whereas the fully featured API
- * sacrifices execution speed to ensure better interrupt responsiveness.
- */
-#define xSemaphoreAltGive( xSemaphore ) xQueueAltGenericSend( ( xQueueHandle ) ( xSemaphore ), NULL, semGIVE_BLOCK_TIME, queueSEND_TO_BACK )
-
-/**
- * semphr. h
- *
- xSemaphoreGiveFromISR(
- xSemaphoreHandle xSemaphore,
- signed portBASE_TYPE *pxHigherPriorityTaskWoken
- )
- *
- * Macro to release a semaphore. The semaphore must have previously been
- * created with a call to vSemaphoreCreateBinary() or xSemaphoreCreateCounting().
- *
- * Mutex type semaphores (those created using a call to xSemaphoreCreateMutex())
- * must not be used with this macro.
- *
- * This macro can be used from an ISR.
- *
- * @param xSemaphore A handle to the semaphore being released. This is the
- * handle returned when the semaphore was created.
- *
- * @param pxHigherPriorityTaskWoken xSemaphoreGiveFromISR() will set
- * *pxHigherPriorityTaskWoken to pdTRUE if giving the semaphore caused a task
- * to unblock, and the unblocked task has a priority higher than the currently
- * running task. If xSemaphoreGiveFromISR() sets this value to pdTRUE then
- * a context switch should be requested before the interrupt is exited.
- *
- * @return pdTRUE if the semaphore was successfully given, otherwise errQUEUE_FULL.
- *
- * Example usage:
-
- \#define LONG_TIME 0xffff
- \#define TICKS_TO_WAIT 10
- xSemaphoreHandle xSemaphore = NULL;
-
- // Repetitive task.
- void vATask( void * pvParameters )
- {
- for( ;; )
- {
- // We want this task to run every 10 ticks of a timer. The semaphore
- // was created before this task was started.
-
- // Block waiting for the semaphore to become available.
- if( xSemaphoreTake( xSemaphore, LONG_TIME ) == pdTRUE )
- {
- // It is time to execute.
-
- // ...
-
- // We have finished our task. Return to the top of the loop where
- // we will block on the semaphore until it is time to execute
- // again. Note when using the semaphore for synchronisation with an
- // ISR in this manner there is no need to 'give' the semaphore back.
- }
- }
- }
-
- // Timer ISR
- void vTimerISR( void * pvParameters )
- {
- static unsigned char ucLocalTickCount = 0;
- static signed portBASE_TYPE xHigherPriorityTaskWoken;
-
- // A timer tick has occurred.
-
- // ... Do other time functions.
-
- // Is it time for vATask () to run?
- xHigherPriorityTaskWoken = pdFALSE;
- ucLocalTickCount++;
- if( ucLocalTickCount >= TICKS_TO_WAIT )
- {
- // Unblock the task by releasing the semaphore.
- xSemaphoreGiveFromISR( xSemaphore, &xHigherPriorityTaskWoken );
-
- // Reset the count so we release the semaphore again in 10 ticks time.
- ucLocalTickCount = 0;
- }
-
- if( xHigherPriorityTaskWoken != pdFALSE )
- {
- // We can force a context switch here. Context switching from an
- // ISR uses port specific syntax. Check the demo task for your port
- // to find the syntax required.
- }
- }
-
- * \defgroup xSemaphoreGiveFromISR xSemaphoreGiveFromISR
- * \ingroup Semaphores
- */
-#define xSemaphoreGiveFromISR( xSemaphore, pxHigherPriorityTaskWoken ) xQueueGenericSendFromISR( ( xQueueHandle ) ( xSemaphore ), NULL, ( pxHigherPriorityTaskWoken ), queueSEND_TO_BACK )
-
-/**
- * semphr. h
- * xSemaphoreHandle xSemaphoreCreateMutex( void )
- *
- * Macro that implements a mutex semaphore by using the existing queue
- * mechanism.
- *
- * Mutexes created using this macro can be accessed using the xSemaphoreTake()
- * and xSemaphoreGive() macros. The xSemaphoreTakeRecursive() and
- * xSemaphoreGiveRecursive() macros should not be used.
- *
- * This type of semaphore uses a priority inheritance mechanism so a task
- * 'taking' a semaphore MUST ALWAYS 'give' the semaphore back once the
- * semaphore it is no longer required.
- *
- * Mutex type semaphores cannot be used from within interrupt service routines.
- *
- * See vSemaphoreCreateBinary() for an alternative implementation that can be
- * used for pure synchronisation (where one task or interrupt always 'gives' the
- * semaphore and another always 'takes' the semaphore) and from within interrupt
- * service routines.
- *
- * @return xSemaphore Handle to the created mutex semaphore. Should be of type
- * xSemaphoreHandle.
- *
- * Example usage:
-
- xSemaphoreHandle xSemaphore;
-
- void vATask( void * pvParameters )
- {
- // Semaphore cannot be used before a call to xSemaphoreCreateMutex().
- // This is a macro so pass the variable in directly.
- xSemaphore = xSemaphoreCreateMutex();
-
- if( xSemaphore != NULL )
- {
- // The semaphore was created successfully.
- // The semaphore can now be used.
- }
- }
-
- * \defgroup vSemaphoreCreateMutex vSemaphoreCreateMutex
- * \ingroup Semaphores
- */
-#define xSemaphoreCreateMutex() xQueueCreateMutex()
-
-
-/**
- * semphr. h
- * xSemaphoreHandle xSemaphoreCreateRecursiveMutex( void )
- *
- * Macro that implements a recursive mutex by using the existing queue
- * mechanism.
- *
- * Mutexes created using this macro can be accessed using the
- * xSemaphoreTakeRecursive() and xSemaphoreGiveRecursive() macros. The
- * xSemaphoreTake() and xSemaphoreGive() macros should not be used.
- *
- * A mutex used recursively can be 'taken' repeatedly by the owner. The mutex
- * doesn't become available again until the owner has called
- * xSemaphoreGiveRecursive() for each successful 'take' request. For example,
- * if a task successfully 'takes' the same mutex 5 times then the mutex will
- * not be available to any other task until it has also 'given' the mutex back
- * exactly five times.
- *
- * This type of semaphore uses a priority inheritance mechanism so a task
- * 'taking' a semaphore MUST ALWAYS 'give' the semaphore back once the
- * semaphore it is no longer required.
- *
- * Mutex type semaphores cannot be used from within interrupt service routines.
- *
- * See vSemaphoreCreateBinary() for an alternative implementation that can be
- * used for pure synchronisation (where one task or interrupt always 'gives' the
- * semaphore and another always 'takes' the semaphore) and from within interrupt
- * service routines.
- *
- * @return xSemaphore Handle to the created mutex semaphore. Should be of type
- * xSemaphoreHandle.
- *
- * Example usage:
-
- xSemaphoreHandle xSemaphore;
-
- void vATask( void * pvParameters )
- {
- // Semaphore cannot be used before a call to xSemaphoreCreateMutex().
- // This is a macro so pass the variable in directly.
- xSemaphore = xSemaphoreCreateRecursiveMutex();
-
- if( xSemaphore != NULL )
- {
- // The semaphore was created successfully.
- // The semaphore can now be used.
- }
- }
-
- * \defgroup vSemaphoreCreateMutex vSemaphoreCreateMutex
- * \ingroup Semaphores
- */
-#define xSemaphoreCreateRecursiveMutex() xQueueCreateMutex()
-
-/**
- * semphr. h
- * xSemaphoreHandle xSemaphoreCreateCounting( unsigned portBASE_TYPE uxMaxCount, unsigned portBASE_TYPE uxInitialCount )
- *
- * Macro that creates a counting semaphore by using the existing
- * queue mechanism.
- *
- * Counting semaphores are typically used for two things:
- *
- * 1) Counting events.
- *
- * In this usage scenario an event handler will 'give' a semaphore each time
- * an event occurs (incrementing the semaphore count value), and a handler
- * task will 'take' a semaphore each time it processes an event
- * (decrementing the semaphore count value). The count value is therefore
- * the difference between the number of events that have occurred and the
- * number that have been processed. In this case it is desirable for the
- * initial count value to be zero.
- *
- * 2) Resource management.
- *
- * In this usage scenario the count value indicates the number of resources
- * available. To obtain control of a resource a task must first obtain a
- * semaphore - decrementing the semaphore count value. When the count value
- * reaches zero there are no free resources. When a task finishes with the
- * resource it 'gives' the semaphore back - incrementing the semaphore count
- * value. In this case it is desirable for the initial count value to be
- * equal to the maximum count value, indicating that all resources are free.
- *
- * @param uxMaxCount The maximum count value that can be reached. When the
- * semaphore reaches this value it can no longer be 'given'.
- *
- * @param uxInitialCount The count value assigned to the semaphore when it is
- * created.
- *
- * @return Handle to the created semaphore. Null if the semaphore could not be
- * created.
- *
- * Example usage:
-
- xSemaphoreHandle xSemaphore;
-
- void vATask( void * pvParameters )
- {
- xSemaphoreHandle xSemaphore = NULL;
-
- // Semaphore cannot be used before a call to xSemaphoreCreateCounting().
- // The max value to which the semaphore can count should be 10, and the
- // initial value assigned to the count should be 0.
- xSemaphore = xSemaphoreCreateCounting( 10, 0 );
-
- if( xSemaphore != NULL )
- {
- // The semaphore was created successfully.
- // The semaphore can now be used.
- }
- }
-
- * \defgroup xSemaphoreCreateCounting xSemaphoreCreateCounting
- * \ingroup Semaphores
- */
-#define xSemaphoreCreateCounting( uxMaxCount, uxInitialCount ) xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ) )
-
-
-#endif /* SEMAPHORE_H */
-
-
+/*
+ FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.
+
+
+ FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:
+ Atollic AB - Atollic provides professional embedded systems development
+ tools for C/C++ development, code analysis and test automation.
+ See http://www.atollic.com
+
+
+ ***************************************************************************
+ * *
+ * FreeRTOS tutorial books are available in pdf and paperback. *
+ * Complete, revised, and edited pdf reference manuals are also *
+ * available. *
+ * *
+ * Purchasing FreeRTOS documentation will not only help you, by *
+ * ensuring you get running as quickly as possible and with an *
+ * in-depth knowledge of how to use FreeRTOS, it will also help *
+ * the FreeRTOS project to continue with its mission of providing *
+ * professional grade, cross platform, de facto standard solutions *
+ * for microcontrollers - completely free of charge! *
+ * *
+ * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
+ * *
+ * Thank you for using FreeRTOS, and thank you for your support! *
+ * *
+ ***************************************************************************
+
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
+ >>>NOTE<<< The modification to the GPL is included to allow you to
+ distribute a combined work that includes FreeRTOS without being obliged to
+ provide the source code for proprietary components outside of the FreeRTOS
+ kernel. FreeRTOS is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details. You should have received a copy of the GNU General Public
+ License and the FreeRTOS license exception along with FreeRTOS; if not it
+ can be viewed here: http://www.freertos.org/a00114.html and also obtained
+ by writing to Richard Barry, contact details for whom are available on the
+ FreeRTOS WEB site.
+
+ 1 tab == 4 spaces!
+
+ http://www.FreeRTOS.org - Documentation, latest information, license and
+ contact details.
+
+ http://www.SafeRTOS.com - A version that is certified for use in safety
+ critical systems.
+
+ http://www.OpenRTOS.com - Commercial support, development, porting,
+ licensing and training services.
+*/
+
+#ifndef SEMAPHORE_H
+#define SEMAPHORE_H
+
+#ifndef INC_FREERTOS_H
+ #error "#include FreeRTOS.h" must appear in source files before "#include semphr.h"
+#endif
+
+#include "queue.h"
+
+typedef xQueueHandle xSemaphoreHandle;
+
+#define semBINARY_SEMAPHORE_QUEUE_LENGTH ( ( unsigned char ) 1U )
+#define semSEMAPHORE_QUEUE_ITEM_LENGTH ( ( unsigned char ) 0U )
+#define semGIVE_BLOCK_TIME ( ( portTickType ) 0U )
+
+
+/**
+ * semphr. h
+ * vSemaphoreCreateBinary( xSemaphoreHandle xSemaphore )
+ *
+ * Macro that implements a semaphore by using the existing queue mechanism.
+ * The queue length is 1 as this is a binary semaphore. The data size is 0
+ * as we don't want to actually store any data - we just want to know if the
+ * queue is empty or full.
+ *
+ * This type of semaphore can be used for pure synchronisation between tasks or
+ * between an interrupt and a task. The semaphore need not be given back once
+ * obtained, so one task/interrupt can continuously 'give' the semaphore while
+ * another continuously 'takes' the semaphore. For this reason this type of
+ * semaphore does not use a priority inheritance mechanism. For an alternative
+ * that does use priority inheritance see xSemaphoreCreateMutex().
+ *
+ * @param xSemaphore Handle to the created semaphore. Should be of type xSemaphoreHandle.
+ *
+ * Example usage:
+
+ xSemaphoreHandle xSemaphore;
+
+ void vATask( void * pvParameters )
+ {
+ // Semaphore cannot be used before a call to vSemaphoreCreateBinary ().
+ // This is a macro so pass the variable in directly.
+ vSemaphoreCreateBinary( xSemaphore );
+
+ if( xSemaphore != NULL )
+ {
+ // The semaphore was created successfully.
+ // The semaphore can now be used.
+ }
+ }
+
+ * \defgroup vSemaphoreCreateBinary vSemaphoreCreateBinary
+ * \ingroup Semaphores
+ */
+#define vSemaphoreCreateBinary( xSemaphore ) { \
+ ( xSemaphore ) = xQueueCreate( ( unsigned portBASE_TYPE ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH ); \
+ if( ( xSemaphore ) != NULL ) \
+ { \
+ xSemaphoreGive( ( xSemaphore ) ); \
+ } \
+ }
+
+/**
+ * semphr. h
+ * xSemaphoreTake(
+ * xSemaphoreHandle xSemaphore,
+ * portTickType xBlockTime
+ * )
+ *
+ * Macro to obtain a semaphore. The semaphore must have previously been
+ * created with a call to vSemaphoreCreateBinary(), xSemaphoreCreateMutex() or
+ * xSemaphoreCreateCounting().
+ *
+ * @param xSemaphore A handle to the semaphore being taken - obtained when
+ * the semaphore was created.
+ *
+ * @param xBlockTime The time in ticks to wait for the semaphore to become
+ * available. The macro portTICK_RATE_MS can be used to convert this to a
+ * real time. A block time of zero can be used to poll the semaphore. A block
+ * time of portMAX_DELAY can be used to block indefinitely (provided
+ * INCLUDE_vTaskSuspend is set to 1 in FreeRTOSConfig.h).
+ *
+ * @return pdTRUE if the semaphore was obtained. pdFALSE
+ * if xBlockTime expired without the semaphore becoming available.
+ *
+ * Example usage:
+
+ xSemaphoreHandle xSemaphore = NULL;
+
+ // A task that creates a semaphore.
+ void vATask( void * pvParameters )
+ {
+ // Create the semaphore to guard a shared resource.
+ vSemaphoreCreateBinary( xSemaphore );
+ }
+
+ // A task that uses the semaphore.
+ void vAnotherTask( void * pvParameters )
+ {
+ // ... Do other things.
+
+ if( xSemaphore != NULL )
+ {
+ // See if we can obtain the semaphore. If the semaphore is not available
+ // wait 10 ticks to see if it becomes free.
+ if( xSemaphoreTake( xSemaphore, ( portTickType ) 10 ) == pdTRUE )
+ {
+ // We were able to obtain the semaphore and can now access the
+ // shared resource.
+
+ // ...
+
+ // We have finished accessing the shared resource. Release the
+ // semaphore.
+ xSemaphoreGive( xSemaphore );
+ }
+ else
+ {
+ // We could not obtain the semaphore and can therefore not access
+ // the shared resource safely.
+ }
+ }
+ }
+
+ * \defgroup xSemaphoreTake xSemaphoreTake
+ * \ingroup Semaphores
+ */
+#define xSemaphoreTake( xSemaphore, xBlockTime ) xQueueGenericReceive( ( xQueueHandle ) ( xSemaphore ), NULL, ( xBlockTime ), pdFALSE )
+
+/**
+ * semphr. h
+ * xSemaphoreTakeRecursive(
+ * xSemaphoreHandle xMutex,
+ * portTickType xBlockTime
+ * )
+ *
+ * Macro to recursively obtain, or 'take', a mutex type semaphore.
+ * The mutex must have previously been created using a call to
+ * xSemaphoreCreateRecursiveMutex();
+ *
+ * configUSE_RECURSIVE_MUTEXES must be set to 1 in FreeRTOSConfig.h for this
+ * macro to be available.
+ *
+ * This macro must not be used on mutexes created using xSemaphoreCreateMutex().
+ *
+ * A mutex used recursively can be 'taken' repeatedly by the owner. The mutex
+ * doesn't become available again until the owner has called
+ * xSemaphoreGiveRecursive() for each successful 'take' request. For example,
+ * if a task successfully 'takes' the same mutex 5 times then the mutex will
+ * not be available to any other task until it has also 'given' the mutex back
+ * exactly five times.
+ *
+ * @param xMutex A handle to the mutex being obtained. This is the
+ * handle returned by xSemaphoreCreateRecursiveMutex();
+ *
+ * @param xBlockTime The time in ticks to wait for the semaphore to become
+ * available. The macro portTICK_RATE_MS can be used to convert this to a
+ * real time. A block time of zero can be used to poll the semaphore. If
+ * the task already owns the semaphore then xSemaphoreTakeRecursive() will
+ * return immediately no matter what the value of xBlockTime.
+ *
+ * @return pdTRUE if the semaphore was obtained. pdFALSE if xBlockTime
+ * expired without the semaphore becoming available.
+ *
+ * Example usage:
+
+ xSemaphoreHandle xMutex = NULL;
+
+ // A task that creates a mutex.
+ void vATask( void * pvParameters )
+ {
+ // Create the mutex to guard a shared resource.
+ xMutex = xSemaphoreCreateRecursiveMutex();
+ }
+
+ // A task that uses the mutex.
+ void vAnotherTask( void * pvParameters )
+ {
+ // ... Do other things.
+
+ if( xMutex != NULL )
+ {
+ // See if we can obtain the mutex. If the mutex is not available
+ // wait 10 ticks to see if it becomes free.
+ if( xSemaphoreTakeRecursive( xSemaphore, ( portTickType ) 10 ) == pdTRUE )
+ {
+ // We were able to obtain the mutex and can now access the
+ // shared resource.
+
+ // ...
+ // For some reason due to the nature of the code further calls to
+ // xSemaphoreTakeRecursive() are made on the same mutex. In real
+ // code these would not be just sequential calls as this would make
+ // no sense. Instead the calls are likely to be buried inside
+ // a more complex call structure.
+ xSemaphoreTakeRecursive( xMutex, ( portTickType ) 10 );
+ xSemaphoreTakeRecursive( xMutex, ( portTickType ) 10 );
+
+ // The mutex has now been 'taken' three times, so will not be
+ // available to another task until it has also been given back
+ // three times. Again it is unlikely that real code would have
+ // these calls sequentially, but instead buried in a more complex
+ // call structure. This is just for illustrative purposes.
+ xSemaphoreGiveRecursive( xMutex );
+ xSemaphoreGiveRecursive( xMutex );
+ xSemaphoreGiveRecursive( xMutex );
+
+ // Now the mutex can be taken by other tasks.
+ }
+ else
+ {
+ // We could not obtain the mutex and can therefore not access
+ // the shared resource safely.
+ }
+ }
+ }
+
+ * \defgroup xSemaphoreTakeRecursive xSemaphoreTakeRecursive
+ * \ingroup Semaphores
+ */
+#define xSemaphoreTakeRecursive( xMutex, xBlockTime ) xQueueTakeMutexRecursive( ( xMutex ), ( xBlockTime ) )
+
+
+/*
+ * xSemaphoreAltTake() is an alternative version of xSemaphoreTake().
+ *
+ * The source code that implements the alternative (Alt) API is much
+ * simpler because it executes everything from within a critical section.
+ * This is the approach taken by many other RTOSes, but FreeRTOS.org has the
+ * preferred fully featured API too. The fully featured API has more
+ * complex code that takes longer to execute, but makes much less use of
+ * critical sections. Therefore the alternative API sacrifices interrupt
+ * responsiveness to gain execution speed, whereas the fully featured API
+ * sacrifices execution speed to ensure better interrupt responsiveness.
+ */
+#define xSemaphoreAltTake( xSemaphore, xBlockTime ) xQueueAltGenericReceive( ( xQueueHandle ) ( xSemaphore ), NULL, ( xBlockTime ), pdFALSE )
+
+/**
+ * semphr. h
+ * xSemaphoreGive( xSemaphoreHandle xSemaphore )
+ *
+ * Macro to release a semaphore. The semaphore must have previously been
+ * created with a call to vSemaphoreCreateBinary(), xSemaphoreCreateMutex() or
+ * xSemaphoreCreateCounting(). and obtained using sSemaphoreTake().
+ *
+ * This macro must not be used from an ISR. See xSemaphoreGiveFromISR () for
+ * an alternative which can be used from an ISR.
+ *
+ * This macro must also not be used on semaphores created using
+ * xSemaphoreCreateRecursiveMutex().
+ *
+ * @param xSemaphore A handle to the semaphore being released. This is the
+ * handle returned when the semaphore was created.
+ *
+ * @return pdTRUE if the semaphore was released. pdFALSE if an error occurred.
+ * Semaphores are implemented using queues. An error can occur if there is
+ * no space on the queue to post a message - indicating that the
+ * semaphore was not first obtained correctly.
+ *
+ * Example usage:
+
+ xSemaphoreHandle xSemaphore = NULL;
+
+ void vATask( void * pvParameters )
+ {
+ // Create the semaphore to guard a shared resource.
+ vSemaphoreCreateBinary( xSemaphore );
+
+ if( xSemaphore != NULL )
+ {
+ if( xSemaphoreGive( xSemaphore ) != pdTRUE )
+ {
+ // We would expect this call to fail because we cannot give
+ // a semaphore without first "taking" it!
+ }
+
+ // Obtain the semaphore - don't block if the semaphore is not
+ // immediately available.
+ if( xSemaphoreTake( xSemaphore, ( portTickType ) 0 ) )
+ {
+ // We now have the semaphore and can access the shared resource.
+
+ // ...
+
+ // We have finished accessing the shared resource so can free the
+ // semaphore.
+ if( xSemaphoreGive( xSemaphore ) != pdTRUE )
+ {
+ // We would not expect this call to fail because we must have
+ // obtained the semaphore to get here.
+ }
+ }
+ }
+ }
+
+ * \defgroup xSemaphoreGive xSemaphoreGive
+ * \ingroup Semaphores
+ */
+#define xSemaphoreGive( xSemaphore ) xQueueGenericSend( ( xQueueHandle ) ( xSemaphore ), NULL, semGIVE_BLOCK_TIME, queueSEND_TO_BACK )
+
+/**
+ * semphr. h
+ * xSemaphoreGiveRecursive( xSemaphoreHandle xMutex )
+ *
+ * Macro to recursively release, or 'give', a mutex type semaphore.
+ * The mutex must have previously been created using a call to
+ * xSemaphoreCreateRecursiveMutex();
+ *
+ * configUSE_RECURSIVE_MUTEXES must be set to 1 in FreeRTOSConfig.h for this
+ * macro to be available.
+ *
+ * This macro must not be used on mutexes created using xSemaphoreCreateMutex().
+ *
+ * A mutex used recursively can be 'taken' repeatedly by the owner. The mutex
+ * doesn't become available again until the owner has called
+ * xSemaphoreGiveRecursive() for each successful 'take' request. For example,
+ * if a task successfully 'takes' the same mutex 5 times then the mutex will
+ * not be available to any other task until it has also 'given' the mutex back
+ * exactly five times.
+ *
+ * @param xMutex A handle to the mutex being released, or 'given'. This is the
+ * handle returned by xSemaphoreCreateMutex();
+ *
+ * @return pdTRUE if the semaphore was given.
+ *
+ * Example usage:
+
+ xSemaphoreHandle xMutex = NULL;
+
+ // A task that creates a mutex.
+ void vATask( void * pvParameters )
+ {
+ // Create the mutex to guard a shared resource.
+ xMutex = xSemaphoreCreateRecursiveMutex();
+ }
+
+ // A task that uses the mutex.
+ void vAnotherTask( void * pvParameters )
+ {
+ // ... Do other things.
+
+ if( xMutex != NULL )
+ {
+ // See if we can obtain the mutex. If the mutex is not available
+ // wait 10 ticks to see if it becomes free.
+ if( xSemaphoreTakeRecursive( xMutex, ( portTickType ) 10 ) == pdTRUE )
+ {
+ // We were able to obtain the mutex and can now access the
+ // shared resource.
+
+ // ...
+ // For some reason due to the nature of the code further calls to
+ // xSemaphoreTakeRecursive() are made on the same mutex. In real
+ // code these would not be just sequential calls as this would make
+ // no sense. Instead the calls are likely to be buried inside
+ // a more complex call structure.
+ xSemaphoreTakeRecursive( xMutex, ( portTickType ) 10 );
+ xSemaphoreTakeRecursive( xMutex, ( portTickType ) 10 );
+
+ // The mutex has now been 'taken' three times, so will not be
+ // available to another task until it has also been given back
+ // three times. Again it is unlikely that real code would have
+ // these calls sequentially, it would be more likely that the calls
+ // to xSemaphoreGiveRecursive() would be called as a call stack
+ // unwound. This is just for demonstrative purposes.
+ xSemaphoreGiveRecursive( xMutex );
+ xSemaphoreGiveRecursive( xMutex );
+ xSemaphoreGiveRecursive( xMutex );
+
+ // Now the mutex can be taken by other tasks.
+ }
+ else
+ {
+ // We could not obtain the mutex and can therefore not access
+ // the shared resource safely.
+ }
+ }
+ }
+
+ * \defgroup xSemaphoreGiveRecursive xSemaphoreGiveRecursive
+ * \ingroup Semaphores
+ */
+#define xSemaphoreGiveRecursive( xMutex ) xQueueGiveMutexRecursive( ( xMutex ) )
+
+/*
+ * xSemaphoreAltGive() is an alternative version of xSemaphoreGive().
+ *
+ * The source code that implements the alternative (Alt) API is much
+ * simpler because it executes everything from within a critical section.
+ * This is the approach taken by many other RTOSes, but FreeRTOS.org has the
+ * preferred fully featured API too. The fully featured API has more
+ * complex code that takes longer to execute, but makes much less use of
+ * critical sections. Therefore the alternative API sacrifices interrupt
+ * responsiveness to gain execution speed, whereas the fully featured API
+ * sacrifices execution speed to ensure better interrupt responsiveness.
+ */
+#define xSemaphoreAltGive( xSemaphore ) xQueueAltGenericSend( ( xQueueHandle ) ( xSemaphore ), NULL, semGIVE_BLOCK_TIME, queueSEND_TO_BACK )
+
+/**
+ * semphr. h
+ *
+ xSemaphoreGiveFromISR(
+ xSemaphoreHandle xSemaphore,
+ signed portBASE_TYPE *pxHigherPriorityTaskWoken
+ )
+ *
+ * Macro to release a semaphore. The semaphore must have previously been
+ * created with a call to vSemaphoreCreateBinary() or xSemaphoreCreateCounting().
+ *
+ * Mutex type semaphores (those created using a call to xSemaphoreCreateMutex())
+ * must not be used with this macro.
+ *
+ * This macro can be used from an ISR.
+ *
+ * @param xSemaphore A handle to the semaphore being released. This is the
+ * handle returned when the semaphore was created.
+ *
+ * @param pxHigherPriorityTaskWoken xSemaphoreGiveFromISR() will set
+ * *pxHigherPriorityTaskWoken to pdTRUE if giving the semaphore caused a task
+ * to unblock, and the unblocked task has a priority higher than the currently
+ * running task. If xSemaphoreGiveFromISR() sets this value to pdTRUE then
+ * a context switch should be requested before the interrupt is exited.
+ *
+ * @return pdTRUE if the semaphore was successfully given, otherwise errQUEUE_FULL.
+ *
+ * Example usage:
+
+ \#define LONG_TIME 0xffff
+ \#define TICKS_TO_WAIT 10
+ xSemaphoreHandle xSemaphore = NULL;
+
+ // Repetitive task.
+ void vATask( void * pvParameters )
+ {
+ for( ;; )
+ {
+ // We want this task to run every 10 ticks of a timer. The semaphore
+ // was created before this task was started.
+
+ // Block waiting for the semaphore to become available.
+ if( xSemaphoreTake( xSemaphore, LONG_TIME ) == pdTRUE )
+ {
+ // It is time to execute.
+
+ // ...
+
+ // We have finished our task. Return to the top of the loop where
+ // we will block on the semaphore until it is time to execute
+ // again. Note when using the semaphore for synchronisation with an
+ // ISR in this manner there is no need to 'give' the semaphore back.
+ }
+ }
+ }
+
+ // Timer ISR
+ void vTimerISR( void * pvParameters )
+ {
+ static unsigned char ucLocalTickCount = 0;
+ static signed portBASE_TYPE xHigherPriorityTaskWoken;
+
+ // A timer tick has occurred.
+
+ // ... Do other time functions.
+
+ // Is it time for vATask () to run?
+ xHigherPriorityTaskWoken = pdFALSE;
+ ucLocalTickCount++;
+ if( ucLocalTickCount >= TICKS_TO_WAIT )
+ {
+ // Unblock the task by releasing the semaphore.
+ xSemaphoreGiveFromISR( xSemaphore, &xHigherPriorityTaskWoken );
+
+ // Reset the count so we release the semaphore again in 10 ticks time.
+ ucLocalTickCount = 0;
+ }
+
+ if( xHigherPriorityTaskWoken != pdFALSE )
+ {
+ // We can force a context switch here. Context switching from an
+ // ISR uses port specific syntax. Check the demo task for your port
+ // to find the syntax required.
+ }
+ }
+
+ * \defgroup xSemaphoreGiveFromISR xSemaphoreGiveFromISR
+ * \ingroup Semaphores
+ */
+#define xSemaphoreGiveFromISR( xSemaphore, pxHigherPriorityTaskWoken ) xQueueGenericSendFromISR( ( xQueueHandle ) ( xSemaphore ), NULL, ( pxHigherPriorityTaskWoken ), queueSEND_TO_BACK )
+
+/**
+ * semphr. h
+ * xSemaphoreHandle xSemaphoreCreateMutex( void )
+ *
+ * Macro that implements a mutex semaphore by using the existing queue
+ * mechanism.
+ *
+ * Mutexes created using this macro can be accessed using the xSemaphoreTake()
+ * and xSemaphoreGive() macros. The xSemaphoreTakeRecursive() and
+ * xSemaphoreGiveRecursive() macros should not be used.
+ *
+ * This type of semaphore uses a priority inheritance mechanism so a task
+ * 'taking' a semaphore MUST ALWAYS 'give' the semaphore back once the
+ * semaphore it is no longer required.
+ *
+ * Mutex type semaphores cannot be used from within interrupt service routines.
+ *
+ * See vSemaphoreCreateBinary() for an alternative implementation that can be
+ * used for pure synchronisation (where one task or interrupt always 'gives' the
+ * semaphore and another always 'takes' the semaphore) and from within interrupt
+ * service routines.
+ *
+ * @return xSemaphore Handle to the created mutex semaphore. Should be of type
+ * xSemaphoreHandle.
+ *
+ * Example usage:
+
+ xSemaphoreHandle xSemaphore;
+
+ void vATask( void * pvParameters )
+ {
+ // Semaphore cannot be used before a call to xSemaphoreCreateMutex().
+ // This is a macro so pass the variable in directly.
+ xSemaphore = xSemaphoreCreateMutex();
+
+ if( xSemaphore != NULL )
+ {
+ // The semaphore was created successfully.
+ // The semaphore can now be used.
+ }
+ }
+
+ * \defgroup vSemaphoreCreateMutex vSemaphoreCreateMutex
+ * \ingroup Semaphores
+ */
+#define xSemaphoreCreateMutex() xQueueCreateMutex()
+
+
+/**
+ * semphr. h
+ * xSemaphoreHandle xSemaphoreCreateRecursiveMutex( void )
+ *
+ * Macro that implements a recursive mutex by using the existing queue
+ * mechanism.
+ *
+ * Mutexes created using this macro can be accessed using the
+ * xSemaphoreTakeRecursive() and xSemaphoreGiveRecursive() macros. The
+ * xSemaphoreTake() and xSemaphoreGive() macros should not be used.
+ *
+ * A mutex used recursively can be 'taken' repeatedly by the owner. The mutex
+ * doesn't become available again until the owner has called
+ * xSemaphoreGiveRecursive() for each successful 'take' request. For example,
+ * if a task successfully 'takes' the same mutex 5 times then the mutex will
+ * not be available to any other task until it has also 'given' the mutex back
+ * exactly five times.
+ *
+ * This type of semaphore uses a priority inheritance mechanism so a task
+ * 'taking' a semaphore MUST ALWAYS 'give' the semaphore back once the
+ * semaphore it is no longer required.
+ *
+ * Mutex type semaphores cannot be used from within interrupt service routines.
+ *
+ * See vSemaphoreCreateBinary() for an alternative implementation that can be
+ * used for pure synchronisation (where one task or interrupt always 'gives' the
+ * semaphore and another always 'takes' the semaphore) and from within interrupt
+ * service routines.
+ *
+ * @return xSemaphore Handle to the created mutex semaphore. Should be of type
+ * xSemaphoreHandle.
+ *
+ * Example usage:
+
+ xSemaphoreHandle xSemaphore;
+
+ void vATask( void * pvParameters )
+ {
+ // Semaphore cannot be used before a call to xSemaphoreCreateMutex().
+ // This is a macro so pass the variable in directly.
+ xSemaphore = xSemaphoreCreateRecursiveMutex();
+
+ if( xSemaphore != NULL )
+ {
+ // The semaphore was created successfully.
+ // The semaphore can now be used.
+ }
+ }
+
+ * \defgroup vSemaphoreCreateMutex vSemaphoreCreateMutex
+ * \ingroup Semaphores
+ */
+#define xSemaphoreCreateRecursiveMutex() xQueueCreateMutex()
+
+/**
+ * semphr. h
+ * xSemaphoreHandle xSemaphoreCreateCounting( unsigned portBASE_TYPE uxMaxCount, unsigned portBASE_TYPE uxInitialCount )
+ *
+ * Macro that creates a counting semaphore by using the existing
+ * queue mechanism.
+ *
+ * Counting semaphores are typically used for two things:
+ *
+ * 1) Counting events.
+ *
+ * In this usage scenario an event handler will 'give' a semaphore each time
+ * an event occurs (incrementing the semaphore count value), and a handler
+ * task will 'take' a semaphore each time it processes an event
+ * (decrementing the semaphore count value). The count value is therefore
+ * the difference between the number of events that have occurred and the
+ * number that have been processed. In this case it is desirable for the
+ * initial count value to be zero.
+ *
+ * 2) Resource management.
+ *
+ * In this usage scenario the count value indicates the number of resources
+ * available. To obtain control of a resource a task must first obtain a
+ * semaphore - decrementing the semaphore count value. When the count value
+ * reaches zero there are no free resources. When a task finishes with the
+ * resource it 'gives' the semaphore back - incrementing the semaphore count
+ * value. In this case it is desirable for the initial count value to be
+ * equal to the maximum count value, indicating that all resources are free.
+ *
+ * @param uxMaxCount The maximum count value that can be reached. When the
+ * semaphore reaches this value it can no longer be 'given'.
+ *
+ * @param uxInitialCount The count value assigned to the semaphore when it is
+ * created.
+ *
+ * @return Handle to the created semaphore. Null if the semaphore could not be
+ * created.
+ *
+ * Example usage:
+
+ xSemaphoreHandle xSemaphore;
+
+ void vATask( void * pvParameters )
+ {
+ xSemaphoreHandle xSemaphore = NULL;
+
+ // Semaphore cannot be used before a call to xSemaphoreCreateCounting().
+ // The max value to which the semaphore can count should be 10, and the
+ // initial value assigned to the count should be 0.
+ xSemaphore = xSemaphoreCreateCounting( 10, 0 );
+
+ if( xSemaphore != NULL )
+ {
+ // The semaphore was created successfully.
+ // The semaphore can now be used.
+ }
+ }
+
+ * \defgroup xSemaphoreCreateCounting xSemaphoreCreateCounting
+ * \ingroup Semaphores
+ */
+#define xSemaphoreCreateCounting( uxMaxCount, uxInitialCount ) xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ) )
+
+
+#endif /* SEMAPHORE_H */
+
+
diff --git a/Libmaple/libmaple/libraries/FreeRTOS/utility/task.h b/Libmaple/libmaple/libraries/FreeRTOS/utility/task.h
index 3c44904d..96ba68e4 100644
--- a/Libmaple/libmaple/libraries/FreeRTOS/utility/task.h
+++ b/Libmaple/libmaple/libraries/FreeRTOS/utility/task.h
@@ -1,1307 +1,1307 @@
-/*
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.
-
-
- FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:
- Atollic AB - Atollic provides professional embedded systems development
- tools for C/C++ development, code analysis and test automation.
- See http://www.atollic.com
-
-
- ***************************************************************************
- * *
- * FreeRTOS tutorial books are available in pdf and paperback. *
- * Complete, revised, and edited pdf reference manuals are also *
- * available. *
- * *
- * Purchasing FreeRTOS documentation will not only help you, by *
- * ensuring you get running as quickly as possible and with an *
- * in-depth knowledge of how to use FreeRTOS, it will also help *
- * the FreeRTOS project to continue with its mission of providing *
- * professional grade, cross platform, de facto standard solutions *
- * for microcontrollers - completely free of charge! *
- * *
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
- * *
- * Thank you for using FreeRTOS, and thank you for your support! *
- * *
- ***************************************************************************
-
-
- This file is part of the FreeRTOS distribution.
-
- FreeRTOS is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License (version 2) as published by the
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
- >>>NOTE<<< The modification to the GPL is included to allow you to
- distribute a combined work that includes FreeRTOS without being obliged to
- provide the source code for proprietary components outside of the FreeRTOS
- kernel. FreeRTOS is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- more details. You should have received a copy of the GNU General Public
- License and the FreeRTOS license exception along with FreeRTOS; if not it
- can be viewed here: http://www.freertos.org/a00114.html and also obtained
- by writing to Richard Barry, contact details for whom are available on the
- FreeRTOS WEB site.
-
- 1 tab == 4 spaces!
-
- http://www.FreeRTOS.org - Documentation, latest information, license and
- contact details.
-
- http://www.SafeRTOS.com - A version that is certified for use in safety
- critical systems.
-
- http://www.OpenRTOS.com - Commercial support, development, porting,
- licensing and training services.
-*/
-
-
-#ifndef TASK_H
-#define TASK_H
-
-#ifndef INC_FREERTOS_H
- #error "include FreeRTOS.h must appear in source files before include task.h"
-#endif
-
-#include "portable.h"
-#include "list.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*-----------------------------------------------------------
- * MACROS AND DEFINITIONS
- *----------------------------------------------------------*/
-
-#define tskKERNEL_VERSION_NUMBER "V7.0.1"
-
-/**
- * task. h
- *
- * Type by which tasks are referenced. For example, a call to xTaskCreate
- * returns (via a pointer parameter) an xTaskHandle variable that can then
- * be used as a parameter to vTaskDelete to delete the task.
- *
- * \page xTaskHandle xTaskHandle
- * \ingroup Tasks
- */
-typedef void * xTaskHandle;
-
-/*
- * Used internally only.
- */
-typedef struct xTIME_OUT
-{
- portBASE_TYPE xOverflowCount;
- portTickType xTimeOnEntering;
-} xTimeOutType;
-
-/*
- * Defines the memory ranges allocated to the task when an MPU is used.
- */
-typedef struct xMEMORY_REGION
-{
- void *pvBaseAddress;
- unsigned long ulLengthInBytes;
- unsigned long ulParameters;
-} xMemoryRegion;
-
-/*
- * Parameters required to create an MPU protected task.
- */
-typedef struct xTASK_PARAMTERS
-{
- pdTASK_CODE pvTaskCode;
- const signed char * const pcName;
- unsigned short usStackDepth;
- void *pvParameters;
- unsigned portBASE_TYPE uxPriority;
- portSTACK_TYPE *puxStackBuffer;
- xMemoryRegion xRegions[ portNUM_CONFIGURABLE_REGIONS ];
-} xTaskParameters;
-
-/*
- * Defines the priority used by the idle task. This must not be modified.
- *
- * \ingroup TaskUtils
- */
-#define tskIDLE_PRIORITY ( ( unsigned portBASE_TYPE ) 0U )
-
-/**
- * task. h
- *
- * Macro for forcing a context switch.
- *
- * \page taskYIELD taskYIELD
- * \ingroup SchedulerControl
- */
-#define taskYIELD() portYIELD()
-
-/**
- * task. h
- *
- * Macro to mark the start of a critical code region. Preemptive context
- * switches cannot occur when in a critical region.
- *
- * NOTE: This may alter the stack (depending on the portable implementation)
- * so must be used with care!
- *
- * \page taskENTER_CRITICAL taskENTER_CRITICAL
- * \ingroup SchedulerControl
- */
-#define taskENTER_CRITICAL() portENTER_CRITICAL()
-
-/**
- * task. h
- *
- * Macro to mark the end of a critical code region. Preemptive context
- * switches cannot occur when in a critical region.
- *
- * NOTE: This may alter the stack (depending on the portable implementation)
- * so must be used with care!
- *
- * \page taskEXIT_CRITICAL taskEXIT_CRITICAL
- * \ingroup SchedulerControl
- */
-#define taskEXIT_CRITICAL() portEXIT_CRITICAL()
-
-/**
- * task. h
- *
- * Macro to disable all maskable interrupts.
- *
- * \page taskDISABLE_INTERRUPTS taskDISABLE_INTERRUPTS
- * \ingroup SchedulerControl
- */
-#define taskDISABLE_INTERRUPTS() portDISABLE_INTERRUPTS()
-
-/**
- * task. h
- *
- * Macro to enable microcontroller interrupts.
- *
- * \page taskENABLE_INTERRUPTS taskENABLE_INTERRUPTS
- * \ingroup SchedulerControl
- */
-#define taskENABLE_INTERRUPTS() portENABLE_INTERRUPTS()
-
-/* Definitions returned by xTaskGetSchedulerState(). */
-#define taskSCHEDULER_NOT_STARTED 0
-#define taskSCHEDULER_RUNNING 1
-#define taskSCHEDULER_SUSPENDED 2
-
-/*-----------------------------------------------------------
- * TASK CREATION API
- *----------------------------------------------------------*/
-
-/**
- * task. h
- *
- portBASE_TYPE xTaskCreate(
- pdTASK_CODE pvTaskCode,
- const char * const pcName,
- unsigned short usStackDepth,
- void *pvParameters,
- unsigned portBASE_TYPE uxPriority,
- xTaskHandle *pvCreatedTask
- );
- *
- * Create a new task and add it to the list of tasks that are ready to run.
- *
- * xTaskCreate() can only be used to create a task that has unrestricted
- * access to the entire microcontroller memory map. Systems that include MPU
- * support can alternatively create an MPU constrained task using
- * xTaskCreateRestricted().
- *
- * @param pvTaskCode Pointer to the task entry function. Tasks
- * must be implemented to never return (i.e. continuous loop).
- *
- * @param pcName A descriptive name for the task. This is mainly used to
- * facilitate debugging. Max length defined by tskMAX_TASK_NAME_LEN - default
- * is 16.
- *
- * @param usStackDepth The size of the task stack specified as the number of
- * variables the stack can hold - not the number of bytes. For example, if
- * the stack is 16 bits wide and usStackDepth is defined as 100, 200 bytes
- * will be allocated for stack storage.
- *
- * @param pvParameters Pointer that will be used as the parameter for the task
- * being created.
- *
- * @param uxPriority The priority at which the task should run. Systems that
- * include MPU support can optionally create tasks in a privileged (system)
- * mode by setting bit portPRIVILEGE_BIT of the priority parameter. For
- * example, to create a privileged task at priority 2 the uxPriority parameter
- * should be set to ( 2 | portPRIVILEGE_BIT ).
- *
- * @param pvCreatedTask Used to pass back a handle by which the created task
- * can be referenced.
- *
- * @return pdPASS if the task was successfully created and added to a ready
- * list, otherwise an error code defined in the file errors. h
- *
- * Example usage:
-
- // Task to be created.
- void vTaskCode( void * pvParameters )
- {
- for( ;; )
- {
- // Task code goes here.
- }
- }
-
- // Function that creates a task.
- void vOtherFunction( void )
- {
- static unsigned char ucParameterToPass;
- xTaskHandle xHandle;
-
- // Create the task, storing the handle. Note that the passed parameter ucParameterToPass
- // must exist for the lifetime of the task, so in this case is declared static. If it was just an
- // an automatic stack variable it might no longer exist, or at least have been corrupted, by the time
- // the new task attempts to access it.
- xTaskCreate( vTaskCode, "NAME", STACK_SIZE, &ucParameterToPass, tskIDLE_PRIORITY, &xHandle );
-
- // Use the handle to delete the task.
- vTaskDelete( xHandle );
- }
-
- * \defgroup xTaskCreate xTaskCreate
- * \ingroup Tasks
- */
-#define xTaskCreate( pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask ) xTaskGenericCreate( ( pvTaskCode ), ( pcName ), ( usStackDepth ), ( pvParameters ), ( uxPriority ), ( pxCreatedTask ), ( NULL ), ( NULL ) )
-
-/**
- * task. h
- *
- portBASE_TYPE xTaskCreateRestricted( xTaskParameters *pxTaskDefinition, xTaskHandle *pxCreatedTask );
- *
- * xTaskCreateRestricted() should only be used in systems that include an MPU
- * implementation.
- *
- * Create a new task and add it to the list of tasks that are ready to run.
- * The function parameters define the memory regions and associated access
- * permissions allocated to the task.
- *
- * @param pxTaskDefinition Pointer to a structure that contains a member
- * for each of the normal xTaskCreate() parameters (see the xTaskCreate() API
- * documentation) plus an optional stack buffer and the memory region
- * definitions.
- *
- * @param pxCreatedTask Used to pass back a handle by which the created task
- * can be referenced.
- *
- * @return pdPASS if the task was successfully created and added to a ready
- * list, otherwise an error code defined in the file errors. h
- *
- * Example usage:
-
-// Create an xTaskParameters structure that defines the task to be created.
-static const xTaskParameters xCheckTaskParameters =
-{
- vATask, // pvTaskCode - the function that implements the task.
- "ATask", // pcName - just a text name for the task to assist debugging.
- 100, // usStackDepth - the stack size DEFINED IN WORDS.
- NULL, // pvParameters - passed into the task function as the function parameters.
- ( 1UL | portPRIVILEGE_BIT ),// uxPriority - task priority, set the portPRIVILEGE_BIT if the task should run in a privileged state.
- cStackBuffer,// puxStackBuffer - the buffer to be used as the task stack.
-
- // xRegions - Allocate up to three separate memory regions for access by
- // the task, with appropriate access permissions. Different processors have
- // different memory alignment requirements - refer to the FreeRTOS documentation
- // for full information.
- {
- // Base address Length Parameters
- { cReadWriteArray, 32, portMPU_REGION_READ_WRITE },
- { cReadOnlyArray, 32, portMPU_REGION_READ_ONLY },
- { cPrivilegedOnlyAccessArray, 128, portMPU_REGION_PRIVILEGED_READ_WRITE }
- }
-};
-
-int main( void )
-{
-xTaskHandle xHandle;
-
- // Create a task from the const structure defined above. The task handle
- // is requested (the second parameter is not NULL) but in this case just for
- // demonstration purposes as its not actually used.
- xTaskCreateRestricted( &xRegTest1Parameters, &xHandle );
-
- // Start the scheduler.
- vTaskStartScheduler();
-
- // Will only get here if there was insufficient memory to create the idle
- // task.
- for( ;; );
-}
-
- * \defgroup xTaskCreateRestricted xTaskCreateRestricted
- * \ingroup Tasks
- */
-#define xTaskCreateRestricted( x, pxCreatedTask ) xTaskGenericCreate( ((x)->pvTaskCode), ((x)->pcName), ((x)->usStackDepth), ((x)->pvParameters), ((x)->uxPriority), (pxCreatedTask), ((x)->puxStackBuffer), ((x)->xRegions) )
-
-/**
- * task. h
- *
- void vTaskAllocateMPURegions( xTaskHandle xTask, const xMemoryRegion * const pxRegions );
- *
- * Memory regions are assigned to a restricted task when the task is created by
- * a call to xTaskCreateRestricted(). These regions can be redefined using
- * vTaskAllocateMPURegions().
- *
- * @param xTask The handle of the task being updated.
- *
- * @param xRegions A pointer to an xMemoryRegion structure that contains the
- * new memory region definitions.
- *
- * Example usage:
-
-// Define an array of xMemoryRegion structures that configures an MPU region
-// allowing read/write access for 1024 bytes starting at the beginning of the
-// ucOneKByte array. The other two of the maximum 3 definable regions are
-// unused so set to zero.
-static const xMemoryRegion xAltRegions[ portNUM_CONFIGURABLE_REGIONS ] =
-{
- // Base address Length Parameters
- { ucOneKByte, 1024, portMPU_REGION_READ_WRITE },
- { 0, 0, 0 },
- { 0, 0, 0 }
-};
-
-void vATask( void *pvParameters )
-{
- // This task was created such that it has access to certain regions of
- // memory as defined by the MPU configuration. At some point it is
- // desired that these MPU regions are replaced with that defined in the
- // xAltRegions const struct above. Use a call to vTaskAllocateMPURegions()
- // for this purpose. NULL is used as the task handle to indicate that this
- // function should modify the MPU regions of the calling task.
- vTaskAllocateMPURegions( NULL, xAltRegions );
-
- // Now the task can continue its function, but from this point on can only
- // access its stack and the ucOneKByte array (unless any other statically
- // defined or shared regions have been declared elsewhere).
-}
-
- * \defgroup xTaskCreateRestricted xTaskCreateRestricted
- * \ingroup Tasks
- */
-void vTaskAllocateMPURegions( xTaskHandle xTask, const xMemoryRegion * const pxRegions ) PRIVILEGED_FUNCTION;
-
-/**
- * task. h
- * void vTaskDelete( xTaskHandle pxTask );
- *
- * INCLUDE_vTaskDelete must be defined as 1 for this function to be available.
- * See the configuration section for more information.
- *
- * Remove a task from the RTOS real time kernels management. The task being
- * deleted will be removed from all ready, blocked, suspended and event lists.
- *
- * NOTE: The idle task is responsible for freeing the kernel allocated
- * memory from tasks that have been deleted. It is therefore important that
- * the idle task is not starved of microcontroller processing time if your
- * application makes any calls to vTaskDelete (). Memory allocated by the
- * task code is not automatically freed, and should be freed before the task
- * is deleted.
- *
- * See the demo application file death.c for sample code that utilises
- * vTaskDelete ().
- *
- * @param pxTask The handle of the task to be deleted. Passing NULL will
- * cause the calling task to be deleted.
- *
- * Example usage:
-
- void vOtherFunction( void )
- {
- xTaskHandle xHandle;
-
- // Create the task, storing the handle.
- xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
-
- // Use the handle to delete the task.
- vTaskDelete( xHandle );
- }
-
- * \defgroup vTaskDelete vTaskDelete
- * \ingroup Tasks
- */
-void vTaskDelete( xTaskHandle pxTaskToDelete ) PRIVILEGED_FUNCTION;
-
-/*-----------------------------------------------------------
- * TASK CONTROL API
- *----------------------------------------------------------*/
-
-/**
- * task. h
- * void vTaskDelay( portTickType xTicksToDelay );
- *
- * Delay a task for a given number of ticks. The actual time that the
- * task remains blocked depends on the tick rate. The constant
- * portTICK_RATE_MS can be used to calculate real time from the tick
- * rate - with the resolution of one tick period.
- *
- * INCLUDE_vTaskDelay must be defined as 1 for this function to be available.
- * See the configuration section for more information.
- *
- *
- * vTaskDelay() specifies a time at which the task wishes to unblock relative to
- * the time at which vTaskDelay() is called. For example, specifying a block
- * period of 100 ticks will cause the task to unblock 100 ticks after
- * vTaskDelay() is called. vTaskDelay() does not therefore provide a good method
- * of controlling the frequency of a cyclical task as the path taken through the
- * code, as well as other task and interrupt activity, will effect the frequency
- * at which vTaskDelay() gets called and therefore the time at which the task
- * next executes. See vTaskDelayUntil() for an alternative API function designed
- * to facilitate fixed frequency execution. It does this by specifying an
- * absolute time (rather than a relative time) at which the calling task should
- * unblock.
- *
- * @param xTicksToDelay The amount of time, in tick periods, that
- * the calling task should block.
- *
- * Example usage:
-
- void vTaskFunction( void * pvParameters )
- {
- void vTaskFunction( void * pvParameters )
- {
- // Block for 500ms.
- const portTickType xDelay = 500 / portTICK_RATE_MS;
-
- for( ;; )
- {
- // Simply toggle the LED every 500ms, blocking between each toggle.
- vToggleLED();
- vTaskDelay( xDelay );
- }
- }
-
- * \defgroup vTaskDelay vTaskDelay
- * \ingroup TaskCtrl
- */
-void vTaskDelay( portTickType xTicksToDelay ) PRIVILEGED_FUNCTION;
-
-/**
- * task. h
- * void vTaskDelayUntil( portTickType *pxPreviousWakeTime, portTickType xTimeIncrement );
- *
- * INCLUDE_vTaskDelayUntil must be defined as 1 for this function to be available.
- * See the configuration section for more information.
- *
- * Delay a task until a specified time. This function can be used by cyclical
- * tasks to ensure a constant execution frequency.
- *
- * This function differs from vTaskDelay () in one important aspect: vTaskDelay () will
- * cause a task to block for the specified number of ticks from the time vTaskDelay () is
- * called. It is therefore difficult to use vTaskDelay () by itself to generate a fixed
- * execution frequency as the time between a task starting to execute and that task
- * calling vTaskDelay () may not be fixed [the task may take a different path though the
- * code between calls, or may get interrupted or preempted a different number of times
- * each time it executes].
- *
- * Whereas vTaskDelay () specifies a wake time relative to the time at which the function
- * is called, vTaskDelayUntil () specifies the absolute (exact) time at which it wishes to
- * unblock.
- *
- * The constant portTICK_RATE_MS can be used to calculate real time from the tick
- * rate - with the resolution of one tick period.
- *
- * @param pxPreviousWakeTime Pointer to a variable that holds the time at which the
- * task was last unblocked. The variable must be initialised with the current time
- * prior to its first use (see the example below). Following this the variable is
- * automatically updated within vTaskDelayUntil ().
- *
- * @param xTimeIncrement The cycle time period. The task will be unblocked at
- * time *pxPreviousWakeTime + xTimeIncrement. Calling vTaskDelayUntil with the
- * same xTimeIncrement parameter value will cause the task to execute with
- * a fixed interface period.
- *
- * Example usage:
-
- // Perform an action every 10 ticks.
- void vTaskFunction( void * pvParameters )
- {
- portTickType xLastWakeTime;
- const portTickType xFrequency = 10;
-
- // Initialise the xLastWakeTime variable with the current time.
- xLastWakeTime = xTaskGetTickCount ();
- for( ;; )
- {
- // Wait for the next cycle.
- vTaskDelayUntil( &xLastWakeTime, xFrequency );
-
- // Perform action here.
- }
- }
-
- * \defgroup vTaskDelayUntil vTaskDelayUntil
- * \ingroup TaskCtrl
- */
-void vTaskDelayUntil( portTickType * const pxPreviousWakeTime, portTickType xTimeIncrement ) PRIVILEGED_FUNCTION;
-
-/**
- * task. h
- * unsigned portBASE_TYPE uxTaskPriorityGet( xTaskHandle pxTask );
- *
- * INCLUDE_xTaskPriorityGet must be defined as 1 for this function to be available.
- * See the configuration section for more information.
- *
- * Obtain the priority of any task.
- *
- * @param pxTask Handle of the task to be queried. Passing a NULL
- * handle results in the priority of the calling task being returned.
- *
- * @return The priority of pxTask.
- *
- * Example usage:
-
- void vAFunction( void )
- {
- xTaskHandle xHandle;
-
- // Create a task, storing the handle.
- xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
-
- // ...
-
- // Use the handle to obtain the priority of the created task.
- // It was created with tskIDLE_PRIORITY, but may have changed
- // it itself.
- if( uxTaskPriorityGet( xHandle ) != tskIDLE_PRIORITY )
- {
- // The task has changed it's priority.
- }
-
- // ...
-
- // Is our priority higher than the created task?
- if( uxTaskPriorityGet( xHandle ) < uxTaskPriorityGet( NULL ) )
- {
- // Our priority (obtained using NULL handle) is higher.
- }
- }
-
- * \defgroup uxTaskPriorityGet uxTaskPriorityGet
- * \ingroup TaskCtrl
- */
-unsigned portBASE_TYPE uxTaskPriorityGet( xTaskHandle pxTask ) PRIVILEGED_FUNCTION;
-
-/**
- * task. h
- * void vTaskPrioritySet( xTaskHandle pxTask, unsigned portBASE_TYPE uxNewPriority );
- *
- * INCLUDE_vTaskPrioritySet must be defined as 1 for this function to be available.
- * See the configuration section for more information.
- *
- * Set the priority of any task.
- *
- * A context switch will occur before the function returns if the priority
- * being set is higher than the currently executing task.
- *
- * @param pxTask Handle to the task for which the priority is being set.
- * Passing a NULL handle results in the priority of the calling task being set.
- *
- * @param uxNewPriority The priority to which the task will be set.
- *
- * Example usage:
-
- void vAFunction( void )
- {
- xTaskHandle xHandle;
-
- // Create a task, storing the handle.
- xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
-
- // ...
-
- // Use the handle to raise the priority of the created task.
- vTaskPrioritySet( xHandle, tskIDLE_PRIORITY + 1 );
-
- // ...
-
- // Use a NULL handle to raise our priority to the same value.
- vTaskPrioritySet( NULL, tskIDLE_PRIORITY + 1 );
- }
-
- * \defgroup vTaskPrioritySet vTaskPrioritySet
- * \ingroup TaskCtrl
- */
-void vTaskPrioritySet( xTaskHandle pxTask, unsigned portBASE_TYPE uxNewPriority ) PRIVILEGED_FUNCTION;
-
-/**
- * task. h
- * void vTaskSuspend( xTaskHandle pxTaskToSuspend );
- *
- * INCLUDE_vTaskSuspend must be defined as 1 for this function to be available.
- * See the configuration section for more information.
- *
- * Suspend any task. When suspended a task will never get any microcontroller
- * processing time, no matter what its priority.
- *
- * Calls to vTaskSuspend are not accumulative -
- * i.e. calling vTaskSuspend () twice on the same task still only requires one
- * call to vTaskResume () to ready the suspended task.
- *
- * @param pxTaskToSuspend Handle to the task being suspended. Passing a NULL
- * handle will cause the calling task to be suspended.
- *
- * Example usage:
-
- void vAFunction( void )
- {
- xTaskHandle xHandle;
-
- // Create a task, storing the handle.
- xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
-
- // ...
-
- // Use the handle to suspend the created task.
- vTaskSuspend( xHandle );
-
- // ...
-
- // The created task will not run during this period, unless
- // another task calls vTaskResume( xHandle ).
-
- //...
-
-
- // Suspend ourselves.
- vTaskSuspend( NULL );
-
- // We cannot get here unless another task calls vTaskResume
- // with our handle as the parameter.
- }
-
- * \defgroup vTaskSuspend vTaskSuspend
- * \ingroup TaskCtrl
- */
-void vTaskSuspend( xTaskHandle pxTaskToSuspend ) PRIVILEGED_FUNCTION;
-
-/**
- * task. h
- * void vTaskResume( xTaskHandle pxTaskToResume );
- *
- * INCLUDE_vTaskSuspend must be defined as 1 for this function to be available.
- * See the configuration section for more information.
- *
- * Resumes a suspended task.
- *
- * A task that has been suspended by one of more calls to vTaskSuspend ()
- * will be made available for running again by a single call to
- * vTaskResume ().
- *
- * @param pxTaskToResume Handle to the task being readied.
- *
- * Example usage:
-
- void vAFunction( void )
- {
- xTaskHandle xHandle;
-
- // Create a task, storing the handle.
- xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
-
- // ...
-
- // Use the handle to suspend the created task.
- vTaskSuspend( xHandle );
-
- // ...
-
- // The created task will not run during this period, unless
- // another task calls vTaskResume( xHandle ).
-
- //...
-
-
- // Resume the suspended task ourselves.
- vTaskResume( xHandle );
-
- // The created task will once again get microcontroller processing
- // time in accordance with it priority within the system.
- }
-
- * \defgroup vTaskResume vTaskResume
- * \ingroup TaskCtrl
- */
-void vTaskResume( xTaskHandle pxTaskToResume ) PRIVILEGED_FUNCTION;
-
-/**
- * task. h
- * void xTaskResumeFromISR( xTaskHandle pxTaskToResume );
- *
- * INCLUDE_xTaskResumeFromISR must be defined as 1 for this function to be
- * available. See the configuration section for more information.
- *
- * An implementation of vTaskResume() that can be called from within an ISR.
- *
- * A task that has been suspended by one of more calls to vTaskSuspend ()
- * will be made available for running again by a single call to
- * xTaskResumeFromISR ().
- *
- * @param pxTaskToResume Handle to the task being readied.
- *
- * \defgroup vTaskResumeFromISR vTaskResumeFromISR
- * \ingroup TaskCtrl
- */
-portBASE_TYPE xTaskResumeFromISR( xTaskHandle pxTaskToResume ) PRIVILEGED_FUNCTION;
-
-/*-----------------------------------------------------------
- * SCHEDULER CONTROL
- *----------------------------------------------------------*/
-
-/**
- * task. h
- * void vTaskStartScheduler( void );
- *
- * Starts the real time kernel tick processing. After calling the kernel
- * has control over which tasks are executed and when. This function
- * does not return until an executing task calls vTaskEndScheduler ().
- *
- * At least one task should be created via a call to xTaskCreate ()
- * before calling vTaskStartScheduler (). The idle task is created
- * automatically when the first application task is created.
- *
- * See the demo application file main.c for an example of creating
- * tasks and starting the kernel.
- *
- * Example usage:
-
- void vAFunction( void )
- {
- // Create at least one task before starting the kernel.
- xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
-
- // Start the real time kernel with preemption.
- vTaskStartScheduler ();
-
- // Will not get here unless a task calls vTaskEndScheduler ()
- }
-
- *
- * \defgroup vTaskStartScheduler vTaskStartScheduler
- * \ingroup SchedulerControl
- */
-void vTaskStartScheduler( void ) PRIVILEGED_FUNCTION;
-
-/**
- * task. h
- * void vTaskEndScheduler( void );
- *
- * Stops the real time kernel tick. All created tasks will be automatically
- * deleted and multitasking (either preemptive or cooperative) will
- * stop. Execution then resumes from the point where vTaskStartScheduler ()
- * was called, as if vTaskStartScheduler () had just returned.
- *
- * See the demo application file main. c in the demo/PC directory for an
- * example that uses vTaskEndScheduler ().
- *
- * vTaskEndScheduler () requires an exit function to be defined within the
- * portable layer (see vPortEndScheduler () in port. c for the PC port). This
- * performs hardware specific operations such as stopping the kernel tick.
- *
- * vTaskEndScheduler () will cause all of the resources allocated by the
- * kernel to be freed - but will not free resources allocated by application
- * tasks.
- *
- * Example usage:
-
- void vTaskCode( void * pvParameters )
- {
- for( ;; )
- {
- // Task code goes here.
-
- // At some point we want to end the real time kernel processing
- // so call ...
- vTaskEndScheduler ();
- }
- }
-
- void vAFunction( void )
- {
- // Create at least one task before starting the kernel.
- xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
-
- // Start the real time kernel with preemption.
- vTaskStartScheduler ();
-
- // Will only get here when the vTaskCode () task has called
- // vTaskEndScheduler (). When we get here we are back to single task
- // execution.
- }
-
- *
- * \defgroup vTaskEndScheduler vTaskEndScheduler
- * \ingroup SchedulerControl
- */
-void vTaskEndScheduler( void ) PRIVILEGED_FUNCTION;
-
-/**
- * task. h
- * void vTaskSuspendAll( void );
- *
- * Suspends all real time kernel activity while keeping interrupts (including the
- * kernel tick) enabled.
- *
- * After calling vTaskSuspendAll () the calling task will continue to execute
- * without risk of being swapped out until a call to xTaskResumeAll () has been
- * made.
- *
- * API functions that have the potential to cause a context switch (for example,
- * vTaskDelayUntil(), xQueueSend(), etc.) must not be called while the scheduler
- * is suspended.
- *
- * Example usage:
-
- void vTask1( void * pvParameters )
- {
- for( ;; )
- {
- // Task code goes here.
-
- // ...
-
- // At some point the task wants to perform a long operation during
- // which it does not want to get swapped out. It cannot use
- // taskENTER_CRITICAL ()/taskEXIT_CRITICAL () as the length of the
- // operation may cause interrupts to be missed - including the
- // ticks.
-
- // Prevent the real time kernel swapping out the task.
- vTaskSuspendAll ();
-
- // Perform the operation here. There is no need to use critical
- // sections as we have all the microcontroller processing time.
- // During this time interrupts will still operate and the kernel
- // tick count will be maintained.
-
- // ...
-
- // The operation is complete. Restart the kernel.
- xTaskResumeAll ();
- }
- }
-
- * \defgroup vTaskSuspendAll vTaskSuspendAll
- * \ingroup SchedulerControl
- */
-void vTaskSuspendAll( void ) PRIVILEGED_FUNCTION;
-
-/**
- * task. h
- * char xTaskResumeAll( void );
- *
- * Resumes real time kernel activity following a call to vTaskSuspendAll ().
- * After a call to vTaskSuspendAll () the kernel will take control of which
- * task is executing at any time.
- *
- * @return If resuming the scheduler caused a context switch then pdTRUE is
- * returned, otherwise pdFALSE is returned.
- *
- * Example usage:
-
- void vTask1( void * pvParameters )
- {
- for( ;; )
- {
- // Task code goes here.
-
- // ...
-
- // At some point the task wants to perform a long operation during
- // which it does not want to get swapped out. It cannot use
- // taskENTER_CRITICAL ()/taskEXIT_CRITICAL () as the length of the
- // operation may cause interrupts to be missed - including the
- // ticks.
-
- // Prevent the real time kernel swapping out the task.
- vTaskSuspendAll ();
-
- // Perform the operation here. There is no need to use critical
- // sections as we have all the microcontroller processing time.
- // During this time interrupts will still operate and the real
- // time kernel tick count will be maintained.
-
- // ...
-
- // The operation is complete. Restart the kernel. We want to force
- // a context switch - but there is no point if resuming the scheduler
- // caused a context switch already.
- if( !xTaskResumeAll () )
- {
- taskYIELD ();
- }
- }
- }
-
- * \defgroup xTaskResumeAll xTaskResumeAll
- * \ingroup SchedulerControl
- */
-signed portBASE_TYPE xTaskResumeAll( void ) PRIVILEGED_FUNCTION;
-
-/**
- * task. h
- * signed portBASE_TYPE xTaskIsTaskSuspended( xTaskHandle xTask );
- *
- * Utility task that simply returns pdTRUE if the task referenced by xTask is
- * currently in the Suspended state, or pdFALSE if the task referenced by xTask
- * is in any other state.
- *
- */
-signed portBASE_TYPE xTaskIsTaskSuspended( xTaskHandle xTask ) PRIVILEGED_FUNCTION;
-
-/*-----------------------------------------------------------
- * TASK UTILITIES
- *----------------------------------------------------------*/
-
-/**
- * task. h
- * portTickType xTaskGetTickCount( void );
- *
- * @return The count of ticks since vTaskStartScheduler was called.
- *
- * \page xTaskGetTickCount xTaskGetTickCount
- * \ingroup TaskUtils
- */
-portTickType xTaskGetTickCount( void ) PRIVILEGED_FUNCTION;
-
-/**
- * task. h
- * portTickType xTaskGetTickCountFromISR( void );
- *
- * @return The count of ticks since vTaskStartScheduler was called.
- *
- * This is a version of xTaskGetTickCount() that is safe to be called from an
- * ISR - provided that portTickType is the natural word size of the
- * microcontroller being used or interrupt nesting is either not supported or
- * not being used.
- *
- * \page xTaskGetTickCount xTaskGetTickCount
- * \ingroup TaskUtils
- */
-portTickType xTaskGetTickCountFromISR( void ) PRIVILEGED_FUNCTION;
-
-/**
- * task. h
- * unsigned short uxTaskGetNumberOfTasks( void );
- *
- * @return The number of tasks that the real time kernel is currently managing.
- * This includes all ready, blocked and suspended tasks. A task that
- * has been deleted but not yet freed by the idle task will also be
- * included in the count.
- *
- * \page uxTaskGetNumberOfTasks uxTaskGetNumberOfTasks
- * \ingroup TaskUtils
- */
-unsigned portBASE_TYPE uxTaskGetNumberOfTasks( void ) PRIVILEGED_FUNCTION;
-
-/**
- * task. h
- * void vTaskList( char *pcWriteBuffer );
- *
- * configUSE_TRACE_FACILITY must be defined as 1 for this function to be
- * available. See the configuration section for more information.
- *
- * NOTE: This function will disable interrupts for its duration. It is
- * not intended for normal application runtime use but as a debug aid.
- *
- * Lists all the current tasks, along with their current state and stack
- * usage high water mark.
- *
- * Tasks are reported as blocked ('B'), ready ('R'), deleted ('D') or
- * suspended ('S').
- *
- * @param pcWriteBuffer A buffer into which the above mentioned details
- * will be written, in ascii form. This buffer is assumed to be large
- * enough to contain the generated report. Approximately 40 bytes per
- * task should be sufficient.
- *
- * \page vTaskList vTaskList
- * \ingroup TaskUtils
- */
-void vTaskList( signed char *pcWriteBuffer ) PRIVILEGED_FUNCTION;
-
-/**
- * task. h
- * void vTaskGetRunTimeStats( char *pcWriteBuffer );
- *
- * configGENERATE_RUN_TIME_STATS must be defined as 1 for this function
- * to be available. The application must also then provide definitions
- * for portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() and
- * portGET_RUN_TIME_COUNTER_VALUE to configure a peripheral timer/counter
- * and return the timers current count value respectively. The counter
- * should be at least 10 times the frequency of the tick count.
- *
- * NOTE: This function will disable interrupts for its duration. It is
- * not intended for normal application runtime use but as a debug aid.
- *
- * Setting configGENERATE_RUN_TIME_STATS to 1 will result in a total
- * accumulated execution time being stored for each task. The resolution
- * of the accumulated time value depends on the frequency of the timer
- * configured by the portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() macro.
- * Calling vTaskGetRunTimeStats() writes the total execution time of each
- * task into a buffer, both as an absolute count value and as a percentage
- * of the total system execution time.
- *
- * @param pcWriteBuffer A buffer into which the execution times will be
- * written, in ascii form. This buffer is assumed to be large enough to
- * contain the generated report. Approximately 40 bytes per task should
- * be sufficient.
- *
- * \page vTaskGetRunTimeStats vTaskGetRunTimeStats
- * \ingroup TaskUtils
- */
-void vTaskGetRunTimeStats( signed char *pcWriteBuffer ) PRIVILEGED_FUNCTION;
-
-/**
- * task. h
- * void vTaskStartTrace( char * pcBuffer, unsigned portBASE_TYPE uxBufferSize );
- *
- * Starts a real time kernel activity trace. The trace logs the identity of
- * which task is running when.
- *
- * The trace file is stored in binary format. A separate DOS utility called
- * convtrce.exe is used to convert this into a tab delimited text file which
- * can be viewed and plotted in a spread sheet.
- *
- * @param pcBuffer The buffer into which the trace will be written.
- *
- * @param ulBufferSize The size of pcBuffer in bytes. The trace will continue
- * until either the buffer in full, or ulTaskEndTrace () is called.
- *
- * \page vTaskStartTrace vTaskStartTrace
- * \ingroup TaskUtils
- */
-void vTaskStartTrace( signed char * pcBuffer, unsigned long ulBufferSize ) PRIVILEGED_FUNCTION;
-
-/**
- * task. h
- * unsigned long ulTaskEndTrace( void );
- *
- * Stops a kernel activity trace. See vTaskStartTrace ().
- *
- * @return The number of bytes that have been written into the trace buffer.
- *
- * \page usTaskEndTrace usTaskEndTrace
- * \ingroup TaskUtils
- */
-unsigned long ulTaskEndTrace( void ) PRIVILEGED_FUNCTION;
-
-/**
- * task.h
- * unsigned portBASE_TYPE uxTaskGetStackHighWaterMark( xTaskHandle xTask );
- *
- * INCLUDE_uxTaskGetStackHighWaterMark must be set to 1 in FreeRTOSConfig.h for
- * this function to be available.
- *
- * Returns the high water mark of the stack associated with xTask. That is,
- * the minimum free stack space there has been (in words, so on a 32 bit machine
- * a value of 1 means 4 bytes) since the task started. The smaller the returned
- * number the closer the task has come to overflowing its stack.
- *
- * @param xTask Handle of the task associated with the stack to be checked.
- * Set xTask to NULL to check the stack of the calling task.
- *
- * @return The smallest amount of free stack space there has been (in bytes)
- * since the task referenced by xTask was created.
- */
-unsigned portBASE_TYPE uxTaskGetStackHighWaterMark( xTaskHandle xTask ) PRIVILEGED_FUNCTION;
-
-/* When using trace macros it is sometimes necessary to include tasks.h before
-FreeRTOS.h. When this is done pdTASK_HOOK_CODE will not yet have been defined,
-so the following two prototypes will cause a compilation error. This can be
-fixed by simply guarding against the inclusion of these two prototypes unless
-they are explicitly required by the configUSE_APPLICATION_TASK_TAG configuration
-constant. */
-#ifdef configUSE_APPLICATION_TASK_TAG
- #if configUSE_APPLICATION_TASK_TAG == 1
- /**
- * task.h
- * void vTaskSetApplicationTaskTag( xTaskHandle xTask, pdTASK_HOOK_CODE pxHookFunction );
- *
- * Sets pxHookFunction to be the task hook function used by the task xTask.
- * Passing xTask as NULL has the effect of setting the calling tasks hook
- * function.
- */
- void vTaskSetApplicationTaskTag( xTaskHandle xTask, pdTASK_HOOK_CODE pxHookFunction ) PRIVILEGED_FUNCTION;
-
- /**
- * task.h
- * void xTaskGetApplicationTaskTag( xTaskHandle xTask );
- *
- * Returns the pxHookFunction value assigned to the task xTask.
- */
- pdTASK_HOOK_CODE xTaskGetApplicationTaskTag( xTaskHandle xTask ) PRIVILEGED_FUNCTION;
- #endif /* configUSE_APPLICATION_TASK_TAG ==1 */
-#endif /* ifdef configUSE_APPLICATION_TASK_TAG */
-
-/**
- * task.h
- * portBASE_TYPE xTaskCallApplicationTaskHook( xTaskHandle xTask, pdTASK_HOOK_CODE pxHookFunction );
- *
- * Calls the hook function associated with xTask. Passing xTask as NULL has
- * the effect of calling the Running tasks (the calling task) hook function.
- *
- * pvParameter is passed to the hook function for the task to interpret as it
- * wants.
- */
-portBASE_TYPE xTaskCallApplicationTaskHook( xTaskHandle xTask, void *pvParameter ) PRIVILEGED_FUNCTION;
-
-
-/*-----------------------------------------------------------
- * SCHEDULER INTERNALS AVAILABLE FOR PORTING PURPOSES
- *----------------------------------------------------------*/
-
-/*
- * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS ONLY
- * INTENDED FOR USE WHEN IMPLEMENTING A PORT OF THE SCHEDULER AND IS
- * AN INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER.
- *
- * Called from the real time kernel tick (either preemptive or cooperative),
- * this increments the tick count and checks if any tasks that are blocked
- * for a finite period required removing from a blocked list and placing on
- * a ready list.
- */
-void vTaskIncrementTick( void ) PRIVILEGED_FUNCTION;
-
-/*
- * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN
- * INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER.
- *
- * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED.
- *
- * Removes the calling task from the ready list and places it both
- * on the list of tasks waiting for a particular event, and the
- * list of delayed tasks. The task will be removed from both lists
- * and replaced on the ready list should either the event occur (and
- * there be no higher priority tasks waiting on the same event) or
- * the delay period expires.
- *
- * @param pxEventList The list containing tasks that are blocked waiting
- * for the event to occur.
- *
- * @param xTicksToWait The maximum amount of time that the task should wait
- * for the event to occur. This is specified in kernel ticks,the constant
- * portTICK_RATE_MS can be used to convert kernel ticks into a real time
- * period.
- */
-void vTaskPlaceOnEventList( const xList * const pxEventList, portTickType xTicksToWait ) PRIVILEGED_FUNCTION;
-
-/*
- * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN
- * INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER.
- *
- * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED.
- *
- * This function performs nearly the same function as vTaskPlaceOnEventList().
- * The difference being that this function does not permit tasks to block
- * indefinitely, whereas vTaskPlaceOnEventList() does.
- *
- * @return pdTRUE if the task being removed has a higher priority than the task
- * making the call, otherwise pdFALSE.
- */
-void vTaskPlaceOnEventListRestricted( const xList * const pxEventList, portTickType xTicksToWait ) PRIVILEGED_FUNCTION;
-
-/*
- * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN
- * INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER.
- *
- * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED.
- *
- * Removes a task from both the specified event list and the list of blocked
- * tasks, and places it on a ready queue.
- *
- * xTaskRemoveFromEventList () will be called if either an event occurs to
- * unblock a task, or the block timeout period expires.
- *
- * @return pdTRUE if the task being removed has a higher priority than the task
- * making the call, otherwise pdFALSE.
- */
-signed portBASE_TYPE xTaskRemoveFromEventList( const xList * const pxEventList ) PRIVILEGED_FUNCTION;
-
-/*
- * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN
- * INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER.
- *
- * INCLUDE_vTaskCleanUpResources and INCLUDE_vTaskSuspend must be defined as 1
- * for this function to be available.
- * See the configuration section for more information.
- *
- * Empties the ready and delayed queues of task control blocks, freeing the
- * memory allocated for the task control block and task stacks as it goes.
- */
-void vTaskCleanUpResources( void ) PRIVILEGED_FUNCTION;
-
-/*
- * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS ONLY
- * INTENDED FOR USE WHEN IMPLEMENTING A PORT OF THE SCHEDULER AND IS
- * AN INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER.
- *
- * Sets the pointer to the current TCB to the TCB of the highest priority task
- * that is ready to run.
- */
-void vTaskSwitchContext( void ) PRIVILEGED_FUNCTION;
-
-/*
- * Return the handle of the calling task.
- */
-xTaskHandle xTaskGetCurrentTaskHandle( void ) PRIVILEGED_FUNCTION;
-
-/*
- * Capture the current time status for future reference.
- */
-void vTaskSetTimeOutState( xTimeOutType * const pxTimeOut ) PRIVILEGED_FUNCTION;
-
-/*
- * Compare the time status now with that previously captured to see if the
- * timeout has expired.
- */
-portBASE_TYPE xTaskCheckForTimeOut( xTimeOutType * const pxTimeOut, portTickType * const pxTicksToWait ) PRIVILEGED_FUNCTION;
-
-/*
- * Shortcut used by the queue implementation to prevent unnecessary call to
- * taskYIELD();
- */
-void vTaskMissedYield( void ) PRIVILEGED_FUNCTION;
-
-/*
- * Returns the scheduler state as taskSCHEDULER_RUNNING,
- * taskSCHEDULER_NOT_STARTED or taskSCHEDULER_SUSPENDED.
- */
-portBASE_TYPE xTaskGetSchedulerState( void ) PRIVILEGED_FUNCTION;
-
-/*
- * Raises the priority of the mutex holder to that of the calling task should
- * the mutex holder have a priority less than the calling task.
- */
-void vTaskPriorityInherit( xTaskHandle * const pxMutexHolder ) PRIVILEGED_FUNCTION;
-
-/*
- * Set the priority of a task back to its proper priority in the case that it
- * inherited a higher priority while it was holding a semaphore.
- */
-void vTaskPriorityDisinherit( xTaskHandle * const pxMutexHolder ) PRIVILEGED_FUNCTION;
-
-/*
- * Generic version of the task creation function which is in turn called by the
- * xTaskCreate() and xTaskCreateRestricted() macros.
- */
-signed portBASE_TYPE xTaskGenericCreate( pdTASK_CODE pxTaskCode, const signed char * const pcName, unsigned short usStackDepth, void *pvParameters, unsigned portBASE_TYPE uxPriority, xTaskHandle *pxCreatedTask, portSTACK_TYPE *puxStackBuffer, const xMemoryRegion * const xRegions ) PRIVILEGED_FUNCTION;
-
-#ifdef __cplusplus
-}
-#endif
-#endif /* TASK_H */
-
-
-
+/*
+ FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.
+
+
+ FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:
+ Atollic AB - Atollic provides professional embedded systems development
+ tools for C/C++ development, code analysis and test automation.
+ See http://www.atollic.com
+
+
+ ***************************************************************************
+ * *
+ * FreeRTOS tutorial books are available in pdf and paperback. *
+ * Complete, revised, and edited pdf reference manuals are also *
+ * available. *
+ * *
+ * Purchasing FreeRTOS documentation will not only help you, by *
+ * ensuring you get running as quickly as possible and with an *
+ * in-depth knowledge of how to use FreeRTOS, it will also help *
+ * the FreeRTOS project to continue with its mission of providing *
+ * professional grade, cross platform, de facto standard solutions *
+ * for microcontrollers - completely free of charge! *
+ * *
+ * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
+ * *
+ * Thank you for using FreeRTOS, and thank you for your support! *
+ * *
+ ***************************************************************************
+
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
+ >>>NOTE<<< The modification to the GPL is included to allow you to
+ distribute a combined work that includes FreeRTOS without being obliged to
+ provide the source code for proprietary components outside of the FreeRTOS
+ kernel. FreeRTOS is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details. You should have received a copy of the GNU General Public
+ License and the FreeRTOS license exception along with FreeRTOS; if not it
+ can be viewed here: http://www.freertos.org/a00114.html and also obtained
+ by writing to Richard Barry, contact details for whom are available on the
+ FreeRTOS WEB site.
+
+ 1 tab == 4 spaces!
+
+ http://www.FreeRTOS.org - Documentation, latest information, license and
+ contact details.
+
+ http://www.SafeRTOS.com - A version that is certified for use in safety
+ critical systems.
+
+ http://www.OpenRTOS.com - Commercial support, development, porting,
+ licensing and training services.
+*/
+
+
+#ifndef TASK_H
+#define TASK_H
+
+#ifndef INC_FREERTOS_H
+ #error "include FreeRTOS.h must appear in source files before include task.h"
+#endif
+
+#include "portable.h"
+#include "list.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*-----------------------------------------------------------
+ * MACROS AND DEFINITIONS
+ *----------------------------------------------------------*/
+
+#define tskKERNEL_VERSION_NUMBER "V7.0.1"
+
+/**
+ * task. h
+ *
+ * Type by which tasks are referenced. For example, a call to xTaskCreate
+ * returns (via a pointer parameter) an xTaskHandle variable that can then
+ * be used as a parameter to vTaskDelete to delete the task.
+ *
+ * \page xTaskHandle xTaskHandle
+ * \ingroup Tasks
+ */
+typedef void * xTaskHandle;
+
+/*
+ * Used internally only.
+ */
+typedef struct xTIME_OUT
+{
+ portBASE_TYPE xOverflowCount;
+ portTickType xTimeOnEntering;
+} xTimeOutType;
+
+/*
+ * Defines the memory ranges allocated to the task when an MPU is used.
+ */
+typedef struct xMEMORY_REGION
+{
+ void *pvBaseAddress;
+ unsigned long ulLengthInBytes;
+ unsigned long ulParameters;
+} xMemoryRegion;
+
+/*
+ * Parameters required to create an MPU protected task.
+ */
+typedef struct xTASK_PARAMTERS
+{
+ pdTASK_CODE pvTaskCode;
+ const signed char * const pcName;
+ unsigned short usStackDepth;
+ void *pvParameters;
+ unsigned portBASE_TYPE uxPriority;
+ portSTACK_TYPE *puxStackBuffer;
+ xMemoryRegion xRegions[ portNUM_CONFIGURABLE_REGIONS ];
+} xTaskParameters;
+
+/*
+ * Defines the priority used by the idle task. This must not be modified.
+ *
+ * \ingroup TaskUtils
+ */
+#define tskIDLE_PRIORITY ( ( unsigned portBASE_TYPE ) 0U )
+
+/**
+ * task. h
+ *
+ * Macro for forcing a context switch.
+ *
+ * \page taskYIELD taskYIELD
+ * \ingroup SchedulerControl
+ */
+#define taskYIELD() portYIELD()
+
+/**
+ * task. h
+ *
+ * Macro to mark the start of a critical code region. Preemptive context
+ * switches cannot occur when in a critical region.
+ *
+ * NOTE: This may alter the stack (depending on the portable implementation)
+ * so must be used with care!
+ *
+ * \page taskENTER_CRITICAL taskENTER_CRITICAL
+ * \ingroup SchedulerControl
+ */
+#define taskENTER_CRITICAL() portENTER_CRITICAL()
+
+/**
+ * task. h
+ *
+ * Macro to mark the end of a critical code region. Preemptive context
+ * switches cannot occur when in a critical region.
+ *
+ * NOTE: This may alter the stack (depending on the portable implementation)
+ * so must be used with care!
+ *
+ * \page taskEXIT_CRITICAL taskEXIT_CRITICAL
+ * \ingroup SchedulerControl
+ */
+#define taskEXIT_CRITICAL() portEXIT_CRITICAL()
+
+/**
+ * task. h
+ *
+ * Macro to disable all maskable interrupts.
+ *
+ * \page taskDISABLE_INTERRUPTS taskDISABLE_INTERRUPTS
+ * \ingroup SchedulerControl
+ */
+#define taskDISABLE_INTERRUPTS() portDISABLE_INTERRUPTS()
+
+/**
+ * task. h
+ *
+ * Macro to enable microcontroller interrupts.
+ *
+ * \page taskENABLE_INTERRUPTS taskENABLE_INTERRUPTS
+ * \ingroup SchedulerControl
+ */
+#define taskENABLE_INTERRUPTS() portENABLE_INTERRUPTS()
+
+/* Definitions returned by xTaskGetSchedulerState(). */
+#define taskSCHEDULER_NOT_STARTED 0
+#define taskSCHEDULER_RUNNING 1
+#define taskSCHEDULER_SUSPENDED 2
+
+/*-----------------------------------------------------------
+ * TASK CREATION API
+ *----------------------------------------------------------*/
+
+/**
+ * task. h
+ *
+ portBASE_TYPE xTaskCreate(
+ pdTASK_CODE pvTaskCode,
+ const char * const pcName,
+ unsigned short usStackDepth,
+ void *pvParameters,
+ unsigned portBASE_TYPE uxPriority,
+ xTaskHandle *pvCreatedTask
+ );
+ *
+ * Create a new task and add it to the list of tasks that are ready to run.
+ *
+ * xTaskCreate() can only be used to create a task that has unrestricted
+ * access to the entire microcontroller memory map. Systems that include MPU
+ * support can alternatively create an MPU constrained task using
+ * xTaskCreateRestricted().
+ *
+ * @param pvTaskCode Pointer to the task entry function. Tasks
+ * must be implemented to never return (i.e. continuous loop).
+ *
+ * @param pcName A descriptive name for the task. This is mainly used to
+ * facilitate debugging. Max length defined by tskMAX_TASK_NAME_LEN - default
+ * is 16.
+ *
+ * @param usStackDepth The size of the task stack specified as the number of
+ * variables the stack can hold - not the number of bytes. For example, if
+ * the stack is 16 bits wide and usStackDepth is defined as 100, 200 bytes
+ * will be allocated for stack storage.
+ *
+ * @param pvParameters Pointer that will be used as the parameter for the task
+ * being created.
+ *
+ * @param uxPriority The priority at which the task should run. Systems that
+ * include MPU support can optionally create tasks in a privileged (system)
+ * mode by setting bit portPRIVILEGE_BIT of the priority parameter. For
+ * example, to create a privileged task at priority 2 the uxPriority parameter
+ * should be set to ( 2 | portPRIVILEGE_BIT ).
+ *
+ * @param pvCreatedTask Used to pass back a handle by which the created task
+ * can be referenced.
+ *
+ * @return pdPASS if the task was successfully created and added to a ready
+ * list, otherwise an error code defined in the file errors. h
+ *
+ * Example usage:
+
+ // Task to be created.
+ void vTaskCode( void * pvParameters )
+ {
+ for( ;; )
+ {
+ // Task code goes here.
+ }
+ }
+
+ // Function that creates a task.
+ void vOtherFunction( void )
+ {
+ static unsigned char ucParameterToPass;
+ xTaskHandle xHandle;
+
+ // Create the task, storing the handle. Note that the passed parameter ucParameterToPass
+ // must exist for the lifetime of the task, so in this case is declared static. If it was just an
+ // an automatic stack variable it might no longer exist, or at least have been corrupted, by the time
+ // the new task attempts to access it.
+ xTaskCreate( vTaskCode, "NAME", STACK_SIZE, &ucParameterToPass, tskIDLE_PRIORITY, &xHandle );
+
+ // Use the handle to delete the task.
+ vTaskDelete( xHandle );
+ }
+
+ * \defgroup xTaskCreate xTaskCreate
+ * \ingroup Tasks
+ */
+#define xTaskCreate( pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask ) xTaskGenericCreate( ( pvTaskCode ), ( pcName ), ( usStackDepth ), ( pvParameters ), ( uxPriority ), ( pxCreatedTask ), ( NULL ), ( NULL ) )
+
+/**
+ * task. h
+ *
+ portBASE_TYPE xTaskCreateRestricted( xTaskParameters *pxTaskDefinition, xTaskHandle *pxCreatedTask );
+ *
+ * xTaskCreateRestricted() should only be used in systems that include an MPU
+ * implementation.
+ *
+ * Create a new task and add it to the list of tasks that are ready to run.
+ * The function parameters define the memory regions and associated access
+ * permissions allocated to the task.
+ *
+ * @param pxTaskDefinition Pointer to a structure that contains a member
+ * for each of the normal xTaskCreate() parameters (see the xTaskCreate() API
+ * documentation) plus an optional stack buffer and the memory region
+ * definitions.
+ *
+ * @param pxCreatedTask Used to pass back a handle by which the created task
+ * can be referenced.
+ *
+ * @return pdPASS if the task was successfully created and added to a ready
+ * list, otherwise an error code defined in the file errors. h
+ *
+ * Example usage:
+
+// Create an xTaskParameters structure that defines the task to be created.
+static const xTaskParameters xCheckTaskParameters =
+{
+ vATask, // pvTaskCode - the function that implements the task.
+ "ATask", // pcName - just a text name for the task to assist debugging.
+ 100, // usStackDepth - the stack size DEFINED IN WORDS.
+ NULL, // pvParameters - passed into the task function as the function parameters.
+ ( 1UL | portPRIVILEGE_BIT ),// uxPriority - task priority, set the portPRIVILEGE_BIT if the task should run in a privileged state.
+ cStackBuffer,// puxStackBuffer - the buffer to be used as the task stack.
+
+ // xRegions - Allocate up to three separate memory regions for access by
+ // the task, with appropriate access permissions. Different processors have
+ // different memory alignment requirements - refer to the FreeRTOS documentation
+ // for full information.
+ {
+ // Base address Length Parameters
+ { cReadWriteArray, 32, portMPU_REGION_READ_WRITE },
+ { cReadOnlyArray, 32, portMPU_REGION_READ_ONLY },
+ { cPrivilegedOnlyAccessArray, 128, portMPU_REGION_PRIVILEGED_READ_WRITE }
+ }
+};
+
+int main( void )
+{
+xTaskHandle xHandle;
+
+ // Create a task from the const structure defined above. The task handle
+ // is requested (the second parameter is not NULL) but in this case just for
+ // demonstration purposes as its not actually used.
+ xTaskCreateRestricted( &xRegTest1Parameters, &xHandle );
+
+ // Start the scheduler.
+ vTaskStartScheduler();
+
+ // Will only get here if there was insufficient memory to create the idle
+ // task.
+ for( ;; );
+}
+
+ * \defgroup xTaskCreateRestricted xTaskCreateRestricted
+ * \ingroup Tasks
+ */
+#define xTaskCreateRestricted( x, pxCreatedTask ) xTaskGenericCreate( ((x)->pvTaskCode), ((x)->pcName), ((x)->usStackDepth), ((x)->pvParameters), ((x)->uxPriority), (pxCreatedTask), ((x)->puxStackBuffer), ((x)->xRegions) )
+
+/**
+ * task. h
+ *
+ void vTaskAllocateMPURegions( xTaskHandle xTask, const xMemoryRegion * const pxRegions );
+ *
+ * Memory regions are assigned to a restricted task when the task is created by
+ * a call to xTaskCreateRestricted(). These regions can be redefined using
+ * vTaskAllocateMPURegions().
+ *
+ * @param xTask The handle of the task being updated.
+ *
+ * @param xRegions A pointer to an xMemoryRegion structure that contains the
+ * new memory region definitions.
+ *
+ * Example usage:
+
+// Define an array of xMemoryRegion structures that configures an MPU region
+// allowing read/write access for 1024 bytes starting at the beginning of the
+// ucOneKByte array. The other two of the maximum 3 definable regions are
+// unused so set to zero.
+static const xMemoryRegion xAltRegions[ portNUM_CONFIGURABLE_REGIONS ] =
+{
+ // Base address Length Parameters
+ { ucOneKByte, 1024, portMPU_REGION_READ_WRITE },
+ { 0, 0, 0 },
+ { 0, 0, 0 }
+};
+
+void vATask( void *pvParameters )
+{
+ // This task was created such that it has access to certain regions of
+ // memory as defined by the MPU configuration. At some point it is
+ // desired that these MPU regions are replaced with that defined in the
+ // xAltRegions const struct above. Use a call to vTaskAllocateMPURegions()
+ // for this purpose. NULL is used as the task handle to indicate that this
+ // function should modify the MPU regions of the calling task.
+ vTaskAllocateMPURegions( NULL, xAltRegions );
+
+ // Now the task can continue its function, but from this point on can only
+ // access its stack and the ucOneKByte array (unless any other statically
+ // defined or shared regions have been declared elsewhere).
+}
+
+ * \defgroup xTaskCreateRestricted xTaskCreateRestricted
+ * \ingroup Tasks
+ */
+void vTaskAllocateMPURegions( xTaskHandle xTask, const xMemoryRegion * const pxRegions ) PRIVILEGED_FUNCTION;
+
+/**
+ * task. h
+ * void vTaskDelete( xTaskHandle pxTask );
+ *
+ * INCLUDE_vTaskDelete must be defined as 1 for this function to be available.
+ * See the configuration section for more information.
+ *
+ * Remove a task from the RTOS real time kernels management. The task being
+ * deleted will be removed from all ready, blocked, suspended and event lists.
+ *
+ * NOTE: The idle task is responsible for freeing the kernel allocated
+ * memory from tasks that have been deleted. It is therefore important that
+ * the idle task is not starved of microcontroller processing time if your
+ * application makes any calls to vTaskDelete (). Memory allocated by the
+ * task code is not automatically freed, and should be freed before the task
+ * is deleted.
+ *
+ * See the demo application file death.c for sample code that utilises
+ * vTaskDelete ().
+ *
+ * @param pxTask The handle of the task to be deleted. Passing NULL will
+ * cause the calling task to be deleted.
+ *
+ * Example usage:
+
+ void vOtherFunction( void )
+ {
+ xTaskHandle xHandle;
+
+ // Create the task, storing the handle.
+ xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
+
+ // Use the handle to delete the task.
+ vTaskDelete( xHandle );
+ }
+
+ * \defgroup vTaskDelete vTaskDelete
+ * \ingroup Tasks
+ */
+void vTaskDelete( xTaskHandle pxTaskToDelete ) PRIVILEGED_FUNCTION;
+
+/*-----------------------------------------------------------
+ * TASK CONTROL API
+ *----------------------------------------------------------*/
+
+/**
+ * task. h
+ * void vTaskDelay( portTickType xTicksToDelay );
+ *
+ * Delay a task for a given number of ticks. The actual time that the
+ * task remains blocked depends on the tick rate. The constant
+ * portTICK_RATE_MS can be used to calculate real time from the tick
+ * rate - with the resolution of one tick period.
+ *
+ * INCLUDE_vTaskDelay must be defined as 1 for this function to be available.
+ * See the configuration section for more information.
+ *
+ *
+ * vTaskDelay() specifies a time at which the task wishes to unblock relative to
+ * the time at which vTaskDelay() is called. For example, specifying a block
+ * period of 100 ticks will cause the task to unblock 100 ticks after
+ * vTaskDelay() is called. vTaskDelay() does not therefore provide a good method
+ * of controlling the frequency of a cyclical task as the path taken through the
+ * code, as well as other task and interrupt activity, will effect the frequency
+ * at which vTaskDelay() gets called and therefore the time at which the task
+ * next executes. See vTaskDelayUntil() for an alternative API function designed
+ * to facilitate fixed frequency execution. It does this by specifying an
+ * absolute time (rather than a relative time) at which the calling task should
+ * unblock.
+ *
+ * @param xTicksToDelay The amount of time, in tick periods, that
+ * the calling task should block.
+ *
+ * Example usage:
+
+ void vTaskFunction( void * pvParameters )
+ {
+ void vTaskFunction( void * pvParameters )
+ {
+ // Block for 500ms.
+ const portTickType xDelay = 500 / portTICK_RATE_MS;
+
+ for( ;; )
+ {
+ // Simply toggle the LED every 500ms, blocking between each toggle.
+ vToggleLED();
+ vTaskDelay( xDelay );
+ }
+ }
+
+ * \defgroup vTaskDelay vTaskDelay
+ * \ingroup TaskCtrl
+ */
+void vTaskDelay( portTickType xTicksToDelay ) PRIVILEGED_FUNCTION;
+
+/**
+ * task. h
+ * void vTaskDelayUntil( portTickType *pxPreviousWakeTime, portTickType xTimeIncrement );
+ *
+ * INCLUDE_vTaskDelayUntil must be defined as 1 for this function to be available.
+ * See the configuration section for more information.
+ *
+ * Delay a task until a specified time. This function can be used by cyclical
+ * tasks to ensure a constant execution frequency.
+ *
+ * This function differs from vTaskDelay () in one important aspect: vTaskDelay () will
+ * cause a task to block for the specified number of ticks from the time vTaskDelay () is
+ * called. It is therefore difficult to use vTaskDelay () by itself to generate a fixed
+ * execution frequency as the time between a task starting to execute and that task
+ * calling vTaskDelay () may not be fixed [the task may take a different path though the
+ * code between calls, or may get interrupted or preempted a different number of times
+ * each time it executes].
+ *
+ * Whereas vTaskDelay () specifies a wake time relative to the time at which the function
+ * is called, vTaskDelayUntil () specifies the absolute (exact) time at which it wishes to
+ * unblock.
+ *
+ * The constant portTICK_RATE_MS can be used to calculate real time from the tick
+ * rate - with the resolution of one tick period.
+ *
+ * @param pxPreviousWakeTime Pointer to a variable that holds the time at which the
+ * task was last unblocked. The variable must be initialised with the current time
+ * prior to its first use (see the example below). Following this the variable is
+ * automatically updated within vTaskDelayUntil ().
+ *
+ * @param xTimeIncrement The cycle time period. The task will be unblocked at
+ * time *pxPreviousWakeTime + xTimeIncrement. Calling vTaskDelayUntil with the
+ * same xTimeIncrement parameter value will cause the task to execute with
+ * a fixed interface period.
+ *
+ * Example usage:
+
+ // Perform an action every 10 ticks.
+ void vTaskFunction( void * pvParameters )
+ {
+ portTickType xLastWakeTime;
+ const portTickType xFrequency = 10;
+
+ // Initialise the xLastWakeTime variable with the current time.
+ xLastWakeTime = xTaskGetTickCount ();
+ for( ;; )
+ {
+ // Wait for the next cycle.
+ vTaskDelayUntil( &xLastWakeTime, xFrequency );
+
+ // Perform action here.
+ }
+ }
+
+ * \defgroup vTaskDelayUntil vTaskDelayUntil
+ * \ingroup TaskCtrl
+ */
+void vTaskDelayUntil( portTickType * const pxPreviousWakeTime, portTickType xTimeIncrement ) PRIVILEGED_FUNCTION;
+
+/**
+ * task. h
+ * unsigned portBASE_TYPE uxTaskPriorityGet( xTaskHandle pxTask );
+ *
+ * INCLUDE_xTaskPriorityGet must be defined as 1 for this function to be available.
+ * See the configuration section for more information.
+ *
+ * Obtain the priority of any task.
+ *
+ * @param pxTask Handle of the task to be queried. Passing a NULL
+ * handle results in the priority of the calling task being returned.
+ *
+ * @return The priority of pxTask.
+ *
+ * Example usage:
+
+ void vAFunction( void )
+ {
+ xTaskHandle xHandle;
+
+ // Create a task, storing the handle.
+ xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
+
+ // ...
+
+ // Use the handle to obtain the priority of the created task.
+ // It was created with tskIDLE_PRIORITY, but may have changed
+ // it itself.
+ if( uxTaskPriorityGet( xHandle ) != tskIDLE_PRIORITY )
+ {
+ // The task has changed it's priority.
+ }
+
+ // ...
+
+ // Is our priority higher than the created task?
+ if( uxTaskPriorityGet( xHandle ) < uxTaskPriorityGet( NULL ) )
+ {
+ // Our priority (obtained using NULL handle) is higher.
+ }
+ }
+
+ * \defgroup uxTaskPriorityGet uxTaskPriorityGet
+ * \ingroup TaskCtrl
+ */
+unsigned portBASE_TYPE uxTaskPriorityGet( xTaskHandle pxTask ) PRIVILEGED_FUNCTION;
+
+/**
+ * task. h
+ * void vTaskPrioritySet( xTaskHandle pxTask, unsigned portBASE_TYPE uxNewPriority );
+ *
+ * INCLUDE_vTaskPrioritySet must be defined as 1 for this function to be available.
+ * See the configuration section for more information.
+ *
+ * Set the priority of any task.
+ *
+ * A context switch will occur before the function returns if the priority
+ * being set is higher than the currently executing task.
+ *
+ * @param pxTask Handle to the task for which the priority is being set.
+ * Passing a NULL handle results in the priority of the calling task being set.
+ *
+ * @param uxNewPriority The priority to which the task will be set.
+ *
+ * Example usage:
+
+ void vAFunction( void )
+ {
+ xTaskHandle xHandle;
+
+ // Create a task, storing the handle.
+ xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
+
+ // ...
+
+ // Use the handle to raise the priority of the created task.
+ vTaskPrioritySet( xHandle, tskIDLE_PRIORITY + 1 );
+
+ // ...
+
+ // Use a NULL handle to raise our priority to the same value.
+ vTaskPrioritySet( NULL, tskIDLE_PRIORITY + 1 );
+ }
+
+ * \defgroup vTaskPrioritySet vTaskPrioritySet
+ * \ingroup TaskCtrl
+ */
+void vTaskPrioritySet( xTaskHandle pxTask, unsigned portBASE_TYPE uxNewPriority ) PRIVILEGED_FUNCTION;
+
+/**
+ * task. h
+ * void vTaskSuspend( xTaskHandle pxTaskToSuspend );
+ *
+ * INCLUDE_vTaskSuspend must be defined as 1 for this function to be available.
+ * See the configuration section for more information.
+ *
+ * Suspend any task. When suspended a task will never get any microcontroller
+ * processing time, no matter what its priority.
+ *
+ * Calls to vTaskSuspend are not accumulative -
+ * i.e. calling vTaskSuspend () twice on the same task still only requires one
+ * call to vTaskResume () to ready the suspended task.
+ *
+ * @param pxTaskToSuspend Handle to the task being suspended. Passing a NULL
+ * handle will cause the calling task to be suspended.
+ *
+ * Example usage:
+
+ void vAFunction( void )
+ {
+ xTaskHandle xHandle;
+
+ // Create a task, storing the handle.
+ xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
+
+ // ...
+
+ // Use the handle to suspend the created task.
+ vTaskSuspend( xHandle );
+
+ // ...
+
+ // The created task will not run during this period, unless
+ // another task calls vTaskResume( xHandle ).
+
+ //...
+
+
+ // Suspend ourselves.
+ vTaskSuspend( NULL );
+
+ // We cannot get here unless another task calls vTaskResume
+ // with our handle as the parameter.
+ }
+
+ * \defgroup vTaskSuspend vTaskSuspend
+ * \ingroup TaskCtrl
+ */
+void vTaskSuspend( xTaskHandle pxTaskToSuspend ) PRIVILEGED_FUNCTION;
+
+/**
+ * task. h
+ * void vTaskResume( xTaskHandle pxTaskToResume );
+ *
+ * INCLUDE_vTaskSuspend must be defined as 1 for this function to be available.
+ * See the configuration section for more information.
+ *
+ * Resumes a suspended task.
+ *
+ * A task that has been suspended by one of more calls to vTaskSuspend ()
+ * will be made available for running again by a single call to
+ * vTaskResume ().
+ *
+ * @param pxTaskToResume Handle to the task being readied.
+ *
+ * Example usage:
+
+ void vAFunction( void )
+ {
+ xTaskHandle xHandle;
+
+ // Create a task, storing the handle.
+ xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
+
+ // ...
+
+ // Use the handle to suspend the created task.
+ vTaskSuspend( xHandle );
+
+ // ...
+
+ // The created task will not run during this period, unless
+ // another task calls vTaskResume( xHandle ).
+
+ //...
+
+
+ // Resume the suspended task ourselves.
+ vTaskResume( xHandle );
+
+ // The created task will once again get microcontroller processing
+ // time in accordance with it priority within the system.
+ }
+
+ * \defgroup vTaskResume vTaskResume
+ * \ingroup TaskCtrl
+ */
+void vTaskResume( xTaskHandle pxTaskToResume ) PRIVILEGED_FUNCTION;
+
+/**
+ * task. h
+ * void xTaskResumeFromISR( xTaskHandle pxTaskToResume );
+ *
+ * INCLUDE_xTaskResumeFromISR must be defined as 1 for this function to be
+ * available. See the configuration section for more information.
+ *
+ * An implementation of vTaskResume() that can be called from within an ISR.
+ *
+ * A task that has been suspended by one of more calls to vTaskSuspend ()
+ * will be made available for running again by a single call to
+ * xTaskResumeFromISR ().
+ *
+ * @param pxTaskToResume Handle to the task being readied.
+ *
+ * \defgroup vTaskResumeFromISR vTaskResumeFromISR
+ * \ingroup TaskCtrl
+ */
+portBASE_TYPE xTaskResumeFromISR( xTaskHandle pxTaskToResume ) PRIVILEGED_FUNCTION;
+
+/*-----------------------------------------------------------
+ * SCHEDULER CONTROL
+ *----------------------------------------------------------*/
+
+/**
+ * task. h
+ * void vTaskStartScheduler( void );
+ *
+ * Starts the real time kernel tick processing. After calling the kernel
+ * has control over which tasks are executed and when. This function
+ * does not return until an executing task calls vTaskEndScheduler ().
+ *
+ * At least one task should be created via a call to xTaskCreate ()
+ * before calling vTaskStartScheduler (). The idle task is created
+ * automatically when the first application task is created.
+ *
+ * See the demo application file main.c for an example of creating
+ * tasks and starting the kernel.
+ *
+ * Example usage:
+
+ void vAFunction( void )
+ {
+ // Create at least one task before starting the kernel.
+ xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
+
+ // Start the real time kernel with preemption.
+ vTaskStartScheduler ();
+
+ // Will not get here unless a task calls vTaskEndScheduler ()
+ }
+
+ *
+ * \defgroup vTaskStartScheduler vTaskStartScheduler
+ * \ingroup SchedulerControl
+ */
+void vTaskStartScheduler( void ) PRIVILEGED_FUNCTION;
+
+/**
+ * task. h
+ * void vTaskEndScheduler( void );
+ *
+ * Stops the real time kernel tick. All created tasks will be automatically
+ * deleted and multitasking (either preemptive or cooperative) will
+ * stop. Execution then resumes from the point where vTaskStartScheduler ()
+ * was called, as if vTaskStartScheduler () had just returned.
+ *
+ * See the demo application file main. c in the demo/PC directory for an
+ * example that uses vTaskEndScheduler ().
+ *
+ * vTaskEndScheduler () requires an exit function to be defined within the
+ * portable layer (see vPortEndScheduler () in port. c for the PC port). This
+ * performs hardware specific operations such as stopping the kernel tick.
+ *
+ * vTaskEndScheduler () will cause all of the resources allocated by the
+ * kernel to be freed - but will not free resources allocated by application
+ * tasks.
+ *
+ * Example usage:
+
+ void vTaskCode( void * pvParameters )
+ {
+ for( ;; )
+ {
+ // Task code goes here.
+
+ // At some point we want to end the real time kernel processing
+ // so call ...
+ vTaskEndScheduler ();
+ }
+ }
+
+ void vAFunction( void )
+ {
+ // Create at least one task before starting the kernel.
+ xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
+
+ // Start the real time kernel with preemption.
+ vTaskStartScheduler ();
+
+ // Will only get here when the vTaskCode () task has called
+ // vTaskEndScheduler (). When we get here we are back to single task
+ // execution.
+ }
+
+ *
+ * \defgroup vTaskEndScheduler vTaskEndScheduler
+ * \ingroup SchedulerControl
+ */
+void vTaskEndScheduler( void ) PRIVILEGED_FUNCTION;
+
+/**
+ * task. h
+ * void vTaskSuspendAll( void );
+ *
+ * Suspends all real time kernel activity while keeping interrupts (including the
+ * kernel tick) enabled.
+ *
+ * After calling vTaskSuspendAll () the calling task will continue to execute
+ * without risk of being swapped out until a call to xTaskResumeAll () has been
+ * made.
+ *
+ * API functions that have the potential to cause a context switch (for example,
+ * vTaskDelayUntil(), xQueueSend(), etc.) must not be called while the scheduler
+ * is suspended.
+ *
+ * Example usage:
+
+ void vTask1( void * pvParameters )
+ {
+ for( ;; )
+ {
+ // Task code goes here.
+
+ // ...
+
+ // At some point the task wants to perform a long operation during
+ // which it does not want to get swapped out. It cannot use
+ // taskENTER_CRITICAL ()/taskEXIT_CRITICAL () as the length of the
+ // operation may cause interrupts to be missed - including the
+ // ticks.
+
+ // Prevent the real time kernel swapping out the task.
+ vTaskSuspendAll ();
+
+ // Perform the operation here. There is no need to use critical
+ // sections as we have all the microcontroller processing time.
+ // During this time interrupts will still operate and the kernel
+ // tick count will be maintained.
+
+ // ...
+
+ // The operation is complete. Restart the kernel.
+ xTaskResumeAll ();
+ }
+ }
+
+ * \defgroup vTaskSuspendAll vTaskSuspendAll
+ * \ingroup SchedulerControl
+ */
+void vTaskSuspendAll( void ) PRIVILEGED_FUNCTION;
+
+/**
+ * task. h
+ * char xTaskResumeAll( void );
+ *
+ * Resumes real time kernel activity following a call to vTaskSuspendAll ().
+ * After a call to vTaskSuspendAll () the kernel will take control of which
+ * task is executing at any time.
+ *
+ * @return If resuming the scheduler caused a context switch then pdTRUE is
+ * returned, otherwise pdFALSE is returned.
+ *
+ * Example usage:
+
+ void vTask1( void * pvParameters )
+ {
+ for( ;; )
+ {
+ // Task code goes here.
+
+ // ...
+
+ // At some point the task wants to perform a long operation during
+ // which it does not want to get swapped out. It cannot use
+ // taskENTER_CRITICAL ()/taskEXIT_CRITICAL () as the length of the
+ // operation may cause interrupts to be missed - including the
+ // ticks.
+
+ // Prevent the real time kernel swapping out the task.
+ vTaskSuspendAll ();
+
+ // Perform the operation here. There is no need to use critical
+ // sections as we have all the microcontroller processing time.
+ // During this time interrupts will still operate and the real
+ // time kernel tick count will be maintained.
+
+ // ...
+
+ // The operation is complete. Restart the kernel. We want to force
+ // a context switch - but there is no point if resuming the scheduler
+ // caused a context switch already.
+ if( !xTaskResumeAll () )
+ {
+ taskYIELD ();
+ }
+ }
+ }
+
+ * \defgroup xTaskResumeAll xTaskResumeAll
+ * \ingroup SchedulerControl
+ */
+signed portBASE_TYPE xTaskResumeAll( void ) PRIVILEGED_FUNCTION;
+
+/**
+ * task. h
+ * signed portBASE_TYPE xTaskIsTaskSuspended( xTaskHandle xTask );
+ *
+ * Utility task that simply returns pdTRUE if the task referenced by xTask is
+ * currently in the Suspended state, or pdFALSE if the task referenced by xTask
+ * is in any other state.
+ *
+ */
+signed portBASE_TYPE xTaskIsTaskSuspended( xTaskHandle xTask ) PRIVILEGED_FUNCTION;
+
+/*-----------------------------------------------------------
+ * TASK UTILITIES
+ *----------------------------------------------------------*/
+
+/**
+ * task. h
+ * portTickType xTaskGetTickCount( void );
+ *
+ * @return The count of ticks since vTaskStartScheduler was called.
+ *
+ * \page xTaskGetTickCount xTaskGetTickCount
+ * \ingroup TaskUtils
+ */
+portTickType xTaskGetTickCount( void ) PRIVILEGED_FUNCTION;
+
+/**
+ * task. h
+ * portTickType xTaskGetTickCountFromISR( void );
+ *
+ * @return The count of ticks since vTaskStartScheduler was called.
+ *
+ * This is a version of xTaskGetTickCount() that is safe to be called from an
+ * ISR - provided that portTickType is the natural word size of the
+ * microcontroller being used or interrupt nesting is either not supported or
+ * not being used.
+ *
+ * \page xTaskGetTickCount xTaskGetTickCount
+ * \ingroup TaskUtils
+ */
+portTickType xTaskGetTickCountFromISR( void ) PRIVILEGED_FUNCTION;
+
+/**
+ * task. h
+ * unsigned short uxTaskGetNumberOfTasks( void );
+ *
+ * @return The number of tasks that the real time kernel is currently managing.
+ * This includes all ready, blocked and suspended tasks. A task that
+ * has been deleted but not yet freed by the idle task will also be
+ * included in the count.
+ *
+ * \page uxTaskGetNumberOfTasks uxTaskGetNumberOfTasks
+ * \ingroup TaskUtils
+ */
+unsigned portBASE_TYPE uxTaskGetNumberOfTasks( void ) PRIVILEGED_FUNCTION;
+
+/**
+ * task. h
+ * void vTaskList( char *pcWriteBuffer );
+ *
+ * configUSE_TRACE_FACILITY must be defined as 1 for this function to be
+ * available. See the configuration section for more information.
+ *
+ * NOTE: This function will disable interrupts for its duration. It is
+ * not intended for normal application runtime use but as a debug aid.
+ *
+ * Lists all the current tasks, along with their current state and stack
+ * usage high water mark.
+ *
+ * Tasks are reported as blocked ('B'), ready ('R'), deleted ('D') or
+ * suspended ('S').
+ *
+ * @param pcWriteBuffer A buffer into which the above mentioned details
+ * will be written, in ascii form. This buffer is assumed to be large
+ * enough to contain the generated report. Approximately 40 bytes per
+ * task should be sufficient.
+ *
+ * \page vTaskList vTaskList
+ * \ingroup TaskUtils
+ */
+void vTaskList( signed char *pcWriteBuffer ) PRIVILEGED_FUNCTION;
+
+/**
+ * task. h
+ * void vTaskGetRunTimeStats( char *pcWriteBuffer );
+ *
+ * configGENERATE_RUN_TIME_STATS must be defined as 1 for this function
+ * to be available. The application must also then provide definitions
+ * for portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() and
+ * portGET_RUN_TIME_COUNTER_VALUE to configure a peripheral timer/counter
+ * and return the timers current count value respectively. The counter
+ * should be at least 10 times the frequency of the tick count.
+ *
+ * NOTE: This function will disable interrupts for its duration. It is
+ * not intended for normal application runtime use but as a debug aid.
+ *
+ * Setting configGENERATE_RUN_TIME_STATS to 1 will result in a total
+ * accumulated execution time being stored for each task. The resolution
+ * of the accumulated time value depends on the frequency of the timer
+ * configured by the portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() macro.
+ * Calling vTaskGetRunTimeStats() writes the total execution time of each
+ * task into a buffer, both as an absolute count value and as a percentage
+ * of the total system execution time.
+ *
+ * @param pcWriteBuffer A buffer into which the execution times will be
+ * written, in ascii form. This buffer is assumed to be large enough to
+ * contain the generated report. Approximately 40 bytes per task should
+ * be sufficient.
+ *
+ * \page vTaskGetRunTimeStats vTaskGetRunTimeStats
+ * \ingroup TaskUtils
+ */
+void vTaskGetRunTimeStats( signed char *pcWriteBuffer ) PRIVILEGED_FUNCTION;
+
+/**
+ * task. h
+ * void vTaskStartTrace( char * pcBuffer, unsigned portBASE_TYPE uxBufferSize );
+ *
+ * Starts a real time kernel activity trace. The trace logs the identity of
+ * which task is running when.
+ *
+ * The trace file is stored in binary format. A separate DOS utility called
+ * convtrce.exe is used to convert this into a tab delimited text file which
+ * can be viewed and plotted in a spread sheet.
+ *
+ * @param pcBuffer The buffer into which the trace will be written.
+ *
+ * @param ulBufferSize The size of pcBuffer in bytes. The trace will continue
+ * until either the buffer in full, or ulTaskEndTrace () is called.
+ *
+ * \page vTaskStartTrace vTaskStartTrace
+ * \ingroup TaskUtils
+ */
+void vTaskStartTrace( signed char * pcBuffer, unsigned long ulBufferSize ) PRIVILEGED_FUNCTION;
+
+/**
+ * task. h
+ * unsigned long ulTaskEndTrace( void );
+ *
+ * Stops a kernel activity trace. See vTaskStartTrace ().
+ *
+ * @return The number of bytes that have been written into the trace buffer.
+ *
+ * \page usTaskEndTrace usTaskEndTrace
+ * \ingroup TaskUtils
+ */
+unsigned long ulTaskEndTrace( void ) PRIVILEGED_FUNCTION;
+
+/**
+ * task.h
+ * unsigned portBASE_TYPE uxTaskGetStackHighWaterMark( xTaskHandle xTask );
+ *
+ * INCLUDE_uxTaskGetStackHighWaterMark must be set to 1 in FreeRTOSConfig.h for
+ * this function to be available.
+ *
+ * Returns the high water mark of the stack associated with xTask. That is,
+ * the minimum free stack space there has been (in words, so on a 32 bit machine
+ * a value of 1 means 4 bytes) since the task started. The smaller the returned
+ * number the closer the task has come to overflowing its stack.
+ *
+ * @param xTask Handle of the task associated with the stack to be checked.
+ * Set xTask to NULL to check the stack of the calling task.
+ *
+ * @return The smallest amount of free stack space there has been (in bytes)
+ * since the task referenced by xTask was created.
+ */
+unsigned portBASE_TYPE uxTaskGetStackHighWaterMark( xTaskHandle xTask ) PRIVILEGED_FUNCTION;
+
+/* When using trace macros it is sometimes necessary to include tasks.h before
+FreeRTOS.h. When this is done pdTASK_HOOK_CODE will not yet have been defined,
+so the following two prototypes will cause a compilation error. This can be
+fixed by simply guarding against the inclusion of these two prototypes unless
+they are explicitly required by the configUSE_APPLICATION_TASK_TAG configuration
+constant. */
+#ifdef configUSE_APPLICATION_TASK_TAG
+ #if configUSE_APPLICATION_TASK_TAG == 1
+ /**
+ * task.h
+ * void vTaskSetApplicationTaskTag( xTaskHandle xTask, pdTASK_HOOK_CODE pxHookFunction );
+ *
+ * Sets pxHookFunction to be the task hook function used by the task xTask.
+ * Passing xTask as NULL has the effect of setting the calling tasks hook
+ * function.
+ */
+ void vTaskSetApplicationTaskTag( xTaskHandle xTask, pdTASK_HOOK_CODE pxHookFunction ) PRIVILEGED_FUNCTION;
+
+ /**
+ * task.h
+ * void xTaskGetApplicationTaskTag( xTaskHandle xTask );
+ *
+ * Returns the pxHookFunction value assigned to the task xTask.
+ */
+ pdTASK_HOOK_CODE xTaskGetApplicationTaskTag( xTaskHandle xTask ) PRIVILEGED_FUNCTION;
+ #endif /* configUSE_APPLICATION_TASK_TAG ==1 */
+#endif /* ifdef configUSE_APPLICATION_TASK_TAG */
+
+/**
+ * task.h
+ * portBASE_TYPE xTaskCallApplicationTaskHook( xTaskHandle xTask, pdTASK_HOOK_CODE pxHookFunction );
+ *
+ * Calls the hook function associated with xTask. Passing xTask as NULL has
+ * the effect of calling the Running tasks (the calling task) hook function.
+ *
+ * pvParameter is passed to the hook function for the task to interpret as it
+ * wants.
+ */
+portBASE_TYPE xTaskCallApplicationTaskHook( xTaskHandle xTask, void *pvParameter ) PRIVILEGED_FUNCTION;
+
+
+/*-----------------------------------------------------------
+ * SCHEDULER INTERNALS AVAILABLE FOR PORTING PURPOSES
+ *----------------------------------------------------------*/
+
+/*
+ * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS ONLY
+ * INTENDED FOR USE WHEN IMPLEMENTING A PORT OF THE SCHEDULER AND IS
+ * AN INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER.
+ *
+ * Called from the real time kernel tick (either preemptive or cooperative),
+ * this increments the tick count and checks if any tasks that are blocked
+ * for a finite period required removing from a blocked list and placing on
+ * a ready list.
+ */
+void vTaskIncrementTick( void ) PRIVILEGED_FUNCTION;
+
+/*
+ * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN
+ * INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER.
+ *
+ * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED.
+ *
+ * Removes the calling task from the ready list and places it both
+ * on the list of tasks waiting for a particular event, and the
+ * list of delayed tasks. The task will be removed from both lists
+ * and replaced on the ready list should either the event occur (and
+ * there be no higher priority tasks waiting on the same event) or
+ * the delay period expires.
+ *
+ * @param pxEventList The list containing tasks that are blocked waiting
+ * for the event to occur.
+ *
+ * @param xTicksToWait The maximum amount of time that the task should wait
+ * for the event to occur. This is specified in kernel ticks,the constant
+ * portTICK_RATE_MS can be used to convert kernel ticks into a real time
+ * period.
+ */
+void vTaskPlaceOnEventList( const xList * const pxEventList, portTickType xTicksToWait ) PRIVILEGED_FUNCTION;
+
+/*
+ * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN
+ * INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER.
+ *
+ * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED.
+ *
+ * This function performs nearly the same function as vTaskPlaceOnEventList().
+ * The difference being that this function does not permit tasks to block
+ * indefinitely, whereas vTaskPlaceOnEventList() does.
+ *
+ * @return pdTRUE if the task being removed has a higher priority than the task
+ * making the call, otherwise pdFALSE.
+ */
+void vTaskPlaceOnEventListRestricted( const xList * const pxEventList, portTickType xTicksToWait ) PRIVILEGED_FUNCTION;
+
+/*
+ * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN
+ * INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER.
+ *
+ * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED.
+ *
+ * Removes a task from both the specified event list and the list of blocked
+ * tasks, and places it on a ready queue.
+ *
+ * xTaskRemoveFromEventList () will be called if either an event occurs to
+ * unblock a task, or the block timeout period expires.
+ *
+ * @return pdTRUE if the task being removed has a higher priority than the task
+ * making the call, otherwise pdFALSE.
+ */
+signed portBASE_TYPE xTaskRemoveFromEventList( const xList * const pxEventList ) PRIVILEGED_FUNCTION;
+
+/*
+ * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN
+ * INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER.
+ *
+ * INCLUDE_vTaskCleanUpResources and INCLUDE_vTaskSuspend must be defined as 1
+ * for this function to be available.
+ * See the configuration section for more information.
+ *
+ * Empties the ready and delayed queues of task control blocks, freeing the
+ * memory allocated for the task control block and task stacks as it goes.
+ */
+void vTaskCleanUpResources( void ) PRIVILEGED_FUNCTION;
+
+/*
+ * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS ONLY
+ * INTENDED FOR USE WHEN IMPLEMENTING A PORT OF THE SCHEDULER AND IS
+ * AN INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER.
+ *
+ * Sets the pointer to the current TCB to the TCB of the highest priority task
+ * that is ready to run.
+ */
+void vTaskSwitchContext( void ) PRIVILEGED_FUNCTION;
+
+/*
+ * Return the handle of the calling task.
+ */
+xTaskHandle xTaskGetCurrentTaskHandle( void ) PRIVILEGED_FUNCTION;
+
+/*
+ * Capture the current time status for future reference.
+ */
+void vTaskSetTimeOutState( xTimeOutType * const pxTimeOut ) PRIVILEGED_FUNCTION;
+
+/*
+ * Compare the time status now with that previously captured to see if the
+ * timeout has expired.
+ */
+portBASE_TYPE xTaskCheckForTimeOut( xTimeOutType * const pxTimeOut, portTickType * const pxTicksToWait ) PRIVILEGED_FUNCTION;
+
+/*
+ * Shortcut used by the queue implementation to prevent unnecessary call to
+ * taskYIELD();
+ */
+void vTaskMissedYield( void ) PRIVILEGED_FUNCTION;
+
+/*
+ * Returns the scheduler state as taskSCHEDULER_RUNNING,
+ * taskSCHEDULER_NOT_STARTED or taskSCHEDULER_SUSPENDED.
+ */
+portBASE_TYPE xTaskGetSchedulerState( void ) PRIVILEGED_FUNCTION;
+
+/*
+ * Raises the priority of the mutex holder to that of the calling task should
+ * the mutex holder have a priority less than the calling task.
+ */
+void vTaskPriorityInherit( xTaskHandle * const pxMutexHolder ) PRIVILEGED_FUNCTION;
+
+/*
+ * Set the priority of a task back to its proper priority in the case that it
+ * inherited a higher priority while it was holding a semaphore.
+ */
+void vTaskPriorityDisinherit( xTaskHandle * const pxMutexHolder ) PRIVILEGED_FUNCTION;
+
+/*
+ * Generic version of the task creation function which is in turn called by the
+ * xTaskCreate() and xTaskCreateRestricted() macros.
+ */
+signed portBASE_TYPE xTaskGenericCreate( pdTASK_CODE pxTaskCode, const signed char * const pcName, unsigned short usStackDepth, void *pvParameters, unsigned portBASE_TYPE uxPriority, xTaskHandle *pxCreatedTask, portSTACK_TYPE *puxStackBuffer, const xMemoryRegion * const xRegions ) PRIVILEGED_FUNCTION;
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* TASK_H */
+
+
+
diff --git a/Libmaple/libmaple/libraries/FreeRTOS/utility/tasks.c b/Libmaple/libmaple/libraries/FreeRTOS/utility/tasks.c
index 020443d3..d48dd4dd 100644
--- a/Libmaple/libmaple/libraries/FreeRTOS/utility/tasks.c
+++ b/Libmaple/libmaple/libraries/FreeRTOS/utility/tasks.c
@@ -1,2522 +1,2522 @@
-/*
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.
-
-
- FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:
- Atollic AB - Atollic provides professional embedded systems development
- tools for C/C++ development, code analysis and test automation.
- See http://www.atollic.com
-
-
- ***************************************************************************
- * *
- * FreeRTOS tutorial books are available in pdf and paperback. *
- * Complete, revised, and edited pdf reference manuals are also *
- * available. *
- * *
- * Purchasing FreeRTOS documentation will not only help you, by *
- * ensuring you get running as quickly as possible and with an *
- * in-depth knowledge of how to use FreeRTOS, it will also help *
- * the FreeRTOS project to continue with its mission of providing *
- * professional grade, cross platform, de facto standard solutions *
- * for microcontrollers - completely free of charge! *
- * *
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
- * *
- * Thank you for using FreeRTOS, and thank you for your support! *
- * *
- ***************************************************************************
-
-
- This file is part of the FreeRTOS distribution.
-
- FreeRTOS is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License (version 2) as published by the
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
- >>>NOTE<<< The modification to the GPL is included to allow you to
- distribute a combined work that includes FreeRTOS without being obliged to
- provide the source code for proprietary components outside of the FreeRTOS
- kernel. FreeRTOS is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- more details. You should have received a copy of the GNU General Public
- License and the FreeRTOS license exception along with FreeRTOS; if not it
- can be viewed here: http://www.freertos.org/a00114.html and also obtained
- by writing to Richard Barry, contact details for whom are available on the
- FreeRTOS WEB site.
-
- 1 tab == 4 spaces!
-
- http://www.FreeRTOS.org - Documentation, latest information, license and
- contact details.
-
- http://www.SafeRTOS.com - A version that is certified for use in safety
- critical systems.
-
- http://www.OpenRTOS.com - Commercial support, development, porting,
- licensing and training services.
-*/
-
-
-#include
-#include
-#include
-
-/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
-all the API functions to use the MPU wrappers. That should only be done when
-task.h is included from an application file. */
-#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
-
-#include "FreeRTOS.h"
-#include "task.h"
-#include "timers.h"
-#include "StackMacros.h"
-
-#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
-
-/*
- * Macro to define the amount of stack available to the idle task.
- */
-#define tskIDLE_STACK_SIZE configMINIMAL_STACK_SIZE
-
-/*
- * Task control block. A task control block (TCB) is allocated to each task,
- * and stores the context of the task.
- */
-typedef struct tskTaskControlBlock
-{
- volatile portSTACK_TYPE *pxTopOfStack; /*< Points to the location of the last item placed on the tasks stack. THIS MUST BE THE FIRST MEMBER OF THE STRUCT. */
-
- #if ( portUSING_MPU_WRAPPERS == 1 )
- xMPU_SETTINGS xMPUSettings; /*< The MPU settings are defined as part of the port layer. THIS MUST BE THE SECOND MEMBER OF THE STRUCT. */
- #endif
-
- xListItem xGenericListItem; /*< List item used to place the TCB in ready and blocked queues. */
- xListItem xEventListItem; /*< List item used to place the TCB in event lists. */
- unsigned portBASE_TYPE uxPriority; /*< The priority of the task where 0 is the lowest priority. */
- portSTACK_TYPE *pxStack; /*< Points to the start of the stack. */
- signed char pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created. Facilitates debugging only. */
-
- #if ( portSTACK_GROWTH > 0 )
- portSTACK_TYPE *pxEndOfStack; /*< Used for stack overflow checking on architectures where the stack grows up from low memory. */
- #endif
-
- #if ( portCRITICAL_NESTING_IN_TCB == 1 )
- unsigned portBASE_TYPE uxCriticalNesting;
- #endif
-
- #if ( configUSE_TRACE_FACILITY == 1 )
- unsigned portBASE_TYPE uxTCBNumber; /*< This is used for tracing the scheduler and making debugging easier only. */
- #endif
-
- #if ( configUSE_MUTEXES == 1 )
- unsigned portBASE_TYPE uxBasePriority; /*< The priority last assigned to the task - used by the priority inheritance mechanism. */
- #endif
-
- #if ( configUSE_APPLICATION_TASK_TAG == 1 )
- pdTASK_HOOK_CODE pxTaskTag;
- #endif
-
- #if ( configGENERATE_RUN_TIME_STATS == 1 )
- unsigned long ulRunTimeCounter; /*< Used for calculating how much CPU time each task is utilising. */
- #endif
-
-} tskTCB;
-
-
-/*
- * Some kernel aware debuggers require data to be viewed to be global, rather
- * than file scope.
- */
-#ifdef portREMOVE_STATIC_QUALIFIER
- #define static
-#endif
-
-/*lint -e956 */
-PRIVILEGED_DATA tskTCB * volatile pxCurrentTCB = NULL;
-
-/* Lists for ready and blocked tasks. --------------------*/
-
-PRIVILEGED_DATA static xList pxReadyTasksLists[ configMAX_PRIORITIES ]; /*< Prioritised ready tasks. */
-PRIVILEGED_DATA static xList xDelayedTaskList1; /*< Delayed tasks. */
-PRIVILEGED_DATA static xList xDelayedTaskList2; /*< Delayed tasks (two lists are used - one for delays that have overflowed the current tick count. */
-PRIVILEGED_DATA static xList * volatile pxDelayedTaskList ; /*< Points to the delayed task list currently being used. */
-PRIVILEGED_DATA static xList * volatile pxOverflowDelayedTaskList; /*< Points to the delayed task list currently being used to hold tasks that have overflowed the current tick count. */
-PRIVILEGED_DATA static xList xPendingReadyList; /*< Tasks that have been readied while the scheduler was suspended. They will be moved to the ready queue when the scheduler is resumed. */
-
-#if ( INCLUDE_vTaskDelete == 1 )
-
- PRIVILEGED_DATA static volatile xList xTasksWaitingTermination; /*< Tasks that have been deleted - but the their memory not yet freed. */
- PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxTasksDeleted = ( unsigned portBASE_TYPE ) 0;
-
-#endif
-
-#if ( INCLUDE_vTaskSuspend == 1 )
-
- PRIVILEGED_DATA static xList xSuspendedTaskList; /*< Tasks that are currently suspended. */
-
-#endif
-
-/* File private variables. --------------------------------*/
-PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxCurrentNumberOfTasks = ( unsigned portBASE_TYPE ) 0;
-PRIVILEGED_DATA static volatile portTickType xTickCount = ( portTickType ) 0;
-PRIVILEGED_DATA static unsigned portBASE_TYPE uxTopUsedPriority = tskIDLE_PRIORITY;
-PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxTopReadyPriority = tskIDLE_PRIORITY;
-PRIVILEGED_DATA static volatile signed portBASE_TYPE xSchedulerRunning = pdFALSE;
-PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxSchedulerSuspended = ( unsigned portBASE_TYPE ) pdFALSE;
-PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxMissedTicks = ( unsigned portBASE_TYPE ) 0;
-PRIVILEGED_DATA static volatile portBASE_TYPE xMissedYield = ( portBASE_TYPE ) pdFALSE;
-PRIVILEGED_DATA static volatile portBASE_TYPE xNumOfOverflows = ( portBASE_TYPE ) 0;
-PRIVILEGED_DATA static unsigned portBASE_TYPE uxTaskNumber = ( unsigned portBASE_TYPE ) 0;
-PRIVILEGED_DATA static portTickType xNextTaskUnblockTime = ( portTickType ) portMAX_DELAY;
-
-#if ( configGENERATE_RUN_TIME_STATS == 1 )
-
- PRIVILEGED_DATA static char pcStatsString[ 50 ] ;
- PRIVILEGED_DATA static unsigned long ulTaskSwitchedInTime = 0UL; /*< Holds the value of a timer/counter the last time a task was switched in. */
- static void prvGenerateRunTimeStatsForTasksInList( const signed char *pcWriteBuffer, xList *pxList, unsigned long ulTotalRunTime ) PRIVILEGED_FUNCTION;
-
-#endif
-
-/* Debugging and trace facilities private variables and macros. ------------*/
-
-/*
- * The value used to fill the stack of a task when the task is created. This
- * is used purely for checking the high water mark for tasks.
- */
-#define tskSTACK_FILL_BYTE ( 0xa5U )
-
-/*
- * Macros used by vListTask to indicate which state a task is in.
- */
-#define tskBLOCKED_CHAR ( ( signed char ) 'B' )
-#define tskREADY_CHAR ( ( signed char ) 'R' )
-#define tskDELETED_CHAR ( ( signed char ) 'D' )
-#define tskSUSPENDED_CHAR ( ( signed char ) 'S' )
-
-/*
- * Macros and private variables used by the trace facility.
- */
-#if ( configUSE_TRACE_FACILITY == 1 )
-
- #define tskSIZE_OF_EACH_TRACE_LINE ( ( unsigned long ) ( sizeof( unsigned long ) + sizeof( unsigned long ) ) )
- PRIVILEGED_DATA static volatile signed char * volatile pcTraceBuffer;
- PRIVILEGED_DATA static signed char *pcTraceBufferStart;
- PRIVILEGED_DATA static signed char *pcTraceBufferEnd;
- PRIVILEGED_DATA static signed portBASE_TYPE xTracing = pdFALSE;
- static unsigned portBASE_TYPE uxPreviousTask = 255U;
- PRIVILEGED_DATA static char pcStatusString[ 50 ];
-
-#endif
-
-/*-----------------------------------------------------------*/
-
-/*
- * Macro that writes a trace of scheduler activity to a buffer. This trace
- * shows which task is running when and is very useful as a debugging tool.
- * As this macro is called each context switch it is a good idea to undefine
- * it if not using the facility.
- */
-#if ( configUSE_TRACE_FACILITY == 1 )
-
- #define vWriteTraceToBuffer() \
- { \
- if( xTracing ) \
- { \
- if( uxPreviousTask != pxCurrentTCB->uxTCBNumber ) \
- { \
- if( ( pcTraceBuffer + tskSIZE_OF_EACH_TRACE_LINE ) < pcTraceBufferEnd ) \
- { \
- uxPreviousTask = pxCurrentTCB->uxTCBNumber; \
- *( unsigned long * ) pcTraceBuffer = ( unsigned long ) xTickCount; \
- pcTraceBuffer += sizeof( unsigned long ); \
- *( unsigned long * ) pcTraceBuffer = ( unsigned long ) uxPreviousTask; \
- pcTraceBuffer += sizeof( unsigned long ); \
- } \
- else \
- { \
- xTracing = pdFALSE; \
- } \
- } \
- } \
- }
-
-#else
-
- #define vWriteTraceToBuffer()
-
-#endif
-/*-----------------------------------------------------------*/
-
-/*
- * Place the task represented by pxTCB into the appropriate ready queue for
- * the task. It is inserted at the end of the list. One quirk of this is
- * that if the task being inserted is at the same priority as the currently
- * executing task, then it will only be rescheduled after the currently
- * executing task has been rescheduled.
- */
-#define prvAddTaskToReadyQueue( pxTCB ) \
- if( ( pxTCB )->uxPriority > uxTopReadyPriority ) \
- { \
- uxTopReadyPriority = ( pxTCB )->uxPriority; \
- } \
- vListInsertEnd( ( xList * ) &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xGenericListItem ) )
-/*-----------------------------------------------------------*/
-
-/*
- * Macro that looks at the list of tasks that are currently delayed to see if
- * any require waking.
- *
- * Tasks are stored in the queue in the order of their wake time - meaning
- * once one tasks has been found whose timer has not expired we need not look
- * any further down the list.
- */
-#define prvCheckDelayedTasks() \
-{ \
-portTickType xItemValue; \
- \
- /* Is the tick count greater than or equal to the wake time of the first \
- task referenced from the delayed tasks list? */ \
- if( xTickCount >= xNextTaskUnblockTime ) \
- { \
- for( ;; ) \
- { \
- if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE ) \
- { \
- /* The delayed list is empty. Set xNextTaskUnblockTime to the \
- maximum possible value so it is extremely unlikely that the \
- if( xTickCount >= xNextTaskUnblockTime ) test will pass next \
- time through. */ \
- xNextTaskUnblockTime = portMAX_DELAY; \
- break; \
- } \
- else \
- { \
- /* The delayed list is not empty, get the value of the item at \
- the head of the delayed list. This is the time at which the \
- task at the head of the delayed list should be removed from \
- the Blocked state. */ \
- pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ); \
- xItemValue = listGET_LIST_ITEM_VALUE( &( pxTCB->xGenericListItem ) ); \
- \
- if( xTickCount < xItemValue ) \
- { \
- /* It is not time to unblock this item yet, but the item \
- value is the time at which the task at the head of the \
- blocked list should be removed from the Blocked state - \
- so record the item value in xNextTaskUnblockTime. */ \
- xNextTaskUnblockTime = xItemValue; \
- break; \
- } \
- \
- /* It is time to remove the item from the Blocked state. */ \
- vListRemove( &( pxTCB->xGenericListItem ) ); \
- \
- /* Is the task waiting on an event also? */ \
- if( pxTCB->xEventListItem.pvContainer ) \
- { \
- vListRemove( &( pxTCB->xEventListItem ) ); \
- } \
- prvAddTaskToReadyQueue( pxTCB ); \
- } \
- } \
- } \
-}
-/*-----------------------------------------------------------*/
-
-/*
- * Several functions take an xTaskHandle parameter that can optionally be NULL,
- * where NULL is used to indicate that the handle of the currently executing
- * task should be used in place of the parameter. This macro simply checks to
- * see if the parameter is NULL and returns a pointer to the appropriate TCB.
- */
-#define prvGetTCBFromHandle( pxHandle ) ( ( ( pxHandle ) == NULL ) ? ( tskTCB * ) pxCurrentTCB : ( tskTCB * ) ( pxHandle ) )
-
-/* Callback function prototypes. --------------------------*/
-extern void vApplicationStackOverflowHook( xTaskHandle *pxTask, signed char *pcTaskName );
-extern void vApplicationTickHook( void );
-
-/* File private functions. --------------------------------*/
-
-/*
- * Utility to ready a TCB for a given task. Mainly just copies the parameters
- * into the TCB structure.
- */
-static void prvInitialiseTCBVariables( tskTCB *pxTCB, const signed char * const pcName, unsigned portBASE_TYPE uxPriority, const xMemoryRegion * const xRegions, unsigned short usStackDepth ) PRIVILEGED_FUNCTION;
-
-/*
- * Utility to ready all the lists used by the scheduler. This is called
- * automatically upon the creation of the first task.
- */
-static void prvInitialiseTaskLists( void ) PRIVILEGED_FUNCTION;
-
-/*
- * The idle task, which as all tasks is implemented as a never ending loop.
- * The idle task is automatically created and added to the ready lists upon
- * creation of the first user task.
- *
- * The portTASK_FUNCTION_PROTO() macro is used to allow port/compiler specific
- * language extensions. The equivalent prototype for this function is:
- *
- * void prvIdleTask( void *pvParameters );
- *
- */
-static portTASK_FUNCTION_PROTO( prvIdleTask, pvParameters );
-
-/*
- * Utility to free all memory allocated by the scheduler to hold a TCB,
- * including the stack pointed to by the TCB.
- *
- * This does not free memory allocated by the task itself (i.e. memory
- * allocated by calls to pvPortMalloc from within the tasks application code).
- */
-#if ( ( INCLUDE_vTaskDelete == 1 ) || ( INCLUDE_vTaskCleanUpResources == 1 ) )
-
- static void prvDeleteTCB( tskTCB *pxTCB ) PRIVILEGED_FUNCTION;
-
-#endif
-
-/*
- * Used only by the idle task. This checks to see if anything has been placed
- * in the list of tasks waiting to be deleted. If so the task is cleaned up
- * and its TCB deleted.
- */
-static void prvCheckTasksWaitingTermination( void ) PRIVILEGED_FUNCTION;
-
-/*
- * The currently executing task is entering the Blocked state. Add the task to
- * either the current or the overflow delayed task list.
- */
-static void prvAddCurrentTaskToDelayedList( portTickType xTimeToWake ) PRIVILEGED_FUNCTION;
-
-/*
- * Allocates memory from the heap for a TCB and associated stack. Checks the
- * allocation was successful.
- */
-static tskTCB *prvAllocateTCBAndStack( unsigned short usStackDepth, portSTACK_TYPE *puxStackBuffer ) PRIVILEGED_FUNCTION;
-
-/*
- * Called from vTaskList. vListTasks details all the tasks currently under
- * control of the scheduler. The tasks may be in one of a number of lists.
- * prvListTaskWithinSingleList accepts a list and details the tasks from
- * within just that list.
- *
- * THIS FUNCTION IS INTENDED FOR DEBUGGING ONLY, AND SHOULD NOT BE CALLED FROM
- * NORMAL APPLICATION CODE.
- */
-#if ( configUSE_TRACE_FACILITY == 1 )
-
- static void prvListTaskWithinSingleList( const signed char *pcWriteBuffer, xList *pxList, signed char cStatus ) PRIVILEGED_FUNCTION;
-
-#endif
-
-/*
- * When a task is created, the stack of the task is filled with a known value.
- * This function determines the 'high water mark' of the task stack by
- * determining how much of the stack remains at the original preset value.
- */
-#if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )
-
- static unsigned short usTaskCheckFreeStackSpace( const unsigned char * pucStackByte ) PRIVILEGED_FUNCTION;
-
-#endif
-
-
-/*lint +e956 */
-
-
-
-/*-----------------------------------------------------------
- * TASK CREATION API documented in task.h
- *----------------------------------------------------------*/
-
-signed portBASE_TYPE xTaskGenericCreate( pdTASK_CODE pxTaskCode, const signed char * const pcName, unsigned short usStackDepth, void *pvParameters, unsigned portBASE_TYPE uxPriority, xTaskHandle *pxCreatedTask, portSTACK_TYPE *puxStackBuffer, const xMemoryRegion * const xRegions )
-{
-signed portBASE_TYPE xReturn;
-tskTCB * pxNewTCB;
-
- configASSERT( pxTaskCode );
- configASSERT( ( uxPriority < configMAX_PRIORITIES ) );
-
- /* Allocate the memory required by the TCB and stack for the new task,
- checking that the allocation was successful. */
- pxNewTCB = prvAllocateTCBAndStack( usStackDepth, puxStackBuffer );
-
- if( pxNewTCB != NULL )
- {
- portSTACK_TYPE *pxTopOfStack;
-
- #if( portUSING_MPU_WRAPPERS == 1 )
- /* Should the task be created in privileged mode? */
- portBASE_TYPE xRunPrivileged;
- if( ( uxPriority & portPRIVILEGE_BIT ) != 0x00 )
- {
- xRunPrivileged = pdTRUE;
- }
- else
- {
- xRunPrivileged = pdFALSE;
- }
- uxPriority &= ~portPRIVILEGE_BIT;
- #endif /* portUSING_MPU_WRAPPERS == 1 */
-
- /* Calculate the top of stack address. This depends on whether the
- stack grows from high memory to low (as per the 80x86) or visa versa.
- portSTACK_GROWTH is used to make the result positive or negative as
- required by the port. */
- #if( portSTACK_GROWTH < 0 )
- {
- pxTopOfStack = pxNewTCB->pxStack + ( usStackDepth - ( unsigned short ) 1 );
- pxTopOfStack = ( portSTACK_TYPE * ) ( ( ( unsigned long ) pxTopOfStack ) & ( ( unsigned long ) ~portBYTE_ALIGNMENT_MASK ) );
-
- /* Check the alignment of the calculated top of stack is correct. */
- configASSERT( ( ( ( unsigned long ) pxTopOfStack & ( unsigned long ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );
- }
- #else
- {
- pxTopOfStack = pxNewTCB->pxStack;
-
- /* Check the alignment of the stack buffer is correct. */
- configASSERT( ( ( ( unsigned long ) pxNewTCB->pxStack & ( unsigned long ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );
-
- /* If we want to use stack checking on architectures that use
- a positive stack growth direction then we also need to store the
- other extreme of the stack space. */
- pxNewTCB->pxEndOfStack = pxNewTCB->pxStack + ( usStackDepth - 1 );
- }
- #endif
-
- /* Setup the newly allocated TCB with the initial state of the task. */
- prvInitialiseTCBVariables( pxNewTCB, pcName, uxPriority, xRegions, usStackDepth );
-
- /* Initialize the TCB stack to look as if the task was already running,
- but had been interrupted by the scheduler. The return address is set
- to the start of the task function. Once the stack has been initialised
- the top of stack variable is updated. */
- #if( portUSING_MPU_WRAPPERS == 1 )
- {
- pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters, xRunPrivileged );
- }
- #else
- {
- pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters );
- }
- #endif
-
- /* Check the alignment of the initialised stack. */
- configASSERT( ( ( ( unsigned long ) pxNewTCB->pxTopOfStack & ( unsigned long ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );
-
- if( ( void * ) pxCreatedTask != NULL )
- {
- /* Pass the TCB out - in an anonymous way. The calling function/
- task can use this as a handle to delete the task later if
- required.*/
- *pxCreatedTask = ( xTaskHandle ) pxNewTCB;
- }
-
- /* We are going to manipulate the task queues to add this task to a
- ready list, so must make sure no interrupts occur. */
- taskENTER_CRITICAL();
- {
- uxCurrentNumberOfTasks++;
- if( pxCurrentTCB == NULL )
- {
- /* There are no other tasks, or all the other tasks are in
- the suspended state - make this the current task. */
- pxCurrentTCB = pxNewTCB;
-
- if( uxCurrentNumberOfTasks == ( unsigned portBASE_TYPE ) 1 )
- {
- /* This is the first task to be created so do the preliminary
- initialisation required. We will not recover if this call
- fails, but we will report the failure. */
- prvInitialiseTaskLists();
- }
- }
- else
- {
- /* If the scheduler is not already running, make this task the
- current task if it is the highest priority task to be created
- so far. */
- if( xSchedulerRunning == pdFALSE )
- {
- if( pxCurrentTCB->uxPriority <= uxPriority )
- {
- pxCurrentTCB = pxNewTCB;
- }
- }
- }
-
- /* Remember the top priority to make context switching faster. Use
- the priority in pxNewTCB as this has been capped to a valid value. */
- if( pxNewTCB->uxPriority > uxTopUsedPriority )
- {
- uxTopUsedPriority = pxNewTCB->uxPriority;
- }
-
- #if ( configUSE_TRACE_FACILITY == 1 )
- {
- /* Add a counter into the TCB for tracing only. */
- pxNewTCB->uxTCBNumber = uxTaskNumber;
- }
- #endif
- uxTaskNumber++;
-
- prvAddTaskToReadyQueue( pxNewTCB );
-
- xReturn = pdPASS;
- traceTASK_CREATE( pxNewTCB );
- }
- taskEXIT_CRITICAL();
- }
- else
- {
- xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
- traceTASK_CREATE_FAILED();
- }
-
- if( xReturn == pdPASS )
- {
- if( xSchedulerRunning != pdFALSE )
- {
- /* If the created task is of a higher priority than the current task
- then it should run now. */
- if( pxCurrentTCB->uxPriority < uxPriority )
- {
- portYIELD_WITHIN_API();
- }
- }
- }
-
- return xReturn;
-}
-/*-----------------------------------------------------------*/
-
-#if ( INCLUDE_vTaskDelete == 1 )
-
- void vTaskDelete( xTaskHandle pxTaskToDelete )
- {
- tskTCB *pxTCB;
-
- taskENTER_CRITICAL();
- {
- /* Ensure a yield is performed if the current task is being
- deleted. */
- if( pxTaskToDelete == pxCurrentTCB )
- {
- pxTaskToDelete = NULL;
- }
-
- /* If null is passed in here then we are deleting ourselves. */
- pxTCB = prvGetTCBFromHandle( pxTaskToDelete );
-
- /* Remove task from the ready list and place in the termination list.
- This will stop the task from be scheduled. The idle task will check
- the termination list and free up any memory allocated by the
- scheduler for the TCB and stack. */
- vListRemove( &( pxTCB->xGenericListItem ) );
-
- /* Is the task waiting on an event also? */
- if( pxTCB->xEventListItem.pvContainer )
- {
- vListRemove( &( pxTCB->xEventListItem ) );
- }
-
- vListInsertEnd( ( xList * ) &xTasksWaitingTermination, &( pxTCB->xGenericListItem ) );
-
- /* Increment the ucTasksDeleted variable so the idle task knows
- there is a task that has been deleted and that it should therefore
- check the xTasksWaitingTermination list. */
- ++uxTasksDeleted;
-
- /* Increment the uxTaskNumberVariable also so kernel aware debuggers
- can detect that the task lists need re-generating. */
- uxTaskNumber++;
-
- traceTASK_DELETE( pxTCB );
- }
- taskEXIT_CRITICAL();
-
- /* Force a reschedule if we have just deleted the current task. */
- if( xSchedulerRunning != pdFALSE )
- {
- if( ( void * ) pxTaskToDelete == NULL )
- {
- portYIELD_WITHIN_API();
- }
- }
- }
-
-#endif
-
-
-
-
-
-
-/*-----------------------------------------------------------
- * TASK CONTROL API documented in task.h
- *----------------------------------------------------------*/
-
-#if ( INCLUDE_vTaskDelayUntil == 1 )
-
- void vTaskDelayUntil( portTickType * const pxPreviousWakeTime, portTickType xTimeIncrement )
- {
- portTickType xTimeToWake;
- portBASE_TYPE xAlreadyYielded, xShouldDelay = pdFALSE;
-
- configASSERT( pxPreviousWakeTime );
- configASSERT( ( xTimeIncrement > 0 ) );
-
- vTaskSuspendAll();
- {
- /* Generate the tick time at which the task wants to wake. */
- xTimeToWake = *pxPreviousWakeTime + xTimeIncrement;
-
- if( xTickCount < *pxPreviousWakeTime )
- {
- /* The tick count has overflowed since this function was
- lasted called. In this case the only time we should ever
- actually delay is if the wake time has also overflowed,
- and the wake time is greater than the tick time. When this
- is the case it is as if neither time had overflowed. */
- if( ( xTimeToWake < *pxPreviousWakeTime ) && ( xTimeToWake > xTickCount ) )
- {
- xShouldDelay = pdTRUE;
- }
- }
- else
- {
- /* The tick time has not overflowed. In this case we will
- delay if either the wake time has overflowed, and/or the
- tick time is less than the wake time. */
- if( ( xTimeToWake < *pxPreviousWakeTime ) || ( xTimeToWake > xTickCount ) )
- {
- xShouldDelay = pdTRUE;
- }
- }
-
- /* Update the wake time ready for the next call. */
- *pxPreviousWakeTime = xTimeToWake;
-
- if( xShouldDelay != pdFALSE )
- {
- traceTASK_DELAY_UNTIL();
-
- /* We must remove ourselves from the ready list before adding
- ourselves to the blocked list as the same list item is used for
- both lists. */
- vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
- prvAddCurrentTaskToDelayedList( xTimeToWake );
- }
- }
- xAlreadyYielded = xTaskResumeAll();
-
- /* Force a reschedule if xTaskResumeAll has not already done so, we may
- have put ourselves to sleep. */
- if( !xAlreadyYielded )
- {
- portYIELD_WITHIN_API();
- }
- }
-
-#endif
-/*-----------------------------------------------------------*/
-
-#if ( INCLUDE_vTaskDelay == 1 )
-
- void vTaskDelay( portTickType xTicksToDelay )
- {
- portTickType xTimeToWake;
- signed portBASE_TYPE xAlreadyYielded = pdFALSE;
-
- /* A delay time of zero just forces a reschedule. */
- if( xTicksToDelay > ( portTickType ) 0 )
- {
- vTaskSuspendAll();
- {
- traceTASK_DELAY();
-
- /* A task that is removed from the event list while the
- scheduler is suspended will not get placed in the ready
- list or removed from the blocked list until the scheduler
- is resumed.
-
- This task cannot be in an event list as it is the currently
- executing task. */
-
- /* Calculate the time to wake - this may overflow but this is
- not a problem. */
- xTimeToWake = xTickCount + xTicksToDelay;
-
- /* We must remove ourselves from the ready list before adding
- ourselves to the blocked list as the same list item is used for
- both lists. */
- vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
- prvAddCurrentTaskToDelayedList( xTimeToWake );
- }
- xAlreadyYielded = xTaskResumeAll();
- }
-
- /* Force a reschedule if xTaskResumeAll has not already done so, we may
- have put ourselves to sleep. */
- if( !xAlreadyYielded )
- {
- portYIELD_WITHIN_API();
- }
- }
-
-#endif
-/*-----------------------------------------------------------*/
-
-#if ( INCLUDE_uxTaskPriorityGet == 1 )
-
- unsigned portBASE_TYPE uxTaskPriorityGet( xTaskHandle pxTask )
- {
- tskTCB *pxTCB;
- unsigned portBASE_TYPE uxReturn;
-
- taskENTER_CRITICAL();
- {
- /* If null is passed in here then we are changing the
- priority of the calling function. */
- pxTCB = prvGetTCBFromHandle( pxTask );
- uxReturn = pxTCB->uxPriority;
- }
- taskEXIT_CRITICAL();
-
- return uxReturn;
- }
-
-#endif
-/*-----------------------------------------------------------*/
-
-#if ( INCLUDE_vTaskPrioritySet == 1 )
-
- void vTaskPrioritySet( xTaskHandle pxTask, unsigned portBASE_TYPE uxNewPriority )
- {
- tskTCB *pxTCB;
- unsigned portBASE_TYPE uxCurrentPriority;
- portBASE_TYPE xYieldRequired = pdFALSE;
-
- configASSERT( ( uxNewPriority < configMAX_PRIORITIES ) );
-
- /* Ensure the new priority is valid. */
- if( uxNewPriority >= configMAX_PRIORITIES )
- {
- uxNewPriority = configMAX_PRIORITIES - ( unsigned portBASE_TYPE ) 1U;
- }
-
- taskENTER_CRITICAL();
- {
- if( pxTask == pxCurrentTCB )
- {
- pxTask = NULL;
- }
-
- /* If null is passed in here then we are changing the
- priority of the calling function. */
- pxTCB = prvGetTCBFromHandle( pxTask );
-
- traceTASK_PRIORITY_SET( pxTask, uxNewPriority );
-
- #if ( configUSE_MUTEXES == 1 )
- {
- uxCurrentPriority = pxTCB->uxBasePriority;
- }
- #else
- {
- uxCurrentPriority = pxTCB->uxPriority;
- }
- #endif
-
- if( uxCurrentPriority != uxNewPriority )
- {
- /* The priority change may have readied a task of higher
- priority than the calling task. */
- if( uxNewPriority > uxCurrentPriority )
- {
- if( pxTask != NULL )
- {
- /* The priority of another task is being raised. If we
- were raising the priority of the currently running task
- there would be no need to switch as it must have already
- been the highest priority task. */
- xYieldRequired = pdTRUE;
- }
- }
- else if( pxTask == NULL )
- {
- /* Setting our own priority down means there may now be another
- task of higher priority that is ready to execute. */
- xYieldRequired = pdTRUE;
- }
-
-
-
- #if ( configUSE_MUTEXES == 1 )
- {
- /* Only change the priority being used if the task is not
- currently using an inherited priority. */
- if( pxTCB->uxBasePriority == pxTCB->uxPriority )
- {
- pxTCB->uxPriority = uxNewPriority;
- }
-
- /* The base priority gets set whatever. */
- pxTCB->uxBasePriority = uxNewPriority;
- }
- #else
- {
- pxTCB->uxPriority = uxNewPriority;
- }
- #endif
-
- listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( configMAX_PRIORITIES - ( portTickType ) uxNewPriority ) );
-
- /* If the task is in the blocked or suspended list we need do
- nothing more than change it's priority variable. However, if
- the task is in a ready list it needs to be removed and placed
- in the queue appropriate to its new priority. */
- if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxCurrentPriority ] ), &( pxTCB->xGenericListItem ) ) )
- {
- /* The task is currently in its ready list - remove before adding
- it to it's new ready list. As we are in a critical section we
- can do this even if the scheduler is suspended. */
- vListRemove( &( pxTCB->xGenericListItem ) );
- prvAddTaskToReadyQueue( pxTCB );
- }
-
- if( xYieldRequired == pdTRUE )
- {
- portYIELD_WITHIN_API();
- }
- }
- }
- taskEXIT_CRITICAL();
- }
-
-#endif
-/*-----------------------------------------------------------*/
-
-#if ( INCLUDE_vTaskSuspend == 1 )
-
- void vTaskSuspend( xTaskHandle pxTaskToSuspend )
- {
- tskTCB *pxTCB;
-
- taskENTER_CRITICAL();
- {
- /* Ensure a yield is performed if the current task is being
- suspended. */
- if( pxTaskToSuspend == pxCurrentTCB )
- {
- pxTaskToSuspend = NULL;
- }
-
- /* If null is passed in here then we are suspending ourselves. */
- pxTCB = prvGetTCBFromHandle( pxTaskToSuspend );
-
- traceTASK_SUSPEND( pxTCB );
-
- /* Remove task from the ready/delayed list and place in the suspended list. */
- vListRemove( &( pxTCB->xGenericListItem ) );
-
- /* Is the task waiting on an event also? */
- if( pxTCB->xEventListItem.pvContainer )
- {
- vListRemove( &( pxTCB->xEventListItem ) );
- }
-
- vListInsertEnd( ( xList * ) &xSuspendedTaskList, &( pxTCB->xGenericListItem ) );
- }
- taskEXIT_CRITICAL();
-
- if( ( void * ) pxTaskToSuspend == NULL )
- {
- if( xSchedulerRunning != pdFALSE )
- {
- /* We have just suspended the current task. */
- portYIELD_WITHIN_API();
- }
- else
- {
- /* The scheduler is not running, but the task that was pointed
- to by pxCurrentTCB has just been suspended and pxCurrentTCB
- must be adjusted to point to a different task. */
- if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == uxCurrentNumberOfTasks )
- {
- /* No other tasks are ready, so set pxCurrentTCB back to
- NULL so when the next task is created pxCurrentTCB will
- be set to point to it no matter what its relative priority
- is. */
- pxCurrentTCB = NULL;
- }
- else
- {
- vTaskSwitchContext();
- }
- }
- }
- }
-
-#endif
-/*-----------------------------------------------------------*/
-
-#if ( INCLUDE_vTaskSuspend == 1 )
-
- signed portBASE_TYPE xTaskIsTaskSuspended( xTaskHandle xTask )
- {
- portBASE_TYPE xReturn = pdFALSE;
- const tskTCB * const pxTCB = ( tskTCB * ) xTask;
-
- /* It does not make sense to check if the calling task is suspended. */
- configASSERT( xTask );
-
- /* Is the task we are attempting to resume actually in the
- suspended list? */
- if( listIS_CONTAINED_WITHIN( &xSuspendedTaskList, &( pxTCB->xGenericListItem ) ) != pdFALSE )
- {
- /* Has the task already been resumed from within an ISR? */
- if( listIS_CONTAINED_WITHIN( &xPendingReadyList, &( pxTCB->xEventListItem ) ) != pdTRUE )
- {
- /* Is it in the suspended list because it is in the
- Suspended state? It is possible to be in the suspended
- list because it is blocked on a task with no timeout
- specified. */
- if( listIS_CONTAINED_WITHIN( NULL, &( pxTCB->xEventListItem ) ) == pdTRUE )
- {
- xReturn = pdTRUE;
- }
- }
- }
-
- return xReturn;
- }
-
-#endif
-/*-----------------------------------------------------------*/
-
-#if ( INCLUDE_vTaskSuspend == 1 )
-
- void vTaskResume( xTaskHandle pxTaskToResume )
- {
- tskTCB *pxTCB;
-
- /* It does not make sense to resume the calling task. */
- configASSERT( pxTaskToResume );
-
- /* Remove the task from whichever list it is currently in, and place
- it in the ready list. */
- pxTCB = ( tskTCB * ) pxTaskToResume;
-
- /* The parameter cannot be NULL as it is impossible to resume the
- currently executing task. */
- if( ( pxTCB != NULL ) && ( pxTCB != pxCurrentTCB ) )
- {
- taskENTER_CRITICAL();
- {
- if( xTaskIsTaskSuspended( pxTCB ) == pdTRUE )
- {
- traceTASK_RESUME( pxTCB );
-
- /* As we are in a critical section we can access the ready
- lists even if the scheduler is suspended. */
- vListRemove( &( pxTCB->xGenericListItem ) );
- prvAddTaskToReadyQueue( pxTCB );
-
- /* We may have just resumed a higher priority task. */
- if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
- {
- /* This yield may not cause the task just resumed to run, but
- will leave the lists in the correct state for the next yield. */
- portYIELD_WITHIN_API();
- }
- }
- }
- taskEXIT_CRITICAL();
- }
- }
-
-#endif
-
-/*-----------------------------------------------------------*/
-
-#if ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )
-
- portBASE_TYPE xTaskResumeFromISR( xTaskHandle pxTaskToResume )
- {
- portBASE_TYPE xYieldRequired = pdFALSE;
- tskTCB *pxTCB;
-
- configASSERT( pxTaskToResume );
-
- pxTCB = ( tskTCB * ) pxTaskToResume;
-
- if( xTaskIsTaskSuspended( pxTCB ) == pdTRUE )
- {
- traceTASK_RESUME_FROM_ISR( pxTCB );
-
- if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
- {
- xYieldRequired = ( pxTCB->uxPriority >= pxCurrentTCB->uxPriority );
- vListRemove( &( pxTCB->xGenericListItem ) );
- prvAddTaskToReadyQueue( pxTCB );
- }
- else
- {
- /* We cannot access the delayed or ready lists, so will hold this
- task pending until the scheduler is resumed, at which point a
- yield will be performed if necessary. */
- vListInsertEnd( ( xList * ) &( xPendingReadyList ), &( pxTCB->xEventListItem ) );
- }
- }
-
- return xYieldRequired;
- }
-
-#endif
-
-
-
-
-/*-----------------------------------------------------------
- * PUBLIC SCHEDULER CONTROL documented in task.h
- *----------------------------------------------------------*/
-
-
-void vTaskStartScheduler( void )
-{
-portBASE_TYPE xReturn;
-
- /* Add the idle task at the lowest priority. */
- xReturn = xTaskCreate( prvIdleTask, ( signed char * ) "IDLE", tskIDLE_STACK_SIZE, ( void * ) NULL, ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), ( xTaskHandle * ) NULL );
-
- #if ( configUSE_TIMERS == 1 )
- {
- if( xReturn == pdPASS )
- {
- xReturn = xTimerCreateTimerTask();
- }
- }
- #endif
-
- if( xReturn == pdPASS )
- {
- /* Interrupts are turned off here, to ensure a tick does not occur
- before or during the call to xPortStartScheduler(). The stacks of
- the created tasks contain a status word with interrupts switched on
- so interrupts will automatically get re-enabled when the first task
- starts to run.
-
- STEPPING THROUGH HERE USING A DEBUGGER CAN CAUSE BIG PROBLEMS IF THE
- DEBUGGER ALLOWS INTERRUPTS TO BE PROCESSED. */
- portDISABLE_INTERRUPTS();
-
- xSchedulerRunning = pdTRUE;
- xTickCount = ( portTickType ) 0;
-
- /* If configGENERATE_RUN_TIME_STATS is defined then the following
- macro must be defined to configure the timer/counter used to generate
- the run time counter time base. */
- portCONFIGURE_TIMER_FOR_RUN_TIME_STATS();
-
- /* Setting up the timer tick is hardware specific and thus in the
- portable interface. */
- if( xPortStartScheduler() )
- {
- /* Should not reach here as if the scheduler is running the
- function will not return. */
- }
- else
- {
- /* Should only reach here if a task calls xTaskEndScheduler(). */
- }
- }
-
- /* This line will only be reached if the kernel could not be started. */
- configASSERT( xReturn );
-}
-/*-----------------------------------------------------------*/
-
-void vTaskEndScheduler( void )
-{
- /* Stop the scheduler interrupts and call the portable scheduler end
- routine so the original ISRs can be restored if necessary. The port
- layer must ensure interrupts enable bit is left in the correct state. */
- portDISABLE_INTERRUPTS();
- xSchedulerRunning = pdFALSE;
- vPortEndScheduler();
-}
-/*----------------------------------------------------------*/
-
-void vTaskSuspendAll( void )
-{
- /* A critical section is not required as the variable is of type
- portBASE_TYPE. */
- ++uxSchedulerSuspended;
-}
-/*----------------------------------------------------------*/
-
-signed portBASE_TYPE xTaskResumeAll( void )
-{
-register tskTCB *pxTCB;
-signed portBASE_TYPE xAlreadyYielded = pdFALSE;
-
- /* If uxSchedulerSuspended is zero then this function does not match a
- previous call to vTaskSuspendAll(). */
- configASSERT( uxSchedulerSuspended );
-
- /* It is possible that an ISR caused a task to be removed from an event
- list while the scheduler was suspended. If this was the case then the
- removed task will have been added to the xPendingReadyList. Once the
- scheduler has been resumed it is safe to move all the pending ready
- tasks from this list into their appropriate ready list. */
- taskENTER_CRITICAL();
- {
- --uxSchedulerSuspended;
-
- if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
- {
- if( uxCurrentNumberOfTasks > ( unsigned portBASE_TYPE ) 0 )
- {
- portBASE_TYPE xYieldRequired = pdFALSE;
-
- /* Move any readied tasks from the pending list into the
- appropriate ready list. */
- while( listLIST_IS_EMPTY( ( xList * ) &xPendingReadyList ) == pdFALSE )
- {
- pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( ( ( xList * ) &xPendingReadyList ) );
- vListRemove( &( pxTCB->xEventListItem ) );
- vListRemove( &( pxTCB->xGenericListItem ) );
- prvAddTaskToReadyQueue( pxTCB );
-
- /* If we have moved a task that has a priority higher than
- the current task then we should yield. */
- if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
- {
- xYieldRequired = pdTRUE;
- }
- }
-
- /* If any ticks occurred while the scheduler was suspended then
- they should be processed now. This ensures the tick count does not
- slip, and that any delayed tasks are resumed at the correct time. */
- if( uxMissedTicks > ( unsigned portBASE_TYPE ) 0 )
- {
- while( uxMissedTicks > ( unsigned portBASE_TYPE ) 0 )
- {
- vTaskIncrementTick();
- --uxMissedTicks;
- }
-
- /* As we have processed some ticks it is appropriate to yield
- to ensure the highest priority task that is ready to run is
- the task actually running. */
- #if configUSE_PREEMPTION == 1
- {
- xYieldRequired = pdTRUE;
- }
- #endif
- }
-
- if( ( xYieldRequired == pdTRUE ) || ( xMissedYield == pdTRUE ) )
- {
- xAlreadyYielded = pdTRUE;
- xMissedYield = pdFALSE;
- portYIELD_WITHIN_API();
- }
- }
- }
- }
- taskEXIT_CRITICAL();
-
- return xAlreadyYielded;
-}
-
-
-
-
-
-
-/*-----------------------------------------------------------
- * PUBLIC TASK UTILITIES documented in task.h
- *----------------------------------------------------------*/
-
-
-
-portTickType xTaskGetTickCount( void )
-{
-portTickType xTicks;
-
- /* Critical section required if running on a 16 bit processor. */
- taskENTER_CRITICAL();
- {
- xTicks = xTickCount;
- }
- taskEXIT_CRITICAL();
-
- return xTicks;
-}
-/*-----------------------------------------------------------*/
-
-portTickType xTaskGetTickCountFromISR( void )
-{
-portTickType xReturn;
-unsigned portBASE_TYPE uxSavedInterruptStatus;
-
- uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
- xReturn = xTickCount;
- portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
-
- return xReturn;
-}
-/*-----------------------------------------------------------*/
-
-unsigned portBASE_TYPE uxTaskGetNumberOfTasks( void )
-{
- /* A critical section is not required because the variables are of type
- portBASE_TYPE. */
- return uxCurrentNumberOfTasks;
-}
-/*-----------------------------------------------------------*/
-
-#if ( configUSE_TRACE_FACILITY == 1 )
-
- void vTaskList( signed char *pcWriteBuffer )
- {
- unsigned portBASE_TYPE uxQueue;
-
- /* This is a VERY costly function that should be used for debug only.
- It leaves interrupts disabled for a LONG time. */
-
- vTaskSuspendAll();
- {
- /* Run through all the lists that could potentially contain a TCB and
- report the task name, state and stack high water mark. */
-
- *pcWriteBuffer = ( signed char ) 0x00;
- strcat( ( char * ) pcWriteBuffer, ( const char * ) "\r\n" );
-
- uxQueue = uxTopUsedPriority + ( unsigned portBASE_TYPE ) 1U;
-
- do
- {
- uxQueue--;
-
- if( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxQueue ] ) ) == pdFALSE )
- {
- prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &( pxReadyTasksLists[ uxQueue ] ), tskREADY_CHAR );
- }
- }while( uxQueue > ( unsigned short ) tskIDLE_PRIORITY );
-
- if( listLIST_IS_EMPTY( pxDelayedTaskList ) == pdFALSE )
- {
- prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) pxDelayedTaskList, tskBLOCKED_CHAR );
- }
-
- if( listLIST_IS_EMPTY( pxOverflowDelayedTaskList ) == pdFALSE )
- {
- prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) pxOverflowDelayedTaskList, tskBLOCKED_CHAR );
- }
-
- #if( INCLUDE_vTaskDelete == 1 )
- {
- if( listLIST_IS_EMPTY( &xTasksWaitingTermination ) == pdFALSE )
- {
- prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &xTasksWaitingTermination, tskDELETED_CHAR );
- }
- }
- #endif
-
- #if ( INCLUDE_vTaskSuspend == 1 )
- {
- if( listLIST_IS_EMPTY( &xSuspendedTaskList ) == pdFALSE )
- {
- prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &xSuspendedTaskList, tskSUSPENDED_CHAR );
- }
- }
- #endif
- }
- xTaskResumeAll();
- }
-
-#endif
-/*----------------------------------------------------------*/
-
-#if ( configGENERATE_RUN_TIME_STATS == 1 )
-
- void vTaskGetRunTimeStats( signed char *pcWriteBuffer )
- {
- unsigned portBASE_TYPE uxQueue;
- unsigned long ulTotalRunTime;
-
- /* This is a VERY costly function that should be used for debug only.
- It leaves interrupts disabled for a LONG time. */
-
- vTaskSuspendAll();
- {
- #ifdef portALT_GET_RUN_TIME_COUNTER_VALUE
- portALT_GET_RUN_TIME_COUNTER_VALUE( ulTotalRunTime );
- #else
- ulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE();
- #endif
-
- /* Divide ulTotalRunTime by 100 to make the percentage caluclations
- simpler in the prvGenerateRunTimeStatsForTasksInList() function. */
- ulTotalRunTime /= 100UL;
-
- /* Run through all the lists that could potentially contain a TCB,
- generating a table of run timer percentages in the provided
- buffer. */
-
- *pcWriteBuffer = ( signed char ) 0x00;
- strcat( ( char * ) pcWriteBuffer, ( const char * ) "\r\n" );
-
- uxQueue = uxTopUsedPriority + ( unsigned portBASE_TYPE ) 1U;
-
- do
- {
- uxQueue--;
-
- if( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxQueue ] ) ) == pdFALSE )
- {
- prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) &( pxReadyTasksLists[ uxQueue ] ), ulTotalRunTime );
- }
- }while( uxQueue > ( unsigned short ) tskIDLE_PRIORITY );
-
- if( listLIST_IS_EMPTY( pxDelayedTaskList ) == pdFALSE )
- {
- prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) pxDelayedTaskList, ulTotalRunTime );
- }
-
- if( listLIST_IS_EMPTY( pxOverflowDelayedTaskList ) == pdFALSE )
- {
- prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) pxOverflowDelayedTaskList, ulTotalRunTime );
- }
-
- #if ( INCLUDE_vTaskDelete == 1 )
- {
- if( listLIST_IS_EMPTY( &xTasksWaitingTermination ) == pdFALSE )
- {
- prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) &xTasksWaitingTermination, ulTotalRunTime );
- }
- }
- #endif
-
- #if ( INCLUDE_vTaskSuspend == 1 )
- {
- if( listLIST_IS_EMPTY( &xSuspendedTaskList ) == pdFALSE )
- {
- prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) &xSuspendedTaskList, ulTotalRunTime );
- }
- }
- #endif
- }
- xTaskResumeAll();
- }
-
-#endif
-/*----------------------------------------------------------*/
-
-#if ( configUSE_TRACE_FACILITY == 1 )
-
- void vTaskStartTrace( signed char * pcBuffer, unsigned long ulBufferSize )
- {
- configASSERT( pcBuffer );
- configASSERT( ulBufferSize );
-
- taskENTER_CRITICAL();
- {
- pcTraceBuffer = ( signed char * )pcBuffer;
- pcTraceBufferStart = pcBuffer;
- pcTraceBufferEnd = pcBuffer + ( ulBufferSize - tskSIZE_OF_EACH_TRACE_LINE );
- xTracing = pdTRUE;
- }
- taskEXIT_CRITICAL();
- }
-
-#endif
-/*----------------------------------------------------------*/
-
-#if ( configUSE_TRACE_FACILITY == 1 )
-
- unsigned long ulTaskEndTrace( void )
- {
- unsigned long ulBufferLength;
-
- taskENTER_CRITICAL();
- xTracing = pdFALSE;
- taskEXIT_CRITICAL();
-
- ulBufferLength = ( unsigned long ) ( pcTraceBuffer - pcTraceBufferStart );
-
- return ulBufferLength;
- }
-
-#endif
-
-
-
-/*-----------------------------------------------------------
- * SCHEDULER INTERNALS AVAILABLE FOR PORTING PURPOSES
- * documented in task.h
- *----------------------------------------------------------*/
-
-
-void vTaskIncrementTick( void )
-{
-tskTCB * pxTCB;
-
- /* Called by the portable layer each time a tick interrupt occurs.
- Increments the tick then checks to see if the new tick value will cause any
- tasks to be unblocked. */
- if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
- {
- ++xTickCount;
- if( xTickCount == ( portTickType ) 0 )
- {
- xList *pxTemp;
-
- /* Tick count has overflowed so we need to swap the delay lists.
- If there are any items in pxDelayedTaskList here then there is
- an error! */
- configASSERT( ( listLIST_IS_EMPTY( pxDelayedTaskList ) ) );
-
- pxTemp = pxDelayedTaskList;
- pxDelayedTaskList = pxOverflowDelayedTaskList;
- pxOverflowDelayedTaskList = pxTemp;
- xNumOfOverflows++;
-
- if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE )
- {
- /* The new current delayed list is empty. Set
- xNextTaskUnblockTime to the maximum possible value so it is
- extremely unlikely that the
- if( xTickCount >= xNextTaskUnblockTime ) test will pass until
- there is an item in the delayed list. */
- xNextTaskUnblockTime = portMAX_DELAY;
- }
- else
- {
- /* The new current delayed list is not empty, get the value of
- the item at the head of the delayed list. This is the time at
- which the task at the head of the delayed list should be removed
- from the Blocked state. */
- pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList );
- xNextTaskUnblockTime = listGET_LIST_ITEM_VALUE( &( pxTCB->xGenericListItem ) );
- }
- }
-
- /* See if this tick has made a timeout expire. */
- prvCheckDelayedTasks();
- }
- else
- {
- ++uxMissedTicks;
-
- /* The tick hook gets called at regular intervals, even if the
- scheduler is locked. */
- #if ( configUSE_TICK_HOOK == 1 )
- {
- vApplicationTickHook();
- }
- #endif
- }
-
- #if ( configUSE_TICK_HOOK == 1 )
- {
- /* Guard against the tick hook being called when the missed tick
- count is being unwound (when the scheduler is being unlocked. */
- if( uxMissedTicks == ( unsigned portBASE_TYPE ) 0U )
- {
- vApplicationTickHook();
- }
- }
- #endif
-
- traceTASK_INCREMENT_TICK( xTickCount );
-}
-/*-----------------------------------------------------------*/
-
-#if ( ( INCLUDE_vTaskCleanUpResources == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )
-
- void vTaskCleanUpResources( void )
- {
- unsigned short usQueue;
- volatile tskTCB *pxTCB;
-
- usQueue = ( unsigned short ) uxTopUsedPriority + ( unsigned short ) 1;
-
- /* Remove any TCB's from the ready queues. */
- do
- {
- usQueue--;
-
- while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ usQueue ] ) ) == pdFALSE )
- {
- listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &( pxReadyTasksLists[ usQueue ] ) );
- vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
-
- prvDeleteTCB( ( tskTCB * ) pxTCB );
- }
- }while( usQueue > ( unsigned short ) tskIDLE_PRIORITY );
-
- /* Remove any TCB's from the delayed queue. */
- while( listLIST_IS_EMPTY( &xDelayedTaskList1 ) == pdFALSE )
- {
- listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &xDelayedTaskList1 );
- vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
-
- prvDeleteTCB( ( tskTCB * ) pxTCB );
- }
-
- /* Remove any TCB's from the overflow delayed queue. */
- while( listLIST_IS_EMPTY( &xDelayedTaskList2 ) == pdFALSE )
- {
- listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &xDelayedTaskList2 );
- vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
-
- prvDeleteTCB( ( tskTCB * ) pxTCB );
- }
-
- while( listLIST_IS_EMPTY( &xSuspendedTaskList ) == pdFALSE )
- {
- listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &xSuspendedTaskList );
- vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
-
- prvDeleteTCB( ( tskTCB * ) pxTCB );
- }
- }
-
-#endif
-/*-----------------------------------------------------------*/
-
-#if ( configUSE_APPLICATION_TASK_TAG == 1 )
-
- void vTaskSetApplicationTaskTag( xTaskHandle xTask, pdTASK_HOOK_CODE pxHookFunction )
- {
- tskTCB *xTCB;
-
- /* If xTask is NULL then we are setting our own task hook. */
- if( xTask == NULL )
- {
- xTCB = ( tskTCB * ) pxCurrentTCB;
- }
- else
- {
- xTCB = ( tskTCB * ) xTask;
- }
-
- /* Save the hook function in the TCB. A critical section is required as
- the value can be accessed from an interrupt. */
- taskENTER_CRITICAL();
- xTCB->pxTaskTag = pxHookFunction;
- taskEXIT_CRITICAL();
- }
-
-#endif
-/*-----------------------------------------------------------*/
-
-#if ( configUSE_APPLICATION_TASK_TAG == 1 )
-
- pdTASK_HOOK_CODE xTaskGetApplicationTaskTag( xTaskHandle xTask )
- {
- tskTCB *xTCB;
- pdTASK_HOOK_CODE xReturn;
-
- /* If xTask is NULL then we are setting our own task hook. */
- if( xTask == NULL )
- {
- xTCB = ( tskTCB * ) pxCurrentTCB;
- }
- else
- {
- xTCB = ( tskTCB * ) xTask;
- }
-
- /* Save the hook function in the TCB. A critical section is required as
- the value can be accessed from an interrupt. */
- taskENTER_CRITICAL();
- xReturn = xTCB->pxTaskTag;
- taskEXIT_CRITICAL();
-
- return xReturn;
- }
-
-#endif
-/*-----------------------------------------------------------*/
-
-#if ( configUSE_APPLICATION_TASK_TAG == 1 )
-
- portBASE_TYPE xTaskCallApplicationTaskHook( xTaskHandle xTask, void *pvParameter )
- {
- tskTCB *xTCB;
- portBASE_TYPE xReturn;
-
- /* If xTask is NULL then we are calling our own task hook. */
- if( xTask == NULL )
- {
- xTCB = ( tskTCB * ) pxCurrentTCB;
- }
- else
- {
- xTCB = ( tskTCB * ) xTask;
- }
-
- if( xTCB->pxTaskTag != NULL )
- {
- xReturn = xTCB->pxTaskTag( pvParameter );
- }
- else
- {
- xReturn = pdFAIL;
- }
-
- return xReturn;
- }
-
-#endif
-/*-----------------------------------------------------------*/
-
-void vTaskSwitchContext( void )
-{
- if( uxSchedulerSuspended != ( unsigned portBASE_TYPE ) pdFALSE )
- {
- /* The scheduler is currently suspended - do not allow a context
- switch. */
- xMissedYield = pdTRUE;
- }
- else
- {
- traceTASK_SWITCHED_OUT();
-
- #if ( configGENERATE_RUN_TIME_STATS == 1 )
- {
- unsigned long ulTempCounter;
-
- #ifdef portALT_GET_RUN_TIME_COUNTER_VALUE
- portALT_GET_RUN_TIME_COUNTER_VALUE( ulTempCounter );
- #else
- ulTempCounter = portGET_RUN_TIME_COUNTER_VALUE();
- #endif
-
- /* Add the amount of time the task has been running to the accumulated
- time so far. The time the task started running was stored in
- ulTaskSwitchedInTime. Note that there is no overflow protection here
- so count values are only valid until the timer overflows. Generally
- this will be about 1 hour assuming a 1uS timer increment. */
- pxCurrentTCB->ulRunTimeCounter += ( ulTempCounter - ulTaskSwitchedInTime );
- ulTaskSwitchedInTime = ulTempCounter;
- }
- #endif
-
- taskFIRST_CHECK_FOR_STACK_OVERFLOW();
- taskSECOND_CHECK_FOR_STACK_OVERFLOW();
-
- /* Find the highest priority queue that contains ready tasks. */
- while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopReadyPriority ] ) ) )
- {
- configASSERT( uxTopReadyPriority );
- --uxTopReadyPriority;
- }
-
- /* listGET_OWNER_OF_NEXT_ENTRY walks through the list, so the tasks of the
- same priority get an equal share of the processor time. */
- listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopReadyPriority ] ) );
-
- traceTASK_SWITCHED_IN();
- vWriteTraceToBuffer();
- }
-}
-/*-----------------------------------------------------------*/
-
-void vTaskPlaceOnEventList( const xList * const pxEventList, portTickType xTicksToWait )
-{
-portTickType xTimeToWake;
-
- configASSERT( pxEventList );
-
- /* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE
- SCHEDULER SUSPENDED. */
-
- /* Place the event list item of the TCB in the appropriate event list.
- This is placed in the list in priority order so the highest priority task
- is the first to be woken by the event. */
- vListInsert( ( xList * ) pxEventList, ( xListItem * ) &( pxCurrentTCB->xEventListItem ) );
-
- /* We must remove ourselves from the ready list before adding ourselves
- to the blocked list as the same list item is used for both lists. We have
- exclusive access to the ready lists as the scheduler is locked. */
- vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
-
-
- #if ( INCLUDE_vTaskSuspend == 1 )
- {
- if( xTicksToWait == portMAX_DELAY )
- {
- /* Add ourselves to the suspended task list instead of a delayed task
- list to ensure we are not woken by a timing event. We will block
- indefinitely. */
- vListInsertEnd( ( xList * ) &xSuspendedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
- }
- else
- {
- /* Calculate the time at which the task should be woken if the event does
- not occur. This may overflow but this doesn't matter. */
- xTimeToWake = xTickCount + xTicksToWait;
- prvAddCurrentTaskToDelayedList( xTimeToWake );
- }
- }
- #else
- {
- /* Calculate the time at which the task should be woken if the event does
- not occur. This may overflow but this doesn't matter. */
- xTimeToWake = xTickCount + xTicksToWait;
- prvAddCurrentTaskToDelayedList( xTimeToWake );
- }
- #endif
-}
-/*-----------------------------------------------------------*/
-
-#if configUSE_TIMERS == 1
-
- void vTaskPlaceOnEventListRestricted( const xList * const pxEventList, portTickType xTicksToWait )
- {
- portTickType xTimeToWake;
-
- configASSERT( pxEventList );
-
- /* This function should not be called by application code hence the
- 'Restricted' in its name. It is not part of the public API. It is
- designed for use by kernel code, and has special calling requirements -
- it should be called from a critical section. */
-
-
- /* Place the event list item of the TCB in the appropriate event list.
- In this case it is assume that this is the only task that is going to
- be waiting on this event list, so the faster vListInsertEnd() function
- can be used in place of vListInsert. */
- vListInsertEnd( ( xList * ) pxEventList, ( xListItem * ) &( pxCurrentTCB->xEventListItem ) );
-
- /* We must remove this task from the ready list before adding it to the
- blocked list as the same list item is used for both lists. This
- function is called form a critical section. */
- vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
-
- /* Calculate the time at which the task should be woken if the event does
- not occur. This may overflow but this doesn't matter. */
- xTimeToWake = xTickCount + xTicksToWait;
- prvAddCurrentTaskToDelayedList( xTimeToWake );
- }
-
-#endif /* configUSE_TIMERS */
-/*-----------------------------------------------------------*/
-
-signed portBASE_TYPE xTaskRemoveFromEventList( const xList * const pxEventList )
-{
-tskTCB *pxUnblockedTCB;
-portBASE_TYPE xReturn;
-
- /* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE
- SCHEDULER SUSPENDED. It can also be called from within an ISR. */
-
- /* The event list is sorted in priority order, so we can remove the
- first in the list, remove the TCB from the delayed list, and add
- it to the ready list.
-
- If an event is for a queue that is locked then this function will never
- get called - the lock count on the queue will get modified instead. This
- means we can always expect exclusive access to the event list here.
-
- This function assumes that a check has already been made to ensure that
- pxEventList is not empty. */
- pxUnblockedTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList );
- configASSERT( pxUnblockedTCB );
- vListRemove( &( pxUnblockedTCB->xEventListItem ) );
-
- if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
- {
- vListRemove( &( pxUnblockedTCB->xGenericListItem ) );
- prvAddTaskToReadyQueue( pxUnblockedTCB );
- }
- else
- {
- /* We cannot access the delayed or ready lists, so will hold this
- task pending until the scheduler is resumed. */
- vListInsertEnd( ( xList * ) &( xPendingReadyList ), &( pxUnblockedTCB->xEventListItem ) );
- }
-
- if( pxUnblockedTCB->uxPriority >= pxCurrentTCB->uxPriority )
- {
- /* Return true if the task removed from the event list has
- a higher priority than the calling task. This allows
- the calling task to know if it should force a context
- switch now. */
- xReturn = pdTRUE;
- }
- else
- {
- xReturn = pdFALSE;
- }
-
- return xReturn;
-}
-/*-----------------------------------------------------------*/
-
-void vTaskSetTimeOutState( xTimeOutType * const pxTimeOut )
-{
- configASSERT( pxTimeOut );
- pxTimeOut->xOverflowCount = xNumOfOverflows;
- pxTimeOut->xTimeOnEntering = xTickCount;
-}
-/*-----------------------------------------------------------*/
-
-portBASE_TYPE xTaskCheckForTimeOut( xTimeOutType * const pxTimeOut, portTickType * const pxTicksToWait )
-{
-portBASE_TYPE xReturn;
-
- configASSERT( pxTimeOut );
- configASSERT( pxTicksToWait );
-
- taskENTER_CRITICAL();
- {
- #if ( INCLUDE_vTaskSuspend == 1 )
- /* If INCLUDE_vTaskSuspend is set to 1 and the block time specified is
- the maximum block time then the task should block indefinitely, and
- therefore never time out. */
- if( *pxTicksToWait == portMAX_DELAY )
- {
- xReturn = pdFALSE;
- }
- else /* We are not blocking indefinitely, perform the checks below. */
- #endif
-
- if( ( xNumOfOverflows != pxTimeOut->xOverflowCount ) && ( ( portTickType ) xTickCount >= ( portTickType ) pxTimeOut->xTimeOnEntering ) )
- {
- /* The tick count is greater than the time at which vTaskSetTimeout()
- was called, but has also overflowed since vTaskSetTimeOut() was called.
- It must have wrapped all the way around and gone past us again. This
- passed since vTaskSetTimeout() was called. */
- xReturn = pdTRUE;
- }
- else if( ( ( portTickType ) ( ( portTickType ) xTickCount - ( portTickType ) pxTimeOut->xTimeOnEntering ) ) < ( portTickType ) *pxTicksToWait )
- {
- /* Not a genuine timeout. Adjust parameters for time remaining. */
- *pxTicksToWait -= ( ( portTickType ) xTickCount - ( portTickType ) pxTimeOut->xTimeOnEntering );
- vTaskSetTimeOutState( pxTimeOut );
- xReturn = pdFALSE;
- }
- else
- {
- xReturn = pdTRUE;
- }
- }
- taskEXIT_CRITICAL();
-
- return xReturn;
-}
-/*-----------------------------------------------------------*/
-
-void vTaskMissedYield( void )
-{
- xMissedYield = pdTRUE;
-}
-
-/*
- * -----------------------------------------------------------
- * The Idle task.
- * ----------------------------------------------------------
- *
- * The portTASK_FUNCTION() macro is used to allow port/compiler specific
- * language extensions. The equivalent prototype for this function is:
- *
- * void prvIdleTask( void *pvParameters );
- *
- */
-static portTASK_FUNCTION( prvIdleTask, pvParameters )
-{
- /* Stop warnings. */
- ( void ) pvParameters;
-
- for( ;; )
- {
- /* See if any tasks have been deleted. */
- prvCheckTasksWaitingTermination();
-
- #if ( configUSE_PREEMPTION == 0 )
- {
- /* If we are not using preemption we keep forcing a task switch to
- see if any other task has become available. If we are using
- preemption we don't need to do this as any task becoming available
- will automatically get the processor anyway. */
- taskYIELD();
- }
- #endif
-
- #if ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) )
- {
- /* When using preemption tasks of equal priority will be
- timesliced. If a task that is sharing the idle priority is ready
- to run then the idle task should yield before the end of the
- timeslice.
-
- A critical region is not required here as we are just reading from
- the list, and an occasional incorrect value will not matter. If
- the ready list at the idle priority contains more than one task
- then a task other than the idle task is ready to execute. */
- if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > ( unsigned portBASE_TYPE ) 1 )
- {
- taskYIELD();
- }
- }
- #endif
-
- #if ( configUSE_IDLE_HOOK == 1 )
- {
- extern void vApplicationIdleHook( void );
-
- /* Call the user defined function from within the idle task. This
- allows the application designer to add background functionality
- without the overhead of a separate task.
- NOTE: vApplicationIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES,
- CALL A FUNCTION THAT MIGHT BLOCK. */
- vApplicationIdleHook();
- }
- #endif
- }
-} /*lint !e715 pvParameters is not accessed but all task functions require the same prototype. */
-
-
-
-
-
-
-
-/*-----------------------------------------------------------
- * File private functions documented at the top of the file.
- *----------------------------------------------------------*/
-
-
-
-static void prvInitialiseTCBVariables( tskTCB *pxTCB, const signed char * const pcName, unsigned portBASE_TYPE uxPriority, const xMemoryRegion * const xRegions, unsigned short usStackDepth )
-{
- /* Store the function name in the TCB. */
- #if configMAX_TASK_NAME_LEN > 1
- {
- /* Don't bring strncpy into the build unnecessarily. */
- strncpy( ( char * ) pxTCB->pcTaskName, ( const char * ) pcName, ( unsigned short ) configMAX_TASK_NAME_LEN );
- }
- #endif
- pxTCB->pcTaskName[ ( unsigned short ) configMAX_TASK_NAME_LEN - ( unsigned short ) 1 ] = ( signed char ) '\0';
-
- /* This is used as an array index so must ensure it's not too large. First
- remove the privilege bit if one is present. */
- if( uxPriority >= configMAX_PRIORITIES )
- {
- uxPriority = configMAX_PRIORITIES - ( unsigned portBASE_TYPE ) 1U;
- }
-
- pxTCB->uxPriority = uxPriority;
- #if ( configUSE_MUTEXES == 1 )
- {
- pxTCB->uxBasePriority = uxPriority;
- }
- #endif
-
- vListInitialiseItem( &( pxTCB->xGenericListItem ) );
- vListInitialiseItem( &( pxTCB->xEventListItem ) );
-
- /* Set the pxTCB as a link back from the xListItem. This is so we can get
- back to the containing TCB from a generic item in a list. */
- listSET_LIST_ITEM_OWNER( &( pxTCB->xGenericListItem ), pxTCB );
-
- /* Event lists are always in priority order. */
- listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) uxPriority );
- listSET_LIST_ITEM_OWNER( &( pxTCB->xEventListItem ), pxTCB );
-
- #if ( portCRITICAL_NESTING_IN_TCB == 1 )
- {
- pxTCB->uxCriticalNesting = ( unsigned portBASE_TYPE ) 0;
- }
- #endif
-
- #if ( configUSE_APPLICATION_TASK_TAG == 1 )
- {
- pxTCB->pxTaskTag = NULL;
- }
- #endif
-
- #if ( configGENERATE_RUN_TIME_STATS == 1 )
- {
- pxTCB->ulRunTimeCounter = 0UL;
- }
- #endif
-
- #if ( portUSING_MPU_WRAPPERS == 1 )
- {
- vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, pxTCB->pxStack, usStackDepth );
- }
- #else
- {
- ( void ) xRegions;
- ( void ) usStackDepth;
- }
- #endif
-}
-/*-----------------------------------------------------------*/
-
-#if ( portUSING_MPU_WRAPPERS == 1 )
-
- void vTaskAllocateMPURegions( xTaskHandle xTaskToModify, const xMemoryRegion * const xRegions )
- {
- tskTCB *pxTCB;
-
- if( xTaskToModify == pxCurrentTCB )
- {
- xTaskToModify = NULL;
- }
-
- /* If null is passed in here then we are deleting ourselves. */
- pxTCB = prvGetTCBFromHandle( xTaskToModify );
-
- vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, NULL, 0 );
- }
- /*-----------------------------------------------------------*/
-#endif
-
-static void prvInitialiseTaskLists( void )
-{
-unsigned portBASE_TYPE uxPriority;
-
- for( uxPriority = ( unsigned portBASE_TYPE ) 0U; uxPriority < configMAX_PRIORITIES; uxPriority++ )
- {
- vListInitialise( ( xList * ) &( pxReadyTasksLists[ uxPriority ] ) );
- }
-
- vListInitialise( ( xList * ) &xDelayedTaskList1 );
- vListInitialise( ( xList * ) &xDelayedTaskList2 );
- vListInitialise( ( xList * ) &xPendingReadyList );
-
- #if ( INCLUDE_vTaskDelete == 1 )
- {
- vListInitialise( ( xList * ) &xTasksWaitingTermination );
- }
- #endif
-
- #if ( INCLUDE_vTaskSuspend == 1 )
- {
- vListInitialise( ( xList * ) &xSuspendedTaskList );
- }
- #endif
-
- /* Start with pxDelayedTaskList using list1 and the pxOverflowDelayedTaskList
- using list2. */
- pxDelayedTaskList = &xDelayedTaskList1;
- pxOverflowDelayedTaskList = &xDelayedTaskList2;
-}
-/*-----------------------------------------------------------*/
-
-static void prvCheckTasksWaitingTermination( void )
-{
- #if ( INCLUDE_vTaskDelete == 1 )
- {
- portBASE_TYPE xListIsEmpty;
-
- /* ucTasksDeleted is used to prevent vTaskSuspendAll() being called
- too often in the idle task. */
- if( uxTasksDeleted > ( unsigned portBASE_TYPE ) 0 )
- {
- vTaskSuspendAll();
- xListIsEmpty = listLIST_IS_EMPTY( &xTasksWaitingTermination );
- xTaskResumeAll();
-
- if( xListIsEmpty == pdFALSE )
- {
- tskTCB *pxTCB;
-
- taskENTER_CRITICAL();
- {
- pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( ( ( xList * ) &xTasksWaitingTermination ) );
- vListRemove( &( pxTCB->xGenericListItem ) );
- --uxCurrentNumberOfTasks;
- --uxTasksDeleted;
- }
- taskEXIT_CRITICAL();
-
- prvDeleteTCB( pxTCB );
- }
- }
- }
- #endif
-}
-/*-----------------------------------------------------------*/
-
-static void prvAddCurrentTaskToDelayedList( portTickType xTimeToWake )
-{
- /* The list item will be inserted in wake time order. */
- listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );
-
- if( xTimeToWake < xTickCount )
- {
- /* Wake time has overflowed. Place this item in the overflow list. */
- vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
- }
- else
- {
- /* The wake time has not overflowed, so we can use the current block list. */
- vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
-
- /* If the task entering the blocked state was placed at the head of the
- list of blocked tasks then xNextTaskUnblockTime needs to be updated
- too. */
- if( xTimeToWake < xNextTaskUnblockTime )
- {
- xNextTaskUnblockTime = xTimeToWake;
- }
- }
-}
-/*-----------------------------------------------------------*/
-
-static tskTCB *prvAllocateTCBAndStack( unsigned short usStackDepth, portSTACK_TYPE *puxStackBuffer )
-{
-tskTCB *pxNewTCB;
-
- /* Allocate space for the TCB. Where the memory comes from depends on
- the implementation of the port malloc function. */
- pxNewTCB = ( tskTCB * ) pvPortMalloc( sizeof( tskTCB ) );
-
- if( pxNewTCB != NULL )
- {
- /* Allocate space for the stack used by the task being created.
- The base of the stack memory stored in the TCB so the task can
- be deleted later if required. */
- pxNewTCB->pxStack = ( portSTACK_TYPE * ) pvPortMallocAligned( ( ( ( size_t )usStackDepth ) * sizeof( portSTACK_TYPE ) ), puxStackBuffer );
-
- if( pxNewTCB->pxStack == NULL )
- {
- /* Could not allocate the stack. Delete the allocated TCB. */
- vPortFree( pxNewTCB );
- pxNewTCB = NULL;
- }
- else
- {
- /* Just to help debugging. */
- memset( pxNewTCB->pxStack, tskSTACK_FILL_BYTE, usStackDepth * sizeof( portSTACK_TYPE ) );
- }
- }
-
- return pxNewTCB;
-}
-/*-----------------------------------------------------------*/
-
-#if ( configUSE_TRACE_FACILITY == 1 )
-
- static void prvListTaskWithinSingleList( const signed char *pcWriteBuffer, xList *pxList, signed char cStatus )
- {
- volatile tskTCB *pxNextTCB, *pxFirstTCB;
- unsigned short usStackRemaining;
-
- /* Write the details of all the TCB's in pxList into the buffer. */
- listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList );
- do
- {
- listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList );
- #if ( portSTACK_GROWTH > 0 )
- {
- usStackRemaining = usTaskCheckFreeStackSpace( ( unsigned char * ) pxNextTCB->pxEndOfStack );
- }
- #else
- {
- usStackRemaining = usTaskCheckFreeStackSpace( ( unsigned char * ) pxNextTCB->pxStack );
- }
- #endif
-
- sprintf( pcStatusString, ( char * ) "%s\t\t%c\t%u\t%u\t%u\r\n", pxNextTCB->pcTaskName, cStatus, ( unsigned int ) pxNextTCB->uxPriority, usStackRemaining, ( unsigned int ) pxNextTCB->uxTCBNumber );
- strcat( ( char * ) pcWriteBuffer, ( char * ) pcStatusString );
-
- } while( pxNextTCB != pxFirstTCB );
- }
-
-#endif
-/*-----------------------------------------------------------*/
-
-#if ( configGENERATE_RUN_TIME_STATS == 1 )
-
- static void prvGenerateRunTimeStatsForTasksInList( const signed char *pcWriteBuffer, xList *pxList, unsigned long ulTotalRunTime )
- {
- volatile tskTCB *pxNextTCB, *pxFirstTCB;
- unsigned long ulStatsAsPercentage;
-
- /* Write the run time stats of all the TCB's in pxList into the buffer. */
- listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList );
- do
- {
- /* Get next TCB in from the list. */
- listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList );
-
- /* Divide by zero check. */
- if( ulTotalRunTime > 0UL )
- {
- /* Has the task run at all? */
- if( pxNextTCB->ulRunTimeCounter == 0 )
- {
- /* The task has used no CPU time at all. */
- sprintf( pcStatsString, ( char * ) "%s\t\t0\t\t0%%\r\n", pxNextTCB->pcTaskName );
- }
- else
- {
- /* What percentage of the total run time has the task used?
- This will always be rounded down to the nearest integer.
- ulTotalRunTime has already been divided by 100. */
- ulStatsAsPercentage = pxNextTCB->ulRunTimeCounter / ulTotalRunTime;
-
- if( ulStatsAsPercentage > 0UL )
- {
- #ifdef portLU_PRINTF_SPECIFIER_REQUIRED
- {
- sprintf( pcStatsString, ( char * ) "%s\t\t%lu\t\t%lu%%\r\n", pxNextTCB->pcTaskName, pxNextTCB->ulRunTimeCounter, ulStatsAsPercentage );
- }
- #else
- {
- /* sizeof( int ) == sizeof( long ) so a smaller
- printf() library can be used. */
- sprintf( pcStatsString, ( char * ) "%s\t\t%u\t\t%u%%\r\n", pxNextTCB->pcTaskName, ( unsigned int ) pxNextTCB->ulRunTimeCounter, ( unsigned int ) ulStatsAsPercentage );
- }
- #endif
- }
- else
- {
- /* If the percentage is zero here then the task has
- consumed less than 1% of the total run time. */
- #ifdef portLU_PRINTF_SPECIFIER_REQUIRED
- {
- sprintf( pcStatsString, ( char * ) "%s\t\t%lu\t\t<1%%\r\n", pxNextTCB->pcTaskName, pxNextTCB->ulRunTimeCounter );
- }
- #else
- {
- /* sizeof( int ) == sizeof( long ) so a smaller
- printf() library can be used. */
- sprintf( pcStatsString, ( char * ) "%s\t\t%u\t\t<1%%\r\n", pxNextTCB->pcTaskName, ( unsigned int ) pxNextTCB->ulRunTimeCounter );
- }
- #endif
- }
- }
-
- strcat( ( char * ) pcWriteBuffer, ( char * ) pcStatsString );
- }
-
- } while( pxNextTCB != pxFirstTCB );
- }
-
-#endif
-/*-----------------------------------------------------------*/
-
-#if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )
-
- static unsigned short usTaskCheckFreeStackSpace( const unsigned char * pucStackByte )
- {
- register unsigned short usCount = 0;
-
- while( *pucStackByte == tskSTACK_FILL_BYTE )
- {
- pucStackByte -= portSTACK_GROWTH;
- usCount++;
- }
-
- usCount /= sizeof( portSTACK_TYPE );
-
- return usCount;
- }
-
-#endif
-/*-----------------------------------------------------------*/
-
-#if ( INCLUDE_uxTaskGetStackHighWaterMark == 1 )
-
- unsigned portBASE_TYPE uxTaskGetStackHighWaterMark( xTaskHandle xTask )
- {
- tskTCB *pxTCB;
- unsigned char *pcEndOfStack;
- unsigned portBASE_TYPE uxReturn;
-
- pxTCB = prvGetTCBFromHandle( xTask );
-
- #if portSTACK_GROWTH < 0
- {
- pcEndOfStack = ( unsigned char * ) pxTCB->pxStack;
- }
- #else
- {
- pcEndOfStack = ( unsigned char * ) pxTCB->pxEndOfStack;
- }
- #endif
-
- uxReturn = ( unsigned portBASE_TYPE ) usTaskCheckFreeStackSpace( pcEndOfStack );
-
- return uxReturn;
- }
-
-#endif
-/*-----------------------------------------------------------*/
-
-#if ( ( INCLUDE_vTaskDelete == 1 ) || ( INCLUDE_vTaskCleanUpResources == 1 ) )
-
- static void prvDeleteTCB( tskTCB *pxTCB )
- {
- /* Free up the memory allocated by the scheduler for the task. It is up to
- the task to free any memory allocated at the application level. */
- vPortFreeAligned( pxTCB->pxStack );
- vPortFree( pxTCB );
- }
-
-#endif
-
-
-/*-----------------------------------------------------------*/
-
-#if ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) )
-
- xTaskHandle xTaskGetCurrentTaskHandle( void )
- {
- xTaskHandle xReturn;
-
- /* A critical section is not required as this is not called from
- an interrupt and the current TCB will always be the same for any
- individual execution thread. */
- xReturn = pxCurrentTCB;
-
- return xReturn;
- }
-
-#endif
-
-/*-----------------------------------------------------------*/
-
-#if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )
-
- portBASE_TYPE xTaskGetSchedulerState( void )
- {
- portBASE_TYPE xReturn;
-
- if( xSchedulerRunning == pdFALSE )
- {
- xReturn = taskSCHEDULER_NOT_STARTED;
- }
- else
- {
- if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
- {
- xReturn = taskSCHEDULER_RUNNING;
- }
- else
- {
- xReturn = taskSCHEDULER_SUSPENDED;
- }
- }
-
- return xReturn;
- }
-
-#endif
-/*-----------------------------------------------------------*/
-
-#if ( configUSE_MUTEXES == 1 )
-
- void vTaskPriorityInherit( xTaskHandle * const pxMutexHolder )
- {
- tskTCB * const pxTCB = ( tskTCB * ) pxMutexHolder;
-
- configASSERT( pxMutexHolder );
-
- if( pxTCB->uxPriority < pxCurrentTCB->uxPriority )
- {
- /* Adjust the mutex holder state to account for its new priority. */
- listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) pxCurrentTCB->uxPriority );
-
- /* If the task being modified is in the ready state it will need to
- be moved in to a new list. */
- if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xGenericListItem ) ) )
- {
- vListRemove( &( pxTCB->xGenericListItem ) );
-
- /* Inherit the priority before being moved into the new list. */
- pxTCB->uxPriority = pxCurrentTCB->uxPriority;
- prvAddTaskToReadyQueue( pxTCB );
- }
- else
- {
- /* Just inherit the priority. */
- pxTCB->uxPriority = pxCurrentTCB->uxPriority;
- }
- }
- }
-
-#endif
-/*-----------------------------------------------------------*/
-
-#if ( configUSE_MUTEXES == 1 )
-
- void vTaskPriorityDisinherit( xTaskHandle * const pxMutexHolder )
- {
- tskTCB * const pxTCB = ( tskTCB * ) pxMutexHolder;
-
- if( pxMutexHolder != NULL )
- {
- if( pxTCB->uxPriority != pxTCB->uxBasePriority )
- {
- /* We must be the running task to be able to give the mutex back.
- Remove ourselves from the ready list we currently appear in. */
- vListRemove( &( pxTCB->xGenericListItem ) );
-
- /* Disinherit the priority before adding ourselves into the new
- ready list. */
- pxTCB->uxPriority = pxTCB->uxBasePriority;
- listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) pxTCB->uxPriority );
- prvAddTaskToReadyQueue( pxTCB );
- }
- }
- }
-
-#endif
-/*-----------------------------------------------------------*/
-
-#if ( portCRITICAL_NESTING_IN_TCB == 1 )
-
- void vTaskEnterCritical( void )
- {
- portDISABLE_INTERRUPTS();
-
- if( xSchedulerRunning != pdFALSE )
- {
- ( pxCurrentTCB->uxCriticalNesting )++;
- }
- }
-
-#endif
-/*-----------------------------------------------------------*/
-
-#if ( portCRITICAL_NESTING_IN_TCB == 1 )
-
-void vTaskExitCritical( void )
-{
- if( xSchedulerRunning != pdFALSE )
- {
- if( pxCurrentTCB->uxCriticalNesting > 0 )
- {
- ( pxCurrentTCB->uxCriticalNesting )--;
-
- if( pxCurrentTCB->uxCriticalNesting == 0 )
- {
- portENABLE_INTERRUPTS();
- }
- }
- }
-}
-
-#endif
-/*-----------------------------------------------------------*/
-
-
-
-
+/*
+ FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.
+
+
+ FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:
+ Atollic AB - Atollic provides professional embedded systems development
+ tools for C/C++ development, code analysis and test automation.
+ See http://www.atollic.com
+
+
+ ***************************************************************************
+ * *
+ * FreeRTOS tutorial books are available in pdf and paperback. *
+ * Complete, revised, and edited pdf reference manuals are also *
+ * available. *
+ * *
+ * Purchasing FreeRTOS documentation will not only help you, by *
+ * ensuring you get running as quickly as possible and with an *
+ * in-depth knowledge of how to use FreeRTOS, it will also help *
+ * the FreeRTOS project to continue with its mission of providing *
+ * professional grade, cross platform, de facto standard solutions *
+ * for microcontrollers - completely free of charge! *
+ * *
+ * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
+ * *
+ * Thank you for using FreeRTOS, and thank you for your support! *
+ * *
+ ***************************************************************************
+
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
+ >>>NOTE<<< The modification to the GPL is included to allow you to
+ distribute a combined work that includes FreeRTOS without being obliged to
+ provide the source code for proprietary components outside of the FreeRTOS
+ kernel. FreeRTOS is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details. You should have received a copy of the GNU General Public
+ License and the FreeRTOS license exception along with FreeRTOS; if not it
+ can be viewed here: http://www.freertos.org/a00114.html and also obtained
+ by writing to Richard Barry, contact details for whom are available on the
+ FreeRTOS WEB site.
+
+ 1 tab == 4 spaces!
+
+ http://www.FreeRTOS.org - Documentation, latest information, license and
+ contact details.
+
+ http://www.SafeRTOS.com - A version that is certified for use in safety
+ critical systems.
+
+ http://www.OpenRTOS.com - Commercial support, development, porting,
+ licensing and training services.
+*/
+
+
+#include
+#include
+#include
+
+/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
+all the API functions to use the MPU wrappers. That should only be done when
+task.h is included from an application file. */
+#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
+
+#include "FreeRTOS.h"
+#include "task.h"
+#include "timers.h"
+#include "StackMacros.h"
+
+#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
+
+/*
+ * Macro to define the amount of stack available to the idle task.
+ */
+#define tskIDLE_STACK_SIZE configMINIMAL_STACK_SIZE
+
+/*
+ * Task control block. A task control block (TCB) is allocated to each task,
+ * and stores the context of the task.
+ */
+typedef struct tskTaskControlBlock
+{
+ volatile portSTACK_TYPE *pxTopOfStack; /*< Points to the location of the last item placed on the tasks stack. THIS MUST BE THE FIRST MEMBER OF THE STRUCT. */
+
+ #if ( portUSING_MPU_WRAPPERS == 1 )
+ xMPU_SETTINGS xMPUSettings; /*< The MPU settings are defined as part of the port layer. THIS MUST BE THE SECOND MEMBER OF THE STRUCT. */
+ #endif
+
+ xListItem xGenericListItem; /*< List item used to place the TCB in ready and blocked queues. */
+ xListItem xEventListItem; /*< List item used to place the TCB in event lists. */
+ unsigned portBASE_TYPE uxPriority; /*< The priority of the task where 0 is the lowest priority. */
+ portSTACK_TYPE *pxStack; /*< Points to the start of the stack. */
+ signed char pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created. Facilitates debugging only. */
+
+ #if ( portSTACK_GROWTH > 0 )
+ portSTACK_TYPE *pxEndOfStack; /*< Used for stack overflow checking on architectures where the stack grows up from low memory. */
+ #endif
+
+ #if ( portCRITICAL_NESTING_IN_TCB == 1 )
+ unsigned portBASE_TYPE uxCriticalNesting;
+ #endif
+
+ #if ( configUSE_TRACE_FACILITY == 1 )
+ unsigned portBASE_TYPE uxTCBNumber; /*< This is used for tracing the scheduler and making debugging easier only. */
+ #endif
+
+ #if ( configUSE_MUTEXES == 1 )
+ unsigned portBASE_TYPE uxBasePriority; /*< The priority last assigned to the task - used by the priority inheritance mechanism. */
+ #endif
+
+ #if ( configUSE_APPLICATION_TASK_TAG == 1 )
+ pdTASK_HOOK_CODE pxTaskTag;
+ #endif
+
+ #if ( configGENERATE_RUN_TIME_STATS == 1 )
+ unsigned long ulRunTimeCounter; /*< Used for calculating how much CPU time each task is utilising. */
+ #endif
+
+} tskTCB;
+
+
+/*
+ * Some kernel aware debuggers require data to be viewed to be global, rather
+ * than file scope.
+ */
+#ifdef portREMOVE_STATIC_QUALIFIER
+ #define static
+#endif
+
+/*lint -e956 */
+PRIVILEGED_DATA tskTCB * volatile pxCurrentTCB = NULL;
+
+/* Lists for ready and blocked tasks. --------------------*/
+
+PRIVILEGED_DATA static xList pxReadyTasksLists[ configMAX_PRIORITIES ]; /*< Prioritised ready tasks. */
+PRIVILEGED_DATA static xList xDelayedTaskList1; /*< Delayed tasks. */
+PRIVILEGED_DATA static xList xDelayedTaskList2; /*< Delayed tasks (two lists are used - one for delays that have overflowed the current tick count. */
+PRIVILEGED_DATA static xList * volatile pxDelayedTaskList ; /*< Points to the delayed task list currently being used. */
+PRIVILEGED_DATA static xList * volatile pxOverflowDelayedTaskList; /*< Points to the delayed task list currently being used to hold tasks that have overflowed the current tick count. */
+PRIVILEGED_DATA static xList xPendingReadyList; /*< Tasks that have been readied while the scheduler was suspended. They will be moved to the ready queue when the scheduler is resumed. */
+
+#if ( INCLUDE_vTaskDelete == 1 )
+
+ PRIVILEGED_DATA static volatile xList xTasksWaitingTermination; /*< Tasks that have been deleted - but the their memory not yet freed. */
+ PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxTasksDeleted = ( unsigned portBASE_TYPE ) 0;
+
+#endif
+
+#if ( INCLUDE_vTaskSuspend == 1 )
+
+ PRIVILEGED_DATA static xList xSuspendedTaskList; /*< Tasks that are currently suspended. */
+
+#endif
+
+/* File private variables. --------------------------------*/
+PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxCurrentNumberOfTasks = ( unsigned portBASE_TYPE ) 0;
+PRIVILEGED_DATA static volatile portTickType xTickCount = ( portTickType ) 0;
+PRIVILEGED_DATA static unsigned portBASE_TYPE uxTopUsedPriority = tskIDLE_PRIORITY;
+PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxTopReadyPriority = tskIDLE_PRIORITY;
+PRIVILEGED_DATA static volatile signed portBASE_TYPE xSchedulerRunning = pdFALSE;
+PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxSchedulerSuspended = ( unsigned portBASE_TYPE ) pdFALSE;
+PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxMissedTicks = ( unsigned portBASE_TYPE ) 0;
+PRIVILEGED_DATA static volatile portBASE_TYPE xMissedYield = ( portBASE_TYPE ) pdFALSE;
+PRIVILEGED_DATA static volatile portBASE_TYPE xNumOfOverflows = ( portBASE_TYPE ) 0;
+PRIVILEGED_DATA static unsigned portBASE_TYPE uxTaskNumber = ( unsigned portBASE_TYPE ) 0;
+PRIVILEGED_DATA static portTickType xNextTaskUnblockTime = ( portTickType ) portMAX_DELAY;
+
+#if ( configGENERATE_RUN_TIME_STATS == 1 )
+
+ PRIVILEGED_DATA static char pcStatsString[ 50 ] ;
+ PRIVILEGED_DATA static unsigned long ulTaskSwitchedInTime = 0UL; /*< Holds the value of a timer/counter the last time a task was switched in. */
+ static void prvGenerateRunTimeStatsForTasksInList( const signed char *pcWriteBuffer, xList *pxList, unsigned long ulTotalRunTime ) PRIVILEGED_FUNCTION;
+
+#endif
+
+/* Debugging and trace facilities private variables and macros. ------------*/
+
+/*
+ * The value used to fill the stack of a task when the task is created. This
+ * is used purely for checking the high water mark for tasks.
+ */
+#define tskSTACK_FILL_BYTE ( 0xa5U )
+
+/*
+ * Macros used by vListTask to indicate which state a task is in.
+ */
+#define tskBLOCKED_CHAR ( ( signed char ) 'B' )
+#define tskREADY_CHAR ( ( signed char ) 'R' )
+#define tskDELETED_CHAR ( ( signed char ) 'D' )
+#define tskSUSPENDED_CHAR ( ( signed char ) 'S' )
+
+/*
+ * Macros and private variables used by the trace facility.
+ */
+#if ( configUSE_TRACE_FACILITY == 1 )
+
+ #define tskSIZE_OF_EACH_TRACE_LINE ( ( unsigned long ) ( sizeof( unsigned long ) + sizeof( unsigned long ) ) )
+ PRIVILEGED_DATA static volatile signed char * volatile pcTraceBuffer;
+ PRIVILEGED_DATA static signed char *pcTraceBufferStart;
+ PRIVILEGED_DATA static signed char *pcTraceBufferEnd;
+ PRIVILEGED_DATA static signed portBASE_TYPE xTracing = pdFALSE;
+ static unsigned portBASE_TYPE uxPreviousTask = 255U;
+ PRIVILEGED_DATA static char pcStatusString[ 50 ];
+
+#endif
+
+/*-----------------------------------------------------------*/
+
+/*
+ * Macro that writes a trace of scheduler activity to a buffer. This trace
+ * shows which task is running when and is very useful as a debugging tool.
+ * As this macro is called each context switch it is a good idea to undefine
+ * it if not using the facility.
+ */
+#if ( configUSE_TRACE_FACILITY == 1 )
+
+ #define vWriteTraceToBuffer() \
+ { \
+ if( xTracing ) \
+ { \
+ if( uxPreviousTask != pxCurrentTCB->uxTCBNumber ) \
+ { \
+ if( ( pcTraceBuffer + tskSIZE_OF_EACH_TRACE_LINE ) < pcTraceBufferEnd ) \
+ { \
+ uxPreviousTask = pxCurrentTCB->uxTCBNumber; \
+ *( unsigned long * ) pcTraceBuffer = ( unsigned long ) xTickCount; \
+ pcTraceBuffer += sizeof( unsigned long ); \
+ *( unsigned long * ) pcTraceBuffer = ( unsigned long ) uxPreviousTask; \
+ pcTraceBuffer += sizeof( unsigned long ); \
+ } \
+ else \
+ { \
+ xTracing = pdFALSE; \
+ } \
+ } \
+ } \
+ }
+
+#else
+
+ #define vWriteTraceToBuffer()
+
+#endif
+/*-----------------------------------------------------------*/
+
+/*
+ * Place the task represented by pxTCB into the appropriate ready queue for
+ * the task. It is inserted at the end of the list. One quirk of this is
+ * that if the task being inserted is at the same priority as the currently
+ * executing task, then it will only be rescheduled after the currently
+ * executing task has been rescheduled.
+ */
+#define prvAddTaskToReadyQueue( pxTCB ) \
+ if( ( pxTCB )->uxPriority > uxTopReadyPriority ) \
+ { \
+ uxTopReadyPriority = ( pxTCB )->uxPriority; \
+ } \
+ vListInsertEnd( ( xList * ) &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xGenericListItem ) )
+/*-----------------------------------------------------------*/
+
+/*
+ * Macro that looks at the list of tasks that are currently delayed to see if
+ * any require waking.
+ *
+ * Tasks are stored in the queue in the order of their wake time - meaning
+ * once one tasks has been found whose timer has not expired we need not look
+ * any further down the list.
+ */
+#define prvCheckDelayedTasks() \
+{ \
+portTickType xItemValue; \
+ \
+ /* Is the tick count greater than or equal to the wake time of the first \
+ task referenced from the delayed tasks list? */ \
+ if( xTickCount >= xNextTaskUnblockTime ) \
+ { \
+ for( ;; ) \
+ { \
+ if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE ) \
+ { \
+ /* The delayed list is empty. Set xNextTaskUnblockTime to the \
+ maximum possible value so it is extremely unlikely that the \
+ if( xTickCount >= xNextTaskUnblockTime ) test will pass next \
+ time through. */ \
+ xNextTaskUnblockTime = portMAX_DELAY; \
+ break; \
+ } \
+ else \
+ { \
+ /* The delayed list is not empty, get the value of the item at \
+ the head of the delayed list. This is the time at which the \
+ task at the head of the delayed list should be removed from \
+ the Blocked state. */ \
+ pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ); \
+ xItemValue = listGET_LIST_ITEM_VALUE( &( pxTCB->xGenericListItem ) ); \
+ \
+ if( xTickCount < xItemValue ) \
+ { \
+ /* It is not time to unblock this item yet, but the item \
+ value is the time at which the task at the head of the \
+ blocked list should be removed from the Blocked state - \
+ so record the item value in xNextTaskUnblockTime. */ \
+ xNextTaskUnblockTime = xItemValue; \
+ break; \
+ } \
+ \
+ /* It is time to remove the item from the Blocked state. */ \
+ vListRemove( &( pxTCB->xGenericListItem ) ); \
+ \
+ /* Is the task waiting on an event also? */ \
+ if( pxTCB->xEventListItem.pvContainer ) \
+ { \
+ vListRemove( &( pxTCB->xEventListItem ) ); \
+ } \
+ prvAddTaskToReadyQueue( pxTCB ); \
+ } \
+ } \
+ } \
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * Several functions take an xTaskHandle parameter that can optionally be NULL,
+ * where NULL is used to indicate that the handle of the currently executing
+ * task should be used in place of the parameter. This macro simply checks to
+ * see if the parameter is NULL and returns a pointer to the appropriate TCB.
+ */
+#define prvGetTCBFromHandle( pxHandle ) ( ( ( pxHandle ) == NULL ) ? ( tskTCB * ) pxCurrentTCB : ( tskTCB * ) ( pxHandle ) )
+
+/* Callback function prototypes. --------------------------*/
+extern void vApplicationStackOverflowHook( xTaskHandle *pxTask, signed char *pcTaskName );
+extern void vApplicationTickHook( void );
+
+/* File private functions. --------------------------------*/
+
+/*
+ * Utility to ready a TCB for a given task. Mainly just copies the parameters
+ * into the TCB structure.
+ */
+static void prvInitialiseTCBVariables( tskTCB *pxTCB, const signed char * const pcName, unsigned portBASE_TYPE uxPriority, const xMemoryRegion * const xRegions, unsigned short usStackDepth ) PRIVILEGED_FUNCTION;
+
+/*
+ * Utility to ready all the lists used by the scheduler. This is called
+ * automatically upon the creation of the first task.
+ */
+static void prvInitialiseTaskLists( void ) PRIVILEGED_FUNCTION;
+
+/*
+ * The idle task, which as all tasks is implemented as a never ending loop.
+ * The idle task is automatically created and added to the ready lists upon
+ * creation of the first user task.
+ *
+ * The portTASK_FUNCTION_PROTO() macro is used to allow port/compiler specific
+ * language extensions. The equivalent prototype for this function is:
+ *
+ * void prvIdleTask( void *pvParameters );
+ *
+ */
+static portTASK_FUNCTION_PROTO( prvIdleTask, pvParameters );
+
+/*
+ * Utility to free all memory allocated by the scheduler to hold a TCB,
+ * including the stack pointed to by the TCB.
+ *
+ * This does not free memory allocated by the task itself (i.e. memory
+ * allocated by calls to pvPortMalloc from within the tasks application code).
+ */
+#if ( ( INCLUDE_vTaskDelete == 1 ) || ( INCLUDE_vTaskCleanUpResources == 1 ) )
+
+ static void prvDeleteTCB( tskTCB *pxTCB ) PRIVILEGED_FUNCTION;
+
+#endif
+
+/*
+ * Used only by the idle task. This checks to see if anything has been placed
+ * in the list of tasks waiting to be deleted. If so the task is cleaned up
+ * and its TCB deleted.
+ */
+static void prvCheckTasksWaitingTermination( void ) PRIVILEGED_FUNCTION;
+
+/*
+ * The currently executing task is entering the Blocked state. Add the task to
+ * either the current or the overflow delayed task list.
+ */
+static void prvAddCurrentTaskToDelayedList( portTickType xTimeToWake ) PRIVILEGED_FUNCTION;
+
+/*
+ * Allocates memory from the heap for a TCB and associated stack. Checks the
+ * allocation was successful.
+ */
+static tskTCB *prvAllocateTCBAndStack( unsigned short usStackDepth, portSTACK_TYPE *puxStackBuffer ) PRIVILEGED_FUNCTION;
+
+/*
+ * Called from vTaskList. vListTasks details all the tasks currently under
+ * control of the scheduler. The tasks may be in one of a number of lists.
+ * prvListTaskWithinSingleList accepts a list and details the tasks from
+ * within just that list.
+ *
+ * THIS FUNCTION IS INTENDED FOR DEBUGGING ONLY, AND SHOULD NOT BE CALLED FROM
+ * NORMAL APPLICATION CODE.
+ */
+#if ( configUSE_TRACE_FACILITY == 1 )
+
+ static void prvListTaskWithinSingleList( const signed char *pcWriteBuffer, xList *pxList, signed char cStatus ) PRIVILEGED_FUNCTION;
+
+#endif
+
+/*
+ * When a task is created, the stack of the task is filled with a known value.
+ * This function determines the 'high water mark' of the task stack by
+ * determining how much of the stack remains at the original preset value.
+ */
+#if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )
+
+ static unsigned short usTaskCheckFreeStackSpace( const unsigned char * pucStackByte ) PRIVILEGED_FUNCTION;
+
+#endif
+
+
+/*lint +e956 */
+
+
+
+/*-----------------------------------------------------------
+ * TASK CREATION API documented in task.h
+ *----------------------------------------------------------*/
+
+signed portBASE_TYPE xTaskGenericCreate( pdTASK_CODE pxTaskCode, const signed char * const pcName, unsigned short usStackDepth, void *pvParameters, unsigned portBASE_TYPE uxPriority, xTaskHandle *pxCreatedTask, portSTACK_TYPE *puxStackBuffer, const xMemoryRegion * const xRegions )
+{
+signed portBASE_TYPE xReturn;
+tskTCB * pxNewTCB;
+
+ configASSERT( pxTaskCode );
+ configASSERT( ( uxPriority < configMAX_PRIORITIES ) );
+
+ /* Allocate the memory required by the TCB and stack for the new task,
+ checking that the allocation was successful. */
+ pxNewTCB = prvAllocateTCBAndStack( usStackDepth, puxStackBuffer );
+
+ if( pxNewTCB != NULL )
+ {
+ portSTACK_TYPE *pxTopOfStack;
+
+ #if( portUSING_MPU_WRAPPERS == 1 )
+ /* Should the task be created in privileged mode? */
+ portBASE_TYPE xRunPrivileged;
+ if( ( uxPriority & portPRIVILEGE_BIT ) != 0x00 )
+ {
+ xRunPrivileged = pdTRUE;
+ }
+ else
+ {
+ xRunPrivileged = pdFALSE;
+ }
+ uxPriority &= ~portPRIVILEGE_BIT;
+ #endif /* portUSING_MPU_WRAPPERS == 1 */
+
+ /* Calculate the top of stack address. This depends on whether the
+ stack grows from high memory to low (as per the 80x86) or visa versa.
+ portSTACK_GROWTH is used to make the result positive or negative as
+ required by the port. */
+ #if( portSTACK_GROWTH < 0 )
+ {
+ pxTopOfStack = pxNewTCB->pxStack + ( usStackDepth - ( unsigned short ) 1 );
+ pxTopOfStack = ( portSTACK_TYPE * ) ( ( ( unsigned long ) pxTopOfStack ) & ( ( unsigned long ) ~portBYTE_ALIGNMENT_MASK ) );
+
+ /* Check the alignment of the calculated top of stack is correct. */
+ configASSERT( ( ( ( unsigned long ) pxTopOfStack & ( unsigned long ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );
+ }
+ #else
+ {
+ pxTopOfStack = pxNewTCB->pxStack;
+
+ /* Check the alignment of the stack buffer is correct. */
+ configASSERT( ( ( ( unsigned long ) pxNewTCB->pxStack & ( unsigned long ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );
+
+ /* If we want to use stack checking on architectures that use
+ a positive stack growth direction then we also need to store the
+ other extreme of the stack space. */
+ pxNewTCB->pxEndOfStack = pxNewTCB->pxStack + ( usStackDepth - 1 );
+ }
+ #endif
+
+ /* Setup the newly allocated TCB with the initial state of the task. */
+ prvInitialiseTCBVariables( pxNewTCB, pcName, uxPriority, xRegions, usStackDepth );
+
+ /* Initialize the TCB stack to look as if the task was already running,
+ but had been interrupted by the scheduler. The return address is set
+ to the start of the task function. Once the stack has been initialised
+ the top of stack variable is updated. */
+ #if( portUSING_MPU_WRAPPERS == 1 )
+ {
+ pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters, xRunPrivileged );
+ }
+ #else
+ {
+ pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters );
+ }
+ #endif
+
+ /* Check the alignment of the initialised stack. */
+ configASSERT( ( ( ( unsigned long ) pxNewTCB->pxTopOfStack & ( unsigned long ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );
+
+ if( ( void * ) pxCreatedTask != NULL )
+ {
+ /* Pass the TCB out - in an anonymous way. The calling function/
+ task can use this as a handle to delete the task later if
+ required.*/
+ *pxCreatedTask = ( xTaskHandle ) pxNewTCB;
+ }
+
+ /* We are going to manipulate the task queues to add this task to a
+ ready list, so must make sure no interrupts occur. */
+ taskENTER_CRITICAL();
+ {
+ uxCurrentNumberOfTasks++;
+ if( pxCurrentTCB == NULL )
+ {
+ /* There are no other tasks, or all the other tasks are in
+ the suspended state - make this the current task. */
+ pxCurrentTCB = pxNewTCB;
+
+ if( uxCurrentNumberOfTasks == ( unsigned portBASE_TYPE ) 1 )
+ {
+ /* This is the first task to be created so do the preliminary
+ initialisation required. We will not recover if this call
+ fails, but we will report the failure. */
+ prvInitialiseTaskLists();
+ }
+ }
+ else
+ {
+ /* If the scheduler is not already running, make this task the
+ current task if it is the highest priority task to be created
+ so far. */
+ if( xSchedulerRunning == pdFALSE )
+ {
+ if( pxCurrentTCB->uxPriority <= uxPriority )
+ {
+ pxCurrentTCB = pxNewTCB;
+ }
+ }
+ }
+
+ /* Remember the top priority to make context switching faster. Use
+ the priority in pxNewTCB as this has been capped to a valid value. */
+ if( pxNewTCB->uxPriority > uxTopUsedPriority )
+ {
+ uxTopUsedPriority = pxNewTCB->uxPriority;
+ }
+
+ #if ( configUSE_TRACE_FACILITY == 1 )
+ {
+ /* Add a counter into the TCB for tracing only. */
+ pxNewTCB->uxTCBNumber = uxTaskNumber;
+ }
+ #endif
+ uxTaskNumber++;
+
+ prvAddTaskToReadyQueue( pxNewTCB );
+
+ xReturn = pdPASS;
+ traceTASK_CREATE( pxNewTCB );
+ }
+ taskEXIT_CRITICAL();
+ }
+ else
+ {
+ xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
+ traceTASK_CREATE_FAILED();
+ }
+
+ if( xReturn == pdPASS )
+ {
+ if( xSchedulerRunning != pdFALSE )
+ {
+ /* If the created task is of a higher priority than the current task
+ then it should run now. */
+ if( pxCurrentTCB->uxPriority < uxPriority )
+ {
+ portYIELD_WITHIN_API();
+ }
+ }
+ }
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+#if ( INCLUDE_vTaskDelete == 1 )
+
+ void vTaskDelete( xTaskHandle pxTaskToDelete )
+ {
+ tskTCB *pxTCB;
+
+ taskENTER_CRITICAL();
+ {
+ /* Ensure a yield is performed if the current task is being
+ deleted. */
+ if( pxTaskToDelete == pxCurrentTCB )
+ {
+ pxTaskToDelete = NULL;
+ }
+
+ /* If null is passed in here then we are deleting ourselves. */
+ pxTCB = prvGetTCBFromHandle( pxTaskToDelete );
+
+ /* Remove task from the ready list and place in the termination list.
+ This will stop the task from be scheduled. The idle task will check
+ the termination list and free up any memory allocated by the
+ scheduler for the TCB and stack. */
+ vListRemove( &( pxTCB->xGenericListItem ) );
+
+ /* Is the task waiting on an event also? */
+ if( pxTCB->xEventListItem.pvContainer )
+ {
+ vListRemove( &( pxTCB->xEventListItem ) );
+ }
+
+ vListInsertEnd( ( xList * ) &xTasksWaitingTermination, &( pxTCB->xGenericListItem ) );
+
+ /* Increment the ucTasksDeleted variable so the idle task knows
+ there is a task that has been deleted and that it should therefore
+ check the xTasksWaitingTermination list. */
+ ++uxTasksDeleted;
+
+ /* Increment the uxTaskNumberVariable also so kernel aware debuggers
+ can detect that the task lists need re-generating. */
+ uxTaskNumber++;
+
+ traceTASK_DELETE( pxTCB );
+ }
+ taskEXIT_CRITICAL();
+
+ /* Force a reschedule if we have just deleted the current task. */
+ if( xSchedulerRunning != pdFALSE )
+ {
+ if( ( void * ) pxTaskToDelete == NULL )
+ {
+ portYIELD_WITHIN_API();
+ }
+ }
+ }
+
+#endif
+
+
+
+
+
+
+/*-----------------------------------------------------------
+ * TASK CONTROL API documented in task.h
+ *----------------------------------------------------------*/
+
+#if ( INCLUDE_vTaskDelayUntil == 1 )
+
+ void vTaskDelayUntil( portTickType * const pxPreviousWakeTime, portTickType xTimeIncrement )
+ {
+ portTickType xTimeToWake;
+ portBASE_TYPE xAlreadyYielded, xShouldDelay = pdFALSE;
+
+ configASSERT( pxPreviousWakeTime );
+ configASSERT( ( xTimeIncrement > 0 ) );
+
+ vTaskSuspendAll();
+ {
+ /* Generate the tick time at which the task wants to wake. */
+ xTimeToWake = *pxPreviousWakeTime + xTimeIncrement;
+
+ if( xTickCount < *pxPreviousWakeTime )
+ {
+ /* The tick count has overflowed since this function was
+ lasted called. In this case the only time we should ever
+ actually delay is if the wake time has also overflowed,
+ and the wake time is greater than the tick time. When this
+ is the case it is as if neither time had overflowed. */
+ if( ( xTimeToWake < *pxPreviousWakeTime ) && ( xTimeToWake > xTickCount ) )
+ {
+ xShouldDelay = pdTRUE;
+ }
+ }
+ else
+ {
+ /* The tick time has not overflowed. In this case we will
+ delay if either the wake time has overflowed, and/or the
+ tick time is less than the wake time. */
+ if( ( xTimeToWake < *pxPreviousWakeTime ) || ( xTimeToWake > xTickCount ) )
+ {
+ xShouldDelay = pdTRUE;
+ }
+ }
+
+ /* Update the wake time ready for the next call. */
+ *pxPreviousWakeTime = xTimeToWake;
+
+ if( xShouldDelay != pdFALSE )
+ {
+ traceTASK_DELAY_UNTIL();
+
+ /* We must remove ourselves from the ready list before adding
+ ourselves to the blocked list as the same list item is used for
+ both lists. */
+ vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
+ prvAddCurrentTaskToDelayedList( xTimeToWake );
+ }
+ }
+ xAlreadyYielded = xTaskResumeAll();
+
+ /* Force a reschedule if xTaskResumeAll has not already done so, we may
+ have put ourselves to sleep. */
+ if( !xAlreadyYielded )
+ {
+ portYIELD_WITHIN_API();
+ }
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+#if ( INCLUDE_vTaskDelay == 1 )
+
+ void vTaskDelay( portTickType xTicksToDelay )
+ {
+ portTickType xTimeToWake;
+ signed portBASE_TYPE xAlreadyYielded = pdFALSE;
+
+ /* A delay time of zero just forces a reschedule. */
+ if( xTicksToDelay > ( portTickType ) 0 )
+ {
+ vTaskSuspendAll();
+ {
+ traceTASK_DELAY();
+
+ /* A task that is removed from the event list while the
+ scheduler is suspended will not get placed in the ready
+ list or removed from the blocked list until the scheduler
+ is resumed.
+
+ This task cannot be in an event list as it is the currently
+ executing task. */
+
+ /* Calculate the time to wake - this may overflow but this is
+ not a problem. */
+ xTimeToWake = xTickCount + xTicksToDelay;
+
+ /* We must remove ourselves from the ready list before adding
+ ourselves to the blocked list as the same list item is used for
+ both lists. */
+ vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
+ prvAddCurrentTaskToDelayedList( xTimeToWake );
+ }
+ xAlreadyYielded = xTaskResumeAll();
+ }
+
+ /* Force a reschedule if xTaskResumeAll has not already done so, we may
+ have put ourselves to sleep. */
+ if( !xAlreadyYielded )
+ {
+ portYIELD_WITHIN_API();
+ }
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+#if ( INCLUDE_uxTaskPriorityGet == 1 )
+
+ unsigned portBASE_TYPE uxTaskPriorityGet( xTaskHandle pxTask )
+ {
+ tskTCB *pxTCB;
+ unsigned portBASE_TYPE uxReturn;
+
+ taskENTER_CRITICAL();
+ {
+ /* If null is passed in here then we are changing the
+ priority of the calling function. */
+ pxTCB = prvGetTCBFromHandle( pxTask );
+ uxReturn = pxTCB->uxPriority;
+ }
+ taskEXIT_CRITICAL();
+
+ return uxReturn;
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+#if ( INCLUDE_vTaskPrioritySet == 1 )
+
+ void vTaskPrioritySet( xTaskHandle pxTask, unsigned portBASE_TYPE uxNewPriority )
+ {
+ tskTCB *pxTCB;
+ unsigned portBASE_TYPE uxCurrentPriority;
+ portBASE_TYPE xYieldRequired = pdFALSE;
+
+ configASSERT( ( uxNewPriority < configMAX_PRIORITIES ) );
+
+ /* Ensure the new priority is valid. */
+ if( uxNewPriority >= configMAX_PRIORITIES )
+ {
+ uxNewPriority = configMAX_PRIORITIES - ( unsigned portBASE_TYPE ) 1U;
+ }
+
+ taskENTER_CRITICAL();
+ {
+ if( pxTask == pxCurrentTCB )
+ {
+ pxTask = NULL;
+ }
+
+ /* If null is passed in here then we are changing the
+ priority of the calling function. */
+ pxTCB = prvGetTCBFromHandle( pxTask );
+
+ traceTASK_PRIORITY_SET( pxTask, uxNewPriority );
+
+ #if ( configUSE_MUTEXES == 1 )
+ {
+ uxCurrentPriority = pxTCB->uxBasePriority;
+ }
+ #else
+ {
+ uxCurrentPriority = pxTCB->uxPriority;
+ }
+ #endif
+
+ if( uxCurrentPriority != uxNewPriority )
+ {
+ /* The priority change may have readied a task of higher
+ priority than the calling task. */
+ if( uxNewPriority > uxCurrentPriority )
+ {
+ if( pxTask != NULL )
+ {
+ /* The priority of another task is being raised. If we
+ were raising the priority of the currently running task
+ there would be no need to switch as it must have already
+ been the highest priority task. */
+ xYieldRequired = pdTRUE;
+ }
+ }
+ else if( pxTask == NULL )
+ {
+ /* Setting our own priority down means there may now be another
+ task of higher priority that is ready to execute. */
+ xYieldRequired = pdTRUE;
+ }
+
+
+
+ #if ( configUSE_MUTEXES == 1 )
+ {
+ /* Only change the priority being used if the task is not
+ currently using an inherited priority. */
+ if( pxTCB->uxBasePriority == pxTCB->uxPriority )
+ {
+ pxTCB->uxPriority = uxNewPriority;
+ }
+
+ /* The base priority gets set whatever. */
+ pxTCB->uxBasePriority = uxNewPriority;
+ }
+ #else
+ {
+ pxTCB->uxPriority = uxNewPriority;
+ }
+ #endif
+
+ listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( configMAX_PRIORITIES - ( portTickType ) uxNewPriority ) );
+
+ /* If the task is in the blocked or suspended list we need do
+ nothing more than change it's priority variable. However, if
+ the task is in a ready list it needs to be removed and placed
+ in the queue appropriate to its new priority. */
+ if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxCurrentPriority ] ), &( pxTCB->xGenericListItem ) ) )
+ {
+ /* The task is currently in its ready list - remove before adding
+ it to it's new ready list. As we are in a critical section we
+ can do this even if the scheduler is suspended. */
+ vListRemove( &( pxTCB->xGenericListItem ) );
+ prvAddTaskToReadyQueue( pxTCB );
+ }
+
+ if( xYieldRequired == pdTRUE )
+ {
+ portYIELD_WITHIN_API();
+ }
+ }
+ }
+ taskEXIT_CRITICAL();
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+#if ( INCLUDE_vTaskSuspend == 1 )
+
+ void vTaskSuspend( xTaskHandle pxTaskToSuspend )
+ {
+ tskTCB *pxTCB;
+
+ taskENTER_CRITICAL();
+ {
+ /* Ensure a yield is performed if the current task is being
+ suspended. */
+ if( pxTaskToSuspend == pxCurrentTCB )
+ {
+ pxTaskToSuspend = NULL;
+ }
+
+ /* If null is passed in here then we are suspending ourselves. */
+ pxTCB = prvGetTCBFromHandle( pxTaskToSuspend );
+
+ traceTASK_SUSPEND( pxTCB );
+
+ /* Remove task from the ready/delayed list and place in the suspended list. */
+ vListRemove( &( pxTCB->xGenericListItem ) );
+
+ /* Is the task waiting on an event also? */
+ if( pxTCB->xEventListItem.pvContainer )
+ {
+ vListRemove( &( pxTCB->xEventListItem ) );
+ }
+
+ vListInsertEnd( ( xList * ) &xSuspendedTaskList, &( pxTCB->xGenericListItem ) );
+ }
+ taskEXIT_CRITICAL();
+
+ if( ( void * ) pxTaskToSuspend == NULL )
+ {
+ if( xSchedulerRunning != pdFALSE )
+ {
+ /* We have just suspended the current task. */
+ portYIELD_WITHIN_API();
+ }
+ else
+ {
+ /* The scheduler is not running, but the task that was pointed
+ to by pxCurrentTCB has just been suspended and pxCurrentTCB
+ must be adjusted to point to a different task. */
+ if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == uxCurrentNumberOfTasks )
+ {
+ /* No other tasks are ready, so set pxCurrentTCB back to
+ NULL so when the next task is created pxCurrentTCB will
+ be set to point to it no matter what its relative priority
+ is. */
+ pxCurrentTCB = NULL;
+ }
+ else
+ {
+ vTaskSwitchContext();
+ }
+ }
+ }
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+#if ( INCLUDE_vTaskSuspend == 1 )
+
+ signed portBASE_TYPE xTaskIsTaskSuspended( xTaskHandle xTask )
+ {
+ portBASE_TYPE xReturn = pdFALSE;
+ const tskTCB * const pxTCB = ( tskTCB * ) xTask;
+
+ /* It does not make sense to check if the calling task is suspended. */
+ configASSERT( xTask );
+
+ /* Is the task we are attempting to resume actually in the
+ suspended list? */
+ if( listIS_CONTAINED_WITHIN( &xSuspendedTaskList, &( pxTCB->xGenericListItem ) ) != pdFALSE )
+ {
+ /* Has the task already been resumed from within an ISR? */
+ if( listIS_CONTAINED_WITHIN( &xPendingReadyList, &( pxTCB->xEventListItem ) ) != pdTRUE )
+ {
+ /* Is it in the suspended list because it is in the
+ Suspended state? It is possible to be in the suspended
+ list because it is blocked on a task with no timeout
+ specified. */
+ if( listIS_CONTAINED_WITHIN( NULL, &( pxTCB->xEventListItem ) ) == pdTRUE )
+ {
+ xReturn = pdTRUE;
+ }
+ }
+ }
+
+ return xReturn;
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+#if ( INCLUDE_vTaskSuspend == 1 )
+
+ void vTaskResume( xTaskHandle pxTaskToResume )
+ {
+ tskTCB *pxTCB;
+
+ /* It does not make sense to resume the calling task. */
+ configASSERT( pxTaskToResume );
+
+ /* Remove the task from whichever list it is currently in, and place
+ it in the ready list. */
+ pxTCB = ( tskTCB * ) pxTaskToResume;
+
+ /* The parameter cannot be NULL as it is impossible to resume the
+ currently executing task. */
+ if( ( pxTCB != NULL ) && ( pxTCB != pxCurrentTCB ) )
+ {
+ taskENTER_CRITICAL();
+ {
+ if( xTaskIsTaskSuspended( pxTCB ) == pdTRUE )
+ {
+ traceTASK_RESUME( pxTCB );
+
+ /* As we are in a critical section we can access the ready
+ lists even if the scheduler is suspended. */
+ vListRemove( &( pxTCB->xGenericListItem ) );
+ prvAddTaskToReadyQueue( pxTCB );
+
+ /* We may have just resumed a higher priority task. */
+ if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
+ {
+ /* This yield may not cause the task just resumed to run, but
+ will leave the lists in the correct state for the next yield. */
+ portYIELD_WITHIN_API();
+ }
+ }
+ }
+ taskEXIT_CRITICAL();
+ }
+ }
+
+#endif
+
+/*-----------------------------------------------------------*/
+
+#if ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )
+
+ portBASE_TYPE xTaskResumeFromISR( xTaskHandle pxTaskToResume )
+ {
+ portBASE_TYPE xYieldRequired = pdFALSE;
+ tskTCB *pxTCB;
+
+ configASSERT( pxTaskToResume );
+
+ pxTCB = ( tskTCB * ) pxTaskToResume;
+
+ if( xTaskIsTaskSuspended( pxTCB ) == pdTRUE )
+ {
+ traceTASK_RESUME_FROM_ISR( pxTCB );
+
+ if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
+ {
+ xYieldRequired = ( pxTCB->uxPriority >= pxCurrentTCB->uxPriority );
+ vListRemove( &( pxTCB->xGenericListItem ) );
+ prvAddTaskToReadyQueue( pxTCB );
+ }
+ else
+ {
+ /* We cannot access the delayed or ready lists, so will hold this
+ task pending until the scheduler is resumed, at which point a
+ yield will be performed if necessary. */
+ vListInsertEnd( ( xList * ) &( xPendingReadyList ), &( pxTCB->xEventListItem ) );
+ }
+ }
+
+ return xYieldRequired;
+ }
+
+#endif
+
+
+
+
+/*-----------------------------------------------------------
+ * PUBLIC SCHEDULER CONTROL documented in task.h
+ *----------------------------------------------------------*/
+
+
+void vTaskStartScheduler( void )
+{
+portBASE_TYPE xReturn;
+
+ /* Add the idle task at the lowest priority. */
+ xReturn = xTaskCreate( prvIdleTask, ( signed char * ) "IDLE", tskIDLE_STACK_SIZE, ( void * ) NULL, ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), ( xTaskHandle * ) NULL );
+
+ #if ( configUSE_TIMERS == 1 )
+ {
+ if( xReturn == pdPASS )
+ {
+ xReturn = xTimerCreateTimerTask();
+ }
+ }
+ #endif
+
+ if( xReturn == pdPASS )
+ {
+ /* Interrupts are turned off here, to ensure a tick does not occur
+ before or during the call to xPortStartScheduler(). The stacks of
+ the created tasks contain a status word with interrupts switched on
+ so interrupts will automatically get re-enabled when the first task
+ starts to run.
+
+ STEPPING THROUGH HERE USING A DEBUGGER CAN CAUSE BIG PROBLEMS IF THE
+ DEBUGGER ALLOWS INTERRUPTS TO BE PROCESSED. */
+ portDISABLE_INTERRUPTS();
+
+ xSchedulerRunning = pdTRUE;
+ xTickCount = ( portTickType ) 0;
+
+ /* If configGENERATE_RUN_TIME_STATS is defined then the following
+ macro must be defined to configure the timer/counter used to generate
+ the run time counter time base. */
+ portCONFIGURE_TIMER_FOR_RUN_TIME_STATS();
+
+ /* Setting up the timer tick is hardware specific and thus in the
+ portable interface. */
+ if( xPortStartScheduler() )
+ {
+ /* Should not reach here as if the scheduler is running the
+ function will not return. */
+ }
+ else
+ {
+ /* Should only reach here if a task calls xTaskEndScheduler(). */
+ }
+ }
+
+ /* This line will only be reached if the kernel could not be started. */
+ configASSERT( xReturn );
+}
+/*-----------------------------------------------------------*/
+
+void vTaskEndScheduler( void )
+{
+ /* Stop the scheduler interrupts and call the portable scheduler end
+ routine so the original ISRs can be restored if necessary. The port
+ layer must ensure interrupts enable bit is left in the correct state. */
+ portDISABLE_INTERRUPTS();
+ xSchedulerRunning = pdFALSE;
+ vPortEndScheduler();
+}
+/*----------------------------------------------------------*/
+
+void vTaskSuspendAll( void )
+{
+ /* A critical section is not required as the variable is of type
+ portBASE_TYPE. */
+ ++uxSchedulerSuspended;
+}
+/*----------------------------------------------------------*/
+
+signed portBASE_TYPE xTaskResumeAll( void )
+{
+register tskTCB *pxTCB;
+signed portBASE_TYPE xAlreadyYielded = pdFALSE;
+
+ /* If uxSchedulerSuspended is zero then this function does not match a
+ previous call to vTaskSuspendAll(). */
+ configASSERT( uxSchedulerSuspended );
+
+ /* It is possible that an ISR caused a task to be removed from an event
+ list while the scheduler was suspended. If this was the case then the
+ removed task will have been added to the xPendingReadyList. Once the
+ scheduler has been resumed it is safe to move all the pending ready
+ tasks from this list into their appropriate ready list. */
+ taskENTER_CRITICAL();
+ {
+ --uxSchedulerSuspended;
+
+ if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
+ {
+ if( uxCurrentNumberOfTasks > ( unsigned portBASE_TYPE ) 0 )
+ {
+ portBASE_TYPE xYieldRequired = pdFALSE;
+
+ /* Move any readied tasks from the pending list into the
+ appropriate ready list. */
+ while( listLIST_IS_EMPTY( ( xList * ) &xPendingReadyList ) == pdFALSE )
+ {
+ pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( ( ( xList * ) &xPendingReadyList ) );
+ vListRemove( &( pxTCB->xEventListItem ) );
+ vListRemove( &( pxTCB->xGenericListItem ) );
+ prvAddTaskToReadyQueue( pxTCB );
+
+ /* If we have moved a task that has a priority higher than
+ the current task then we should yield. */
+ if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
+ {
+ xYieldRequired = pdTRUE;
+ }
+ }
+
+ /* If any ticks occurred while the scheduler was suspended then
+ they should be processed now. This ensures the tick count does not
+ slip, and that any delayed tasks are resumed at the correct time. */
+ if( uxMissedTicks > ( unsigned portBASE_TYPE ) 0 )
+ {
+ while( uxMissedTicks > ( unsigned portBASE_TYPE ) 0 )
+ {
+ vTaskIncrementTick();
+ --uxMissedTicks;
+ }
+
+ /* As we have processed some ticks it is appropriate to yield
+ to ensure the highest priority task that is ready to run is
+ the task actually running. */
+ #if configUSE_PREEMPTION == 1
+ {
+ xYieldRequired = pdTRUE;
+ }
+ #endif
+ }
+
+ if( ( xYieldRequired == pdTRUE ) || ( xMissedYield == pdTRUE ) )
+ {
+ xAlreadyYielded = pdTRUE;
+ xMissedYield = pdFALSE;
+ portYIELD_WITHIN_API();
+ }
+ }
+ }
+ }
+ taskEXIT_CRITICAL();
+
+ return xAlreadyYielded;
+}
+
+
+
+
+
+
+/*-----------------------------------------------------------
+ * PUBLIC TASK UTILITIES documented in task.h
+ *----------------------------------------------------------*/
+
+
+
+portTickType xTaskGetTickCount( void )
+{
+portTickType xTicks;
+
+ /* Critical section required if running on a 16 bit processor. */
+ taskENTER_CRITICAL();
+ {
+ xTicks = xTickCount;
+ }
+ taskEXIT_CRITICAL();
+
+ return xTicks;
+}
+/*-----------------------------------------------------------*/
+
+portTickType xTaskGetTickCountFromISR( void )
+{
+portTickType xReturn;
+unsigned portBASE_TYPE uxSavedInterruptStatus;
+
+ uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
+ xReturn = xTickCount;
+ portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+unsigned portBASE_TYPE uxTaskGetNumberOfTasks( void )
+{
+ /* A critical section is not required because the variables are of type
+ portBASE_TYPE. */
+ return uxCurrentNumberOfTasks;
+}
+/*-----------------------------------------------------------*/
+
+#if ( configUSE_TRACE_FACILITY == 1 )
+
+ void vTaskList( signed char *pcWriteBuffer )
+ {
+ unsigned portBASE_TYPE uxQueue;
+
+ /* This is a VERY costly function that should be used for debug only.
+ It leaves interrupts disabled for a LONG time. */
+
+ vTaskSuspendAll();
+ {
+ /* Run through all the lists that could potentially contain a TCB and
+ report the task name, state and stack high water mark. */
+
+ *pcWriteBuffer = ( signed char ) 0x00;
+ strcat( ( char * ) pcWriteBuffer, ( const char * ) "\r\n" );
+
+ uxQueue = uxTopUsedPriority + ( unsigned portBASE_TYPE ) 1U;
+
+ do
+ {
+ uxQueue--;
+
+ if( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxQueue ] ) ) == pdFALSE )
+ {
+ prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &( pxReadyTasksLists[ uxQueue ] ), tskREADY_CHAR );
+ }
+ }while( uxQueue > ( unsigned short ) tskIDLE_PRIORITY );
+
+ if( listLIST_IS_EMPTY( pxDelayedTaskList ) == pdFALSE )
+ {
+ prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) pxDelayedTaskList, tskBLOCKED_CHAR );
+ }
+
+ if( listLIST_IS_EMPTY( pxOverflowDelayedTaskList ) == pdFALSE )
+ {
+ prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) pxOverflowDelayedTaskList, tskBLOCKED_CHAR );
+ }
+
+ #if( INCLUDE_vTaskDelete == 1 )
+ {
+ if( listLIST_IS_EMPTY( &xTasksWaitingTermination ) == pdFALSE )
+ {
+ prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &xTasksWaitingTermination, tskDELETED_CHAR );
+ }
+ }
+ #endif
+
+ #if ( INCLUDE_vTaskSuspend == 1 )
+ {
+ if( listLIST_IS_EMPTY( &xSuspendedTaskList ) == pdFALSE )
+ {
+ prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &xSuspendedTaskList, tskSUSPENDED_CHAR );
+ }
+ }
+ #endif
+ }
+ xTaskResumeAll();
+ }
+
+#endif
+/*----------------------------------------------------------*/
+
+#if ( configGENERATE_RUN_TIME_STATS == 1 )
+
+ void vTaskGetRunTimeStats( signed char *pcWriteBuffer )
+ {
+ unsigned portBASE_TYPE uxQueue;
+ unsigned long ulTotalRunTime;
+
+ /* This is a VERY costly function that should be used for debug only.
+ It leaves interrupts disabled for a LONG time. */
+
+ vTaskSuspendAll();
+ {
+ #ifdef portALT_GET_RUN_TIME_COUNTER_VALUE
+ portALT_GET_RUN_TIME_COUNTER_VALUE( ulTotalRunTime );
+ #else
+ ulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE();
+ #endif
+
+ /* Divide ulTotalRunTime by 100 to make the percentage caluclations
+ simpler in the prvGenerateRunTimeStatsForTasksInList() function. */
+ ulTotalRunTime /= 100UL;
+
+ /* Run through all the lists that could potentially contain a TCB,
+ generating a table of run timer percentages in the provided
+ buffer. */
+
+ *pcWriteBuffer = ( signed char ) 0x00;
+ strcat( ( char * ) pcWriteBuffer, ( const char * ) "\r\n" );
+
+ uxQueue = uxTopUsedPriority + ( unsigned portBASE_TYPE ) 1U;
+
+ do
+ {
+ uxQueue--;
+
+ if( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxQueue ] ) ) == pdFALSE )
+ {
+ prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) &( pxReadyTasksLists[ uxQueue ] ), ulTotalRunTime );
+ }
+ }while( uxQueue > ( unsigned short ) tskIDLE_PRIORITY );
+
+ if( listLIST_IS_EMPTY( pxDelayedTaskList ) == pdFALSE )
+ {
+ prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) pxDelayedTaskList, ulTotalRunTime );
+ }
+
+ if( listLIST_IS_EMPTY( pxOverflowDelayedTaskList ) == pdFALSE )
+ {
+ prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) pxOverflowDelayedTaskList, ulTotalRunTime );
+ }
+
+ #if ( INCLUDE_vTaskDelete == 1 )
+ {
+ if( listLIST_IS_EMPTY( &xTasksWaitingTermination ) == pdFALSE )
+ {
+ prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) &xTasksWaitingTermination, ulTotalRunTime );
+ }
+ }
+ #endif
+
+ #if ( INCLUDE_vTaskSuspend == 1 )
+ {
+ if( listLIST_IS_EMPTY( &xSuspendedTaskList ) == pdFALSE )
+ {
+ prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) &xSuspendedTaskList, ulTotalRunTime );
+ }
+ }
+ #endif
+ }
+ xTaskResumeAll();
+ }
+
+#endif
+/*----------------------------------------------------------*/
+
+#if ( configUSE_TRACE_FACILITY == 1 )
+
+ void vTaskStartTrace( signed char * pcBuffer, unsigned long ulBufferSize )
+ {
+ configASSERT( pcBuffer );
+ configASSERT( ulBufferSize );
+
+ taskENTER_CRITICAL();
+ {
+ pcTraceBuffer = ( signed char * )pcBuffer;
+ pcTraceBufferStart = pcBuffer;
+ pcTraceBufferEnd = pcBuffer + ( ulBufferSize - tskSIZE_OF_EACH_TRACE_LINE );
+ xTracing = pdTRUE;
+ }
+ taskEXIT_CRITICAL();
+ }
+
+#endif
+/*----------------------------------------------------------*/
+
+#if ( configUSE_TRACE_FACILITY == 1 )
+
+ unsigned long ulTaskEndTrace( void )
+ {
+ unsigned long ulBufferLength;
+
+ taskENTER_CRITICAL();
+ xTracing = pdFALSE;
+ taskEXIT_CRITICAL();
+
+ ulBufferLength = ( unsigned long ) ( pcTraceBuffer - pcTraceBufferStart );
+
+ return ulBufferLength;
+ }
+
+#endif
+
+
+
+/*-----------------------------------------------------------
+ * SCHEDULER INTERNALS AVAILABLE FOR PORTING PURPOSES
+ * documented in task.h
+ *----------------------------------------------------------*/
+
+
+void vTaskIncrementTick( void )
+{
+tskTCB * pxTCB;
+
+ /* Called by the portable layer each time a tick interrupt occurs.
+ Increments the tick then checks to see if the new tick value will cause any
+ tasks to be unblocked. */
+ if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
+ {
+ ++xTickCount;
+ if( xTickCount == ( portTickType ) 0 )
+ {
+ xList *pxTemp;
+
+ /* Tick count has overflowed so we need to swap the delay lists.
+ If there are any items in pxDelayedTaskList here then there is
+ an error! */
+ configASSERT( ( listLIST_IS_EMPTY( pxDelayedTaskList ) ) );
+
+ pxTemp = pxDelayedTaskList;
+ pxDelayedTaskList = pxOverflowDelayedTaskList;
+ pxOverflowDelayedTaskList = pxTemp;
+ xNumOfOverflows++;
+
+ if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE )
+ {
+ /* The new current delayed list is empty. Set
+ xNextTaskUnblockTime to the maximum possible value so it is
+ extremely unlikely that the
+ if( xTickCount >= xNextTaskUnblockTime ) test will pass until
+ there is an item in the delayed list. */
+ xNextTaskUnblockTime = portMAX_DELAY;
+ }
+ else
+ {
+ /* The new current delayed list is not empty, get the value of
+ the item at the head of the delayed list. This is the time at
+ which the task at the head of the delayed list should be removed
+ from the Blocked state. */
+ pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList );
+ xNextTaskUnblockTime = listGET_LIST_ITEM_VALUE( &( pxTCB->xGenericListItem ) );
+ }
+ }
+
+ /* See if this tick has made a timeout expire. */
+ prvCheckDelayedTasks();
+ }
+ else
+ {
+ ++uxMissedTicks;
+
+ /* The tick hook gets called at regular intervals, even if the
+ scheduler is locked. */
+ #if ( configUSE_TICK_HOOK == 1 )
+ {
+ vApplicationTickHook();
+ }
+ #endif
+ }
+
+ #if ( configUSE_TICK_HOOK == 1 )
+ {
+ /* Guard against the tick hook being called when the missed tick
+ count is being unwound (when the scheduler is being unlocked. */
+ if( uxMissedTicks == ( unsigned portBASE_TYPE ) 0U )
+ {
+ vApplicationTickHook();
+ }
+ }
+ #endif
+
+ traceTASK_INCREMENT_TICK( xTickCount );
+}
+/*-----------------------------------------------------------*/
+
+#if ( ( INCLUDE_vTaskCleanUpResources == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )
+
+ void vTaskCleanUpResources( void )
+ {
+ unsigned short usQueue;
+ volatile tskTCB *pxTCB;
+
+ usQueue = ( unsigned short ) uxTopUsedPriority + ( unsigned short ) 1;
+
+ /* Remove any TCB's from the ready queues. */
+ do
+ {
+ usQueue--;
+
+ while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ usQueue ] ) ) == pdFALSE )
+ {
+ listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &( pxReadyTasksLists[ usQueue ] ) );
+ vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
+
+ prvDeleteTCB( ( tskTCB * ) pxTCB );
+ }
+ }while( usQueue > ( unsigned short ) tskIDLE_PRIORITY );
+
+ /* Remove any TCB's from the delayed queue. */
+ while( listLIST_IS_EMPTY( &xDelayedTaskList1 ) == pdFALSE )
+ {
+ listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &xDelayedTaskList1 );
+ vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
+
+ prvDeleteTCB( ( tskTCB * ) pxTCB );
+ }
+
+ /* Remove any TCB's from the overflow delayed queue. */
+ while( listLIST_IS_EMPTY( &xDelayedTaskList2 ) == pdFALSE )
+ {
+ listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &xDelayedTaskList2 );
+ vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
+
+ prvDeleteTCB( ( tskTCB * ) pxTCB );
+ }
+
+ while( listLIST_IS_EMPTY( &xSuspendedTaskList ) == pdFALSE )
+ {
+ listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &xSuspendedTaskList );
+ vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
+
+ prvDeleteTCB( ( tskTCB * ) pxTCB );
+ }
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+#if ( configUSE_APPLICATION_TASK_TAG == 1 )
+
+ void vTaskSetApplicationTaskTag( xTaskHandle xTask, pdTASK_HOOK_CODE pxHookFunction )
+ {
+ tskTCB *xTCB;
+
+ /* If xTask is NULL then we are setting our own task hook. */
+ if( xTask == NULL )
+ {
+ xTCB = ( tskTCB * ) pxCurrentTCB;
+ }
+ else
+ {
+ xTCB = ( tskTCB * ) xTask;
+ }
+
+ /* Save the hook function in the TCB. A critical section is required as
+ the value can be accessed from an interrupt. */
+ taskENTER_CRITICAL();
+ xTCB->pxTaskTag = pxHookFunction;
+ taskEXIT_CRITICAL();
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+#if ( configUSE_APPLICATION_TASK_TAG == 1 )
+
+ pdTASK_HOOK_CODE xTaskGetApplicationTaskTag( xTaskHandle xTask )
+ {
+ tskTCB *xTCB;
+ pdTASK_HOOK_CODE xReturn;
+
+ /* If xTask is NULL then we are setting our own task hook. */
+ if( xTask == NULL )
+ {
+ xTCB = ( tskTCB * ) pxCurrentTCB;
+ }
+ else
+ {
+ xTCB = ( tskTCB * ) xTask;
+ }
+
+ /* Save the hook function in the TCB. A critical section is required as
+ the value can be accessed from an interrupt. */
+ taskENTER_CRITICAL();
+ xReturn = xTCB->pxTaskTag;
+ taskEXIT_CRITICAL();
+
+ return xReturn;
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+#if ( configUSE_APPLICATION_TASK_TAG == 1 )
+
+ portBASE_TYPE xTaskCallApplicationTaskHook( xTaskHandle xTask, void *pvParameter )
+ {
+ tskTCB *xTCB;
+ portBASE_TYPE xReturn;
+
+ /* If xTask is NULL then we are calling our own task hook. */
+ if( xTask == NULL )
+ {
+ xTCB = ( tskTCB * ) pxCurrentTCB;
+ }
+ else
+ {
+ xTCB = ( tskTCB * ) xTask;
+ }
+
+ if( xTCB->pxTaskTag != NULL )
+ {
+ xReturn = xTCB->pxTaskTag( pvParameter );
+ }
+ else
+ {
+ xReturn = pdFAIL;
+ }
+
+ return xReturn;
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+void vTaskSwitchContext( void )
+{
+ if( uxSchedulerSuspended != ( unsigned portBASE_TYPE ) pdFALSE )
+ {
+ /* The scheduler is currently suspended - do not allow a context
+ switch. */
+ xMissedYield = pdTRUE;
+ }
+ else
+ {
+ traceTASK_SWITCHED_OUT();
+
+ #if ( configGENERATE_RUN_TIME_STATS == 1 )
+ {
+ unsigned long ulTempCounter;
+
+ #ifdef portALT_GET_RUN_TIME_COUNTER_VALUE
+ portALT_GET_RUN_TIME_COUNTER_VALUE( ulTempCounter );
+ #else
+ ulTempCounter = portGET_RUN_TIME_COUNTER_VALUE();
+ #endif
+
+ /* Add the amount of time the task has been running to the accumulated
+ time so far. The time the task started running was stored in
+ ulTaskSwitchedInTime. Note that there is no overflow protection here
+ so count values are only valid until the timer overflows. Generally
+ this will be about 1 hour assuming a 1uS timer increment. */
+ pxCurrentTCB->ulRunTimeCounter += ( ulTempCounter - ulTaskSwitchedInTime );
+ ulTaskSwitchedInTime = ulTempCounter;
+ }
+ #endif
+
+ taskFIRST_CHECK_FOR_STACK_OVERFLOW();
+ taskSECOND_CHECK_FOR_STACK_OVERFLOW();
+
+ /* Find the highest priority queue that contains ready tasks. */
+ while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopReadyPriority ] ) ) )
+ {
+ configASSERT( uxTopReadyPriority );
+ --uxTopReadyPriority;
+ }
+
+ /* listGET_OWNER_OF_NEXT_ENTRY walks through the list, so the tasks of the
+ same priority get an equal share of the processor time. */
+ listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopReadyPriority ] ) );
+
+ traceTASK_SWITCHED_IN();
+ vWriteTraceToBuffer();
+ }
+}
+/*-----------------------------------------------------------*/
+
+void vTaskPlaceOnEventList( const xList * const pxEventList, portTickType xTicksToWait )
+{
+portTickType xTimeToWake;
+
+ configASSERT( pxEventList );
+
+ /* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE
+ SCHEDULER SUSPENDED. */
+
+ /* Place the event list item of the TCB in the appropriate event list.
+ This is placed in the list in priority order so the highest priority task
+ is the first to be woken by the event. */
+ vListInsert( ( xList * ) pxEventList, ( xListItem * ) &( pxCurrentTCB->xEventListItem ) );
+
+ /* We must remove ourselves from the ready list before adding ourselves
+ to the blocked list as the same list item is used for both lists. We have
+ exclusive access to the ready lists as the scheduler is locked. */
+ vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
+
+
+ #if ( INCLUDE_vTaskSuspend == 1 )
+ {
+ if( xTicksToWait == portMAX_DELAY )
+ {
+ /* Add ourselves to the suspended task list instead of a delayed task
+ list to ensure we are not woken by a timing event. We will block
+ indefinitely. */
+ vListInsertEnd( ( xList * ) &xSuspendedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
+ }
+ else
+ {
+ /* Calculate the time at which the task should be woken if the event does
+ not occur. This may overflow but this doesn't matter. */
+ xTimeToWake = xTickCount + xTicksToWait;
+ prvAddCurrentTaskToDelayedList( xTimeToWake );
+ }
+ }
+ #else
+ {
+ /* Calculate the time at which the task should be woken if the event does
+ not occur. This may overflow but this doesn't matter. */
+ xTimeToWake = xTickCount + xTicksToWait;
+ prvAddCurrentTaskToDelayedList( xTimeToWake );
+ }
+ #endif
+}
+/*-----------------------------------------------------------*/
+
+#if configUSE_TIMERS == 1
+
+ void vTaskPlaceOnEventListRestricted( const xList * const pxEventList, portTickType xTicksToWait )
+ {
+ portTickType xTimeToWake;
+
+ configASSERT( pxEventList );
+
+ /* This function should not be called by application code hence the
+ 'Restricted' in its name. It is not part of the public API. It is
+ designed for use by kernel code, and has special calling requirements -
+ it should be called from a critical section. */
+
+
+ /* Place the event list item of the TCB in the appropriate event list.
+ In this case it is assume that this is the only task that is going to
+ be waiting on this event list, so the faster vListInsertEnd() function
+ can be used in place of vListInsert. */
+ vListInsertEnd( ( xList * ) pxEventList, ( xListItem * ) &( pxCurrentTCB->xEventListItem ) );
+
+ /* We must remove this task from the ready list before adding it to the
+ blocked list as the same list item is used for both lists. This
+ function is called form a critical section. */
+ vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
+
+ /* Calculate the time at which the task should be woken if the event does
+ not occur. This may overflow but this doesn't matter. */
+ xTimeToWake = xTickCount + xTicksToWait;
+ prvAddCurrentTaskToDelayedList( xTimeToWake );
+ }
+
+#endif /* configUSE_TIMERS */
+/*-----------------------------------------------------------*/
+
+signed portBASE_TYPE xTaskRemoveFromEventList( const xList * const pxEventList )
+{
+tskTCB *pxUnblockedTCB;
+portBASE_TYPE xReturn;
+
+ /* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE
+ SCHEDULER SUSPENDED. It can also be called from within an ISR. */
+
+ /* The event list is sorted in priority order, so we can remove the
+ first in the list, remove the TCB from the delayed list, and add
+ it to the ready list.
+
+ If an event is for a queue that is locked then this function will never
+ get called - the lock count on the queue will get modified instead. This
+ means we can always expect exclusive access to the event list here.
+
+ This function assumes that a check has already been made to ensure that
+ pxEventList is not empty. */
+ pxUnblockedTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList );
+ configASSERT( pxUnblockedTCB );
+ vListRemove( &( pxUnblockedTCB->xEventListItem ) );
+
+ if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
+ {
+ vListRemove( &( pxUnblockedTCB->xGenericListItem ) );
+ prvAddTaskToReadyQueue( pxUnblockedTCB );
+ }
+ else
+ {
+ /* We cannot access the delayed or ready lists, so will hold this
+ task pending until the scheduler is resumed. */
+ vListInsertEnd( ( xList * ) &( xPendingReadyList ), &( pxUnblockedTCB->xEventListItem ) );
+ }
+
+ if( pxUnblockedTCB->uxPriority >= pxCurrentTCB->uxPriority )
+ {
+ /* Return true if the task removed from the event list has
+ a higher priority than the calling task. This allows
+ the calling task to know if it should force a context
+ switch now. */
+ xReturn = pdTRUE;
+ }
+ else
+ {
+ xReturn = pdFALSE;
+ }
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+void vTaskSetTimeOutState( xTimeOutType * const pxTimeOut )
+{
+ configASSERT( pxTimeOut );
+ pxTimeOut->xOverflowCount = xNumOfOverflows;
+ pxTimeOut->xTimeOnEntering = xTickCount;
+}
+/*-----------------------------------------------------------*/
+
+portBASE_TYPE xTaskCheckForTimeOut( xTimeOutType * const pxTimeOut, portTickType * const pxTicksToWait )
+{
+portBASE_TYPE xReturn;
+
+ configASSERT( pxTimeOut );
+ configASSERT( pxTicksToWait );
+
+ taskENTER_CRITICAL();
+ {
+ #if ( INCLUDE_vTaskSuspend == 1 )
+ /* If INCLUDE_vTaskSuspend is set to 1 and the block time specified is
+ the maximum block time then the task should block indefinitely, and
+ therefore never time out. */
+ if( *pxTicksToWait == portMAX_DELAY )
+ {
+ xReturn = pdFALSE;
+ }
+ else /* We are not blocking indefinitely, perform the checks below. */
+ #endif
+
+ if( ( xNumOfOverflows != pxTimeOut->xOverflowCount ) && ( ( portTickType ) xTickCount >= ( portTickType ) pxTimeOut->xTimeOnEntering ) )
+ {
+ /* The tick count is greater than the time at which vTaskSetTimeout()
+ was called, but has also overflowed since vTaskSetTimeOut() was called.
+ It must have wrapped all the way around and gone past us again. This
+ passed since vTaskSetTimeout() was called. */
+ xReturn = pdTRUE;
+ }
+ else if( ( ( portTickType ) ( ( portTickType ) xTickCount - ( portTickType ) pxTimeOut->xTimeOnEntering ) ) < ( portTickType ) *pxTicksToWait )
+ {
+ /* Not a genuine timeout. Adjust parameters for time remaining. */
+ *pxTicksToWait -= ( ( portTickType ) xTickCount - ( portTickType ) pxTimeOut->xTimeOnEntering );
+ vTaskSetTimeOutState( pxTimeOut );
+ xReturn = pdFALSE;
+ }
+ else
+ {
+ xReturn = pdTRUE;
+ }
+ }
+ taskEXIT_CRITICAL();
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+void vTaskMissedYield( void )
+{
+ xMissedYield = pdTRUE;
+}
+
+/*
+ * -----------------------------------------------------------
+ * The Idle task.
+ * ----------------------------------------------------------
+ *
+ * The portTASK_FUNCTION() macro is used to allow port/compiler specific
+ * language extensions. The equivalent prototype for this function is:
+ *
+ * void prvIdleTask( void *pvParameters );
+ *
+ */
+static portTASK_FUNCTION( prvIdleTask, pvParameters )
+{
+ /* Stop warnings. */
+ ( void ) pvParameters;
+
+ for( ;; )
+ {
+ /* See if any tasks have been deleted. */
+ prvCheckTasksWaitingTermination();
+
+ #if ( configUSE_PREEMPTION == 0 )
+ {
+ /* If we are not using preemption we keep forcing a task switch to
+ see if any other task has become available. If we are using
+ preemption we don't need to do this as any task becoming available
+ will automatically get the processor anyway. */
+ taskYIELD();
+ }
+ #endif
+
+ #if ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) )
+ {
+ /* When using preemption tasks of equal priority will be
+ timesliced. If a task that is sharing the idle priority is ready
+ to run then the idle task should yield before the end of the
+ timeslice.
+
+ A critical region is not required here as we are just reading from
+ the list, and an occasional incorrect value will not matter. If
+ the ready list at the idle priority contains more than one task
+ then a task other than the idle task is ready to execute. */
+ if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > ( unsigned portBASE_TYPE ) 1 )
+ {
+ taskYIELD();
+ }
+ }
+ #endif
+
+ #if ( configUSE_IDLE_HOOK == 1 )
+ {
+ extern void vApplicationIdleHook( void );
+
+ /* Call the user defined function from within the idle task. This
+ allows the application designer to add background functionality
+ without the overhead of a separate task.
+ NOTE: vApplicationIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES,
+ CALL A FUNCTION THAT MIGHT BLOCK. */
+ vApplicationIdleHook();
+ }
+ #endif
+ }
+} /*lint !e715 pvParameters is not accessed but all task functions require the same prototype. */
+
+
+
+
+
+
+
+/*-----------------------------------------------------------
+ * File private functions documented at the top of the file.
+ *----------------------------------------------------------*/
+
+
+
+static void prvInitialiseTCBVariables( tskTCB *pxTCB, const signed char * const pcName, unsigned portBASE_TYPE uxPriority, const xMemoryRegion * const xRegions, unsigned short usStackDepth )
+{
+ /* Store the function name in the TCB. */
+ #if configMAX_TASK_NAME_LEN > 1
+ {
+ /* Don't bring strncpy into the build unnecessarily. */
+ strncpy( ( char * ) pxTCB->pcTaskName, ( const char * ) pcName, ( unsigned short ) configMAX_TASK_NAME_LEN );
+ }
+ #endif
+ pxTCB->pcTaskName[ ( unsigned short ) configMAX_TASK_NAME_LEN - ( unsigned short ) 1 ] = ( signed char ) '\0';
+
+ /* This is used as an array index so must ensure it's not too large. First
+ remove the privilege bit if one is present. */
+ if( uxPriority >= configMAX_PRIORITIES )
+ {
+ uxPriority = configMAX_PRIORITIES - ( unsigned portBASE_TYPE ) 1U;
+ }
+
+ pxTCB->uxPriority = uxPriority;
+ #if ( configUSE_MUTEXES == 1 )
+ {
+ pxTCB->uxBasePriority = uxPriority;
+ }
+ #endif
+
+ vListInitialiseItem( &( pxTCB->xGenericListItem ) );
+ vListInitialiseItem( &( pxTCB->xEventListItem ) );
+
+ /* Set the pxTCB as a link back from the xListItem. This is so we can get
+ back to the containing TCB from a generic item in a list. */
+ listSET_LIST_ITEM_OWNER( &( pxTCB->xGenericListItem ), pxTCB );
+
+ /* Event lists are always in priority order. */
+ listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) uxPriority );
+ listSET_LIST_ITEM_OWNER( &( pxTCB->xEventListItem ), pxTCB );
+
+ #if ( portCRITICAL_NESTING_IN_TCB == 1 )
+ {
+ pxTCB->uxCriticalNesting = ( unsigned portBASE_TYPE ) 0;
+ }
+ #endif
+
+ #if ( configUSE_APPLICATION_TASK_TAG == 1 )
+ {
+ pxTCB->pxTaskTag = NULL;
+ }
+ #endif
+
+ #if ( configGENERATE_RUN_TIME_STATS == 1 )
+ {
+ pxTCB->ulRunTimeCounter = 0UL;
+ }
+ #endif
+
+ #if ( portUSING_MPU_WRAPPERS == 1 )
+ {
+ vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, pxTCB->pxStack, usStackDepth );
+ }
+ #else
+ {
+ ( void ) xRegions;
+ ( void ) usStackDepth;
+ }
+ #endif
+}
+/*-----------------------------------------------------------*/
+
+#if ( portUSING_MPU_WRAPPERS == 1 )
+
+ void vTaskAllocateMPURegions( xTaskHandle xTaskToModify, const xMemoryRegion * const xRegions )
+ {
+ tskTCB *pxTCB;
+
+ if( xTaskToModify == pxCurrentTCB )
+ {
+ xTaskToModify = NULL;
+ }
+
+ /* If null is passed in here then we are deleting ourselves. */
+ pxTCB = prvGetTCBFromHandle( xTaskToModify );
+
+ vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, NULL, 0 );
+ }
+ /*-----------------------------------------------------------*/
+#endif
+
+static void prvInitialiseTaskLists( void )
+{
+unsigned portBASE_TYPE uxPriority;
+
+ for( uxPriority = ( unsigned portBASE_TYPE ) 0U; uxPriority < configMAX_PRIORITIES; uxPriority++ )
+ {
+ vListInitialise( ( xList * ) &( pxReadyTasksLists[ uxPriority ] ) );
+ }
+
+ vListInitialise( ( xList * ) &xDelayedTaskList1 );
+ vListInitialise( ( xList * ) &xDelayedTaskList2 );
+ vListInitialise( ( xList * ) &xPendingReadyList );
+
+ #if ( INCLUDE_vTaskDelete == 1 )
+ {
+ vListInitialise( ( xList * ) &xTasksWaitingTermination );
+ }
+ #endif
+
+ #if ( INCLUDE_vTaskSuspend == 1 )
+ {
+ vListInitialise( ( xList * ) &xSuspendedTaskList );
+ }
+ #endif
+
+ /* Start with pxDelayedTaskList using list1 and the pxOverflowDelayedTaskList
+ using list2. */
+ pxDelayedTaskList = &xDelayedTaskList1;
+ pxOverflowDelayedTaskList = &xDelayedTaskList2;
+}
+/*-----------------------------------------------------------*/
+
+static void prvCheckTasksWaitingTermination( void )
+{
+ #if ( INCLUDE_vTaskDelete == 1 )
+ {
+ portBASE_TYPE xListIsEmpty;
+
+ /* ucTasksDeleted is used to prevent vTaskSuspendAll() being called
+ too often in the idle task. */
+ if( uxTasksDeleted > ( unsigned portBASE_TYPE ) 0 )
+ {
+ vTaskSuspendAll();
+ xListIsEmpty = listLIST_IS_EMPTY( &xTasksWaitingTermination );
+ xTaskResumeAll();
+
+ if( xListIsEmpty == pdFALSE )
+ {
+ tskTCB *pxTCB;
+
+ taskENTER_CRITICAL();
+ {
+ pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( ( ( xList * ) &xTasksWaitingTermination ) );
+ vListRemove( &( pxTCB->xGenericListItem ) );
+ --uxCurrentNumberOfTasks;
+ --uxTasksDeleted;
+ }
+ taskEXIT_CRITICAL();
+
+ prvDeleteTCB( pxTCB );
+ }
+ }
+ }
+ #endif
+}
+/*-----------------------------------------------------------*/
+
+static void prvAddCurrentTaskToDelayedList( portTickType xTimeToWake )
+{
+ /* The list item will be inserted in wake time order. */
+ listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );
+
+ if( xTimeToWake < xTickCount )
+ {
+ /* Wake time has overflowed. Place this item in the overflow list. */
+ vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
+ }
+ else
+ {
+ /* The wake time has not overflowed, so we can use the current block list. */
+ vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
+
+ /* If the task entering the blocked state was placed at the head of the
+ list of blocked tasks then xNextTaskUnblockTime needs to be updated
+ too. */
+ if( xTimeToWake < xNextTaskUnblockTime )
+ {
+ xNextTaskUnblockTime = xTimeToWake;
+ }
+ }
+}
+/*-----------------------------------------------------------*/
+
+static tskTCB *prvAllocateTCBAndStack( unsigned short usStackDepth, portSTACK_TYPE *puxStackBuffer )
+{
+tskTCB *pxNewTCB;
+
+ /* Allocate space for the TCB. Where the memory comes from depends on
+ the implementation of the port malloc function. */
+ pxNewTCB = ( tskTCB * ) pvPortMalloc( sizeof( tskTCB ) );
+
+ if( pxNewTCB != NULL )
+ {
+ /* Allocate space for the stack used by the task being created.
+ The base of the stack memory stored in the TCB so the task can
+ be deleted later if required. */
+ pxNewTCB->pxStack = ( portSTACK_TYPE * ) pvPortMallocAligned( ( ( ( size_t )usStackDepth ) * sizeof( portSTACK_TYPE ) ), puxStackBuffer );
+
+ if( pxNewTCB->pxStack == NULL )
+ {
+ /* Could not allocate the stack. Delete the allocated TCB. */
+ vPortFree( pxNewTCB );
+ pxNewTCB = NULL;
+ }
+ else
+ {
+ /* Just to help debugging. */
+ memset( pxNewTCB->pxStack, tskSTACK_FILL_BYTE, usStackDepth * sizeof( portSTACK_TYPE ) );
+ }
+ }
+
+ return pxNewTCB;
+}
+/*-----------------------------------------------------------*/
+
+#if ( configUSE_TRACE_FACILITY == 1 )
+
+ static void prvListTaskWithinSingleList( const signed char *pcWriteBuffer, xList *pxList, signed char cStatus )
+ {
+ volatile tskTCB *pxNextTCB, *pxFirstTCB;
+ unsigned short usStackRemaining;
+
+ /* Write the details of all the TCB's in pxList into the buffer. */
+ listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList );
+ do
+ {
+ listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList );
+ #if ( portSTACK_GROWTH > 0 )
+ {
+ usStackRemaining = usTaskCheckFreeStackSpace( ( unsigned char * ) pxNextTCB->pxEndOfStack );
+ }
+ #else
+ {
+ usStackRemaining = usTaskCheckFreeStackSpace( ( unsigned char * ) pxNextTCB->pxStack );
+ }
+ #endif
+
+ sprintf( pcStatusString, ( char * ) "%s\t\t%c\t%u\t%u\t%u\r\n", pxNextTCB->pcTaskName, cStatus, ( unsigned int ) pxNextTCB->uxPriority, usStackRemaining, ( unsigned int ) pxNextTCB->uxTCBNumber );
+ strcat( ( char * ) pcWriteBuffer, ( char * ) pcStatusString );
+
+ } while( pxNextTCB != pxFirstTCB );
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+#if ( configGENERATE_RUN_TIME_STATS == 1 )
+
+ static void prvGenerateRunTimeStatsForTasksInList( const signed char *pcWriteBuffer, xList *pxList, unsigned long ulTotalRunTime )
+ {
+ volatile tskTCB *pxNextTCB, *pxFirstTCB;
+ unsigned long ulStatsAsPercentage;
+
+ /* Write the run time stats of all the TCB's in pxList into the buffer. */
+ listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList );
+ do
+ {
+ /* Get next TCB in from the list. */
+ listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList );
+
+ /* Divide by zero check. */
+ if( ulTotalRunTime > 0UL )
+ {
+ /* Has the task run at all? */
+ if( pxNextTCB->ulRunTimeCounter == 0 )
+ {
+ /* The task has used no CPU time at all. */
+ sprintf( pcStatsString, ( char * ) "%s\t\t0\t\t0%%\r\n", pxNextTCB->pcTaskName );
+ }
+ else
+ {
+ /* What percentage of the total run time has the task used?
+ This will always be rounded down to the nearest integer.
+ ulTotalRunTime has already been divided by 100. */
+ ulStatsAsPercentage = pxNextTCB->ulRunTimeCounter / ulTotalRunTime;
+
+ if( ulStatsAsPercentage > 0UL )
+ {
+ #ifdef portLU_PRINTF_SPECIFIER_REQUIRED
+ {
+ sprintf( pcStatsString, ( char * ) "%s\t\t%lu\t\t%lu%%\r\n", pxNextTCB->pcTaskName, pxNextTCB->ulRunTimeCounter, ulStatsAsPercentage );
+ }
+ #else
+ {
+ /* sizeof( int ) == sizeof( long ) so a smaller
+ printf() library can be used. */
+ sprintf( pcStatsString, ( char * ) "%s\t\t%u\t\t%u%%\r\n", pxNextTCB->pcTaskName, ( unsigned int ) pxNextTCB->ulRunTimeCounter, ( unsigned int ) ulStatsAsPercentage );
+ }
+ #endif
+ }
+ else
+ {
+ /* If the percentage is zero here then the task has
+ consumed less than 1% of the total run time. */
+ #ifdef portLU_PRINTF_SPECIFIER_REQUIRED
+ {
+ sprintf( pcStatsString, ( char * ) "%s\t\t%lu\t\t<1%%\r\n", pxNextTCB->pcTaskName, pxNextTCB->ulRunTimeCounter );
+ }
+ #else
+ {
+ /* sizeof( int ) == sizeof( long ) so a smaller
+ printf() library can be used. */
+ sprintf( pcStatsString, ( char * ) "%s\t\t%u\t\t<1%%\r\n", pxNextTCB->pcTaskName, ( unsigned int ) pxNextTCB->ulRunTimeCounter );
+ }
+ #endif
+ }
+ }
+
+ strcat( ( char * ) pcWriteBuffer, ( char * ) pcStatsString );
+ }
+
+ } while( pxNextTCB != pxFirstTCB );
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+#if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )
+
+ static unsigned short usTaskCheckFreeStackSpace( const unsigned char * pucStackByte )
+ {
+ register unsigned short usCount = 0;
+
+ while( *pucStackByte == tskSTACK_FILL_BYTE )
+ {
+ pucStackByte -= portSTACK_GROWTH;
+ usCount++;
+ }
+
+ usCount /= sizeof( portSTACK_TYPE );
+
+ return usCount;
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+#if ( INCLUDE_uxTaskGetStackHighWaterMark == 1 )
+
+ unsigned portBASE_TYPE uxTaskGetStackHighWaterMark( xTaskHandle xTask )
+ {
+ tskTCB *pxTCB;
+ unsigned char *pcEndOfStack;
+ unsigned portBASE_TYPE uxReturn;
+
+ pxTCB = prvGetTCBFromHandle( xTask );
+
+ #if portSTACK_GROWTH < 0
+ {
+ pcEndOfStack = ( unsigned char * ) pxTCB->pxStack;
+ }
+ #else
+ {
+ pcEndOfStack = ( unsigned char * ) pxTCB->pxEndOfStack;
+ }
+ #endif
+
+ uxReturn = ( unsigned portBASE_TYPE ) usTaskCheckFreeStackSpace( pcEndOfStack );
+
+ return uxReturn;
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+#if ( ( INCLUDE_vTaskDelete == 1 ) || ( INCLUDE_vTaskCleanUpResources == 1 ) )
+
+ static void prvDeleteTCB( tskTCB *pxTCB )
+ {
+ /* Free up the memory allocated by the scheduler for the task. It is up to
+ the task to free any memory allocated at the application level. */
+ vPortFreeAligned( pxTCB->pxStack );
+ vPortFree( pxTCB );
+ }
+
+#endif
+
+
+/*-----------------------------------------------------------*/
+
+#if ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) )
+
+ xTaskHandle xTaskGetCurrentTaskHandle( void )
+ {
+ xTaskHandle xReturn;
+
+ /* A critical section is not required as this is not called from
+ an interrupt and the current TCB will always be the same for any
+ individual execution thread. */
+ xReturn = pxCurrentTCB;
+
+ return xReturn;
+ }
+
+#endif
+
+/*-----------------------------------------------------------*/
+
+#if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )
+
+ portBASE_TYPE xTaskGetSchedulerState( void )
+ {
+ portBASE_TYPE xReturn;
+
+ if( xSchedulerRunning == pdFALSE )
+ {
+ xReturn = taskSCHEDULER_NOT_STARTED;
+ }
+ else
+ {
+ if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
+ {
+ xReturn = taskSCHEDULER_RUNNING;
+ }
+ else
+ {
+ xReturn = taskSCHEDULER_SUSPENDED;
+ }
+ }
+
+ return xReturn;
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+#if ( configUSE_MUTEXES == 1 )
+
+ void vTaskPriorityInherit( xTaskHandle * const pxMutexHolder )
+ {
+ tskTCB * const pxTCB = ( tskTCB * ) pxMutexHolder;
+
+ configASSERT( pxMutexHolder );
+
+ if( pxTCB->uxPriority < pxCurrentTCB->uxPriority )
+ {
+ /* Adjust the mutex holder state to account for its new priority. */
+ listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) pxCurrentTCB->uxPriority );
+
+ /* If the task being modified is in the ready state it will need to
+ be moved in to a new list. */
+ if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xGenericListItem ) ) )
+ {
+ vListRemove( &( pxTCB->xGenericListItem ) );
+
+ /* Inherit the priority before being moved into the new list. */
+ pxTCB->uxPriority = pxCurrentTCB->uxPriority;
+ prvAddTaskToReadyQueue( pxTCB );
+ }
+ else
+ {
+ /* Just inherit the priority. */
+ pxTCB->uxPriority = pxCurrentTCB->uxPriority;
+ }
+ }
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+#if ( configUSE_MUTEXES == 1 )
+
+ void vTaskPriorityDisinherit( xTaskHandle * const pxMutexHolder )
+ {
+ tskTCB * const pxTCB = ( tskTCB * ) pxMutexHolder;
+
+ if( pxMutexHolder != NULL )
+ {
+ if( pxTCB->uxPriority != pxTCB->uxBasePriority )
+ {
+ /* We must be the running task to be able to give the mutex back.
+ Remove ourselves from the ready list we currently appear in. */
+ vListRemove( &( pxTCB->xGenericListItem ) );
+
+ /* Disinherit the priority before adding ourselves into the new
+ ready list. */
+ pxTCB->uxPriority = pxTCB->uxBasePriority;
+ listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) pxTCB->uxPriority );
+ prvAddTaskToReadyQueue( pxTCB );
+ }
+ }
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+#if ( portCRITICAL_NESTING_IN_TCB == 1 )
+
+ void vTaskEnterCritical( void )
+ {
+ portDISABLE_INTERRUPTS();
+
+ if( xSchedulerRunning != pdFALSE )
+ {
+ ( pxCurrentTCB->uxCriticalNesting )++;
+ }
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+#if ( portCRITICAL_NESTING_IN_TCB == 1 )
+
+void vTaskExitCritical( void )
+{
+ if( xSchedulerRunning != pdFALSE )
+ {
+ if( pxCurrentTCB->uxCriticalNesting > 0 )
+ {
+ ( pxCurrentTCB->uxCriticalNesting )--;
+
+ if( pxCurrentTCB->uxCriticalNesting == 0 )
+ {
+ portENABLE_INTERRUPTS();
+ }
+ }
+ }
+}
+
+#endif
+/*-----------------------------------------------------------*/
+
+
+
+
diff --git a/Libmaple/libmaple/libraries/FreeRTOS/utility/timers.c b/Libmaple/libmaple/libraries/FreeRTOS/utility/timers.c
index 7e5ef22a..1dd7555a 100644
--- a/Libmaple/libmaple/libraries/FreeRTOS/utility/timers.c
+++ b/Libmaple/libmaple/libraries/FreeRTOS/utility/timers.c
@@ -1,649 +1,649 @@
-/*
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.
-
-
- FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:
- Atollic AB - Atollic provides professional embedded systems development
- tools for C/C++ development, code analysis and test automation.
- See http://www.atollic.com
-
-
- ***************************************************************************
- * *
- * FreeRTOS tutorial books are available in pdf and paperback. *
- * Complete, revised, and edited pdf reference manuals are also *
- * available. *
- * *
- * Purchasing FreeRTOS documentation will not only help you, by *
- * ensuring you get running as quickly as possible and with an *
- * in-depth knowledge of how to use FreeRTOS, it will also help *
- * the FreeRTOS project to continue with its mission of providing *
- * professional grade, cross platform, de facto standard solutions *
- * for microcontrollers - completely free of charge! *
- * *
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
- * *
- * Thank you for using FreeRTOS, and thank you for your support! *
- * *
- ***************************************************************************
-
-
- This file is part of the FreeRTOS distribution.
-
- FreeRTOS is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License (version 2) as published by the
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
- >>>NOTE<<< The modification to the GPL is included to allow you to
- distribute a combined work that includes FreeRTOS without being obliged to
- provide the source code for proprietary components outside of the FreeRTOS
- kernel. FreeRTOS is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- more details. You should have received a copy of the GNU General Public
- License and the FreeRTOS license exception along with FreeRTOS; if not it
- can be viewed here: http://www.freertos.org/a00114.html and also obtained
- by writing to Richard Barry, contact details for whom are available on the
- FreeRTOS WEB site.
-
- 1 tab == 4 spaces!
-
- http://www.FreeRTOS.org - Documentation, latest information, license and
- contact details.
-
- http://www.SafeRTOS.com - A version that is certified for use in safety
- critical systems.
-
- http://www.OpenRTOS.com - Commercial support, development, porting,
- licensing and training services.
-*/
-
-/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
-all the API functions to use the MPU wrappers. That should only be done when
-task.h is included from an application file. */
-#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
-
-#include "FreeRTOS.h"
-#include "task.h"
-#include "queue.h"
-#include "timers.h"
-
-#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
-
-/* This entire source file will be skipped if the application is not configured
-to include software timer functionality. This #if is closed at the very bottom
-of this file. If you want to include software timer functionality then ensure
-configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */
-#if ( configUSE_TIMERS == 1 )
-
-/* Misc definitions. */
-#define tmrNO_DELAY ( portTickType ) 0U
-
-/* The definition of the timers themselves. */
-typedef struct tmrTimerControl
-{
- const signed char *pcTimerName; /*<< Text name. This is not used by the kernel, it is included simply to make debugging easier. */
- xListItem xTimerListItem; /*<< Standard linked list item as used by all kernel features for event management. */
- portTickType xTimerPeriodInTicks;/*<< How quickly and often the timer expires. */
- unsigned portBASE_TYPE uxAutoReload; /*<< Set to pdTRUE if the timer should be automatically restarted once expired. Set to pdFALSE if the timer is, in effect, a one shot timer. */
- void *pvTimerID; /*<< An ID to identify the timer. This allows the timer to be identified when the same callback is used for multiple timers. */
- tmrTIMER_CALLBACK pxCallbackFunction; /*<< The function that will be called when the timer expires. */
-} xTIMER;
-
-/* The definition of messages that can be sent and received on the timer
-queue. */
-typedef struct tmrTimerQueueMessage
-{
- portBASE_TYPE xMessageID; /*<< The command being sent to the timer service task. */
- portTickType xMessageValue; /*<< An optional value used by a subset of commands, for example, when changing the period of a timer. */
- xTIMER * pxTimer; /*<< The timer to which the command will be applied. */
-} xTIMER_MESSAGE;
-
-
-/* The list in which active timers are stored. Timers are referenced in expire
-time order, with the nearest expiry time at the front of the list. Only the
-timer service task is allowed to access xActiveTimerList. */
-PRIVILEGED_DATA static xList xActiveTimerList1;
-PRIVILEGED_DATA static xList xActiveTimerList2;
-PRIVILEGED_DATA static xList *pxCurrentTimerList;
-PRIVILEGED_DATA static xList *pxOverflowTimerList;
-
-/* A queue that is used to send commands to the timer service task. */
-PRIVILEGED_DATA static xQueueHandle xTimerQueue = NULL;
-
-/*-----------------------------------------------------------*/
-
-/*
- * Initialise the infrastructure used by the timer service task if it has not
- * been initialised already.
- */
-static void prvCheckForValidListAndQueue( void ) PRIVILEGED_FUNCTION;
-
-/*
- * The timer service task (daemon). Timer functionality is controlled by this
- * task. Other tasks communicate with the timer service task using the
- * xTimerQueue queue.
- */
-static void prvTimerTask( void *pvParameters ) PRIVILEGED_FUNCTION;
-
-/*
- * Called by the timer service task to interpret and process a command it
- * received on the timer queue.
- */
-static void prvProcessReceivedCommands( void ) PRIVILEGED_FUNCTION;
-
-/*
- * Insert the timer into either xActiveTimerList1, or xActiveTimerList2,
- * depending on if the expire time causes a timer counter overflow.
- */
-static portBASE_TYPE prvInsertTimerInActiveList( xTIMER *pxTimer, portTickType xNextExpiryTime, portTickType xTimeNow, portTickType xCommandTime ) PRIVILEGED_FUNCTION;
-
-/*
- * An active timer has reached its expire time. Reload the timer if it is an
- * auto reload timer, then call its callback.
- */
-static void prvProcessExpiredTimer( portTickType xNextExpireTime, portTickType xTimeNow ) PRIVILEGED_FUNCTION;
-
-/*
- * The tick count has overflowed. Switch the timer lists after ensuring the
- * current timer list does not still reference some timers.
- */
-static void prvSwitchTimerLists( portTickType xLastTime ) PRIVILEGED_FUNCTION;
-
-/*
- * Obtain the current tick count, setting *pxTimerListsWereSwitched to pdTRUE
- * if a tick count overflow occurred since prvSampleTimeNow() was last called.
- */
-static portTickType prvSampleTimeNow( portBASE_TYPE *pxTimerListsWereSwitched ) PRIVILEGED_FUNCTION;
-
-/*
- * If the timer list contains any active timers then return the expire time of
- * the timer that will expire first and set *pxListWasEmpty to false. If the
- * timer list does not contain any timers then return 0 and set *pxListWasEmpty
- * to pdTRUE.
- */
-static portTickType prvGetNextExpireTime( portBASE_TYPE *pxListWasEmpty ) PRIVILEGED_FUNCTION;
-
-/*
- * If a timer has expired, process it. Otherwise, block the timer service task
- * until either a timer does expire or a command is received.
- */
-static void prvProcessTimerOrBlockTask( portTickType xNextExpireTime, portBASE_TYPE xListWasEmpty ) PRIVILEGED_FUNCTION;
-
-/*-----------------------------------------------------------*/
-
-portBASE_TYPE xTimerCreateTimerTask( void )
-{
-portBASE_TYPE xReturn = pdFAIL;
-
- /* This function is called when the scheduler is started if
- configUSE_TIMERS is set to 1. Check that the infrastructure used by the
- timer service task has been created/initialised. If timers have already
- been created then the initialisation will already have been performed. */
- prvCheckForValidListAndQueue();
-
- if( xTimerQueue != NULL )
- {
- xReturn = xTaskCreate( prvTimerTask, ( const signed char * ) "Tmr Svc", ( unsigned short ) configTIMER_TASK_STACK_DEPTH, NULL, ( unsigned portBASE_TYPE ) configTIMER_TASK_PRIORITY, NULL);
- }
-
- configASSERT( xReturn );
- return xReturn;
-}
-/*-----------------------------------------------------------*/
-
-xTimerHandle xTimerCreate( const signed char *pcTimerName, portTickType xTimerPeriodInTicks, unsigned portBASE_TYPE uxAutoReload, void *pvTimerID, tmrTIMER_CALLBACK pxCallbackFunction )
-{
-xTIMER *pxNewTimer;
-
- /* Allocate the timer structure. */
- if( xTimerPeriodInTicks == ( portTickType ) 0U )
- {
- pxNewTimer = NULL;
- configASSERT( ( xTimerPeriodInTicks > 0 ) );
- }
- else
- {
- pxNewTimer = ( xTIMER * ) pvPortMalloc( sizeof( xTIMER ) );
- if( pxNewTimer != NULL )
- {
- /* Ensure the infrastructure used by the timer service task has been
- created/initialised. */
- prvCheckForValidListAndQueue();
-
- /* Initialise the timer structure members using the function parameters. */
- pxNewTimer->pcTimerName = pcTimerName;
- pxNewTimer->xTimerPeriodInTicks = xTimerPeriodInTicks;
- pxNewTimer->uxAutoReload = uxAutoReload;
- pxNewTimer->pvTimerID = pvTimerID;
- pxNewTimer->pxCallbackFunction = pxCallbackFunction;
- vListInitialiseItem( &( pxNewTimer->xTimerListItem ) );
-
- traceTIMER_CREATE( pxNewTimer );
- }
- else
- {
- traceTIMER_CREATE_FAILED();
- }
- }
-
- return ( xTimerHandle ) pxNewTimer;
-}
-/*-----------------------------------------------------------*/
-
-portBASE_TYPE xTimerGenericCommand( xTimerHandle xTimer, portBASE_TYPE xCommandID, portTickType xOptionalValue, portBASE_TYPE *pxHigherPriorityTaskWoken, portTickType xBlockTime )
-{
-portBASE_TYPE xReturn = pdFAIL;
-xTIMER_MESSAGE xMessage;
-
- /* Send a message to the timer service task to perform a particular action
- on a particular timer definition. */
- if( xTimerQueue != NULL )
- {
- /* Send a command to the timer service task to start the xTimer timer. */
- xMessage.xMessageID = xCommandID;
- xMessage.xMessageValue = xOptionalValue;
- xMessage.pxTimer = ( xTIMER * ) xTimer;
-
- if( pxHigherPriorityTaskWoken == NULL )
- {
- if( xTaskGetSchedulerState() == taskSCHEDULER_RUNNING )
- {
- xReturn = xQueueSendToBack( xTimerQueue, &xMessage, xBlockTime );
- }
- else
- {
- xReturn = xQueueSendToBack( xTimerQueue, &xMessage, tmrNO_DELAY );
- }
- }
- else
- {
- xReturn = xQueueSendToBackFromISR( xTimerQueue, &xMessage, pxHigherPriorityTaskWoken );
- }
-
- traceTIMER_COMMAND_SEND( xTimer, xCommandID, xOptionalValue, xReturn );
- }
-
- return xReturn;
-}
-/*-----------------------------------------------------------*/
-
-static void prvProcessExpiredTimer( portTickType xNextExpireTime, portTickType xTimeNow )
-{
-xTIMER *pxTimer;
-portBASE_TYPE xResult;
-
- /* Remove the timer from the list of active timers. A check has already
- been performed to ensure the list is not empty. */
- pxTimer = ( xTIMER * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTimerList );
- vListRemove( &( pxTimer->xTimerListItem ) );
- traceTIMER_EXPIRED( pxTimer );
-
- /* If the timer is an auto reload timer then calculate the next
- expiry time and re-insert the timer in the list of active timers. */
- if( pxTimer->uxAutoReload == ( unsigned portBASE_TYPE ) pdTRUE )
- {
- /* This is the only time a timer is inserted into a list using
- a time relative to anything other than the current time. It
- will therefore be inserted into the correct list relative to
- the time this task thinks it is now, even if a command to
- switch lists due to a tick count overflow is already waiting in
- the timer queue. */
- if( prvInsertTimerInActiveList( pxTimer, ( xNextExpireTime + pxTimer->xTimerPeriodInTicks ), xTimeNow, xNextExpireTime ) == pdTRUE )
- {
- /* The timer expired before it was added to the active timer
- list. Reload it now. */
- xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START, xNextExpireTime, NULL, tmrNO_DELAY );
- configASSERT( xResult );
- ( void ) xResult;
- }
- }
-
- /* Call the timer callback. */
- pxTimer->pxCallbackFunction( ( xTimerHandle ) pxTimer );
-}
-/*-----------------------------------------------------------*/
-
-static void prvTimerTask( void *pvParameters )
-{
-portTickType xNextExpireTime;
-portBASE_TYPE xListWasEmpty;
-
- /* Just to avoid compiler warnings. */
- ( void ) pvParameters;
-
- for( ;; )
- {
- /* Query the timers list to see if it contains any timers, and if so,
- obtain the time at which the next timer will expire. */
- xNextExpireTime = prvGetNextExpireTime( &xListWasEmpty );
-
- /* If a timer has expired, process it. Otherwise, block this task
- until either a timer does expire, or a command is received. */
- prvProcessTimerOrBlockTask( xNextExpireTime, xListWasEmpty );
-
- /* Empty the command queue. */
- prvProcessReceivedCommands();
- }
-}
-/*-----------------------------------------------------------*/
-
-static void prvProcessTimerOrBlockTask( portTickType xNextExpireTime, portBASE_TYPE xListWasEmpty )
-{
-portTickType xTimeNow;
-portBASE_TYPE xTimerListsWereSwitched;
-
- vTaskSuspendAll();
- {
- /* Obtain the time now to make an assessment as to whether the timer
- has expired or not. If obtaining the time causes the lists to switch
- then don't process this timer as any timers that remained in the list
- when the lists were switched will have been processed within the
- prvSampelTimeNow() function. */
- xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched );
- if( xTimerListsWereSwitched == pdFALSE )
- {
- /* The tick count has not overflowed, has the timer expired? */
- if( ( xListWasEmpty == pdFALSE ) && ( xNextExpireTime <= xTimeNow ) )
- {
- xTaskResumeAll();
- prvProcessExpiredTimer( xNextExpireTime, xTimeNow );
- }
- else
- {
- /* The tick count has not overflowed, and the next expire
- time has not been reached yet. This task should therefore
- block to wait for the next expire time or a command to be
- received - whichever comes first. The following line cannot
- be reached unless xNextExpireTime > xTimeNow, except in the
- case when the current timer list is empty. */
- vQueueWaitForMessageRestricted( xTimerQueue, ( xNextExpireTime - xTimeNow ) );
-
- if( xTaskResumeAll() == pdFALSE )
- {
- /* Yield to wait for either a command to arrive, or the block time
- to expire. If a command arrived between the critical section being
- exited and this yield then the yield will not cause the task
- to block. */
- portYIELD_WITHIN_API();
- }
- }
- }
- else
- {
- xTaskResumeAll();
- }
- }
-}
-/*-----------------------------------------------------------*/
-
-static portTickType prvGetNextExpireTime( portBASE_TYPE *pxListWasEmpty )
-{
-portTickType xNextExpireTime;
-
- /* Timers are listed in expiry time order, with the head of the list
- referencing the task that will expire first. Obtain the time at which
- the timer with the nearest expiry time will expire. If there are no
- active timers then just set the next expire time to 0. That will cause
- this task to unblock when the tick count overflows, at which point the
- timer lists will be switched and the next expiry time can be
- re-assessed. */
- *pxListWasEmpty = listLIST_IS_EMPTY( pxCurrentTimerList );
- if( *pxListWasEmpty == pdFALSE )
- {
- xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList );
- }
- else
- {
- /* Ensure the task unblocks when the tick count rolls over. */
- xNextExpireTime = ( portTickType ) 0U;
- }
-
- return xNextExpireTime;
-}
-/*-----------------------------------------------------------*/
-
-static portTickType prvSampleTimeNow( portBASE_TYPE *pxTimerListsWereSwitched )
-{
-portTickType xTimeNow;
-static portTickType xLastTime = ( portTickType ) 0U;
-
- xTimeNow = xTaskGetTickCount();
-
- if( xTimeNow < xLastTime )
- {
- prvSwitchTimerLists( xLastTime );
- *pxTimerListsWereSwitched = pdTRUE;
- }
- else
- {
- *pxTimerListsWereSwitched = pdFALSE;
- }
-
- xLastTime = xTimeNow;
-
- return xTimeNow;
-}
-/*-----------------------------------------------------------*/
-
-static portBASE_TYPE prvInsertTimerInActiveList( xTIMER *pxTimer, portTickType xNextExpiryTime, portTickType xTimeNow, portTickType xCommandTime )
-{
-portBASE_TYPE xProcessTimerNow = pdFALSE;
-
- listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xNextExpiryTime );
- listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer );
-
- if( xNextExpiryTime <= xTimeNow )
- {
- /* Has the expiry time elapsed between the command to start/reset a
- timer was issued, and the time the command was processed? */
- if( ( ( portTickType ) ( xTimeNow - xCommandTime ) ) >= pxTimer->xTimerPeriodInTicks )
- {
- /* The time between a command being issued and the command being
- processed actually exceeds the timers period. */
- xProcessTimerNow = pdTRUE;
- }
- else
- {
- vListInsert( pxOverflowTimerList, &( pxTimer->xTimerListItem ) );
- }
- }
- else
- {
- if( ( xTimeNow < xCommandTime ) && ( xNextExpiryTime >= xCommandTime ) )
- {
- /* If, since the command was issued, the tick count has overflowed
- but the expiry time has not, then the timer must have already passed
- its expiry time and should be processed immediately. */
- xProcessTimerNow = pdTRUE;
- }
- else
- {
- vListInsert( pxCurrentTimerList, &( pxTimer->xTimerListItem ) );
- }
- }
-
- return xProcessTimerNow;
-}
-/*-----------------------------------------------------------*/
-
-static void prvProcessReceivedCommands( void )
-{
-xTIMER_MESSAGE xMessage;
-xTIMER *pxTimer;
-portBASE_TYPE xTimerListsWereSwitched, xResult;
-portTickType xTimeNow;
-
- /* In this case the xTimerListsWereSwitched parameter is not used, but it
- must be present in the function call. */
- xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched );
-
- while( xQueueReceive( xTimerQueue, &xMessage, tmrNO_DELAY ) != pdFAIL )
- {
- pxTimer = xMessage.pxTimer;
-
- /* Is the timer already in a list of active timers? When the command
- is trmCOMMAND_PROCESS_TIMER_OVERFLOW, the timer will be NULL as the
- command is to the task rather than to an individual timer. */
- if( pxTimer != NULL )
- {
- if( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) == pdFALSE )
- {
- /* The timer is in a list, remove it. */
- vListRemove( &( pxTimer->xTimerListItem ) );
- }
- }
-
- traceTIMER_COMMAND_RECEIVED( pxTimer, xMessage.xMessageID, xMessage.xMessageValue );
-
- switch( xMessage.xMessageID )
- {
- case tmrCOMMAND_START :
- /* Start or restart a timer. */
- if( prvInsertTimerInActiveList( pxTimer, xMessage.xMessageValue + pxTimer->xTimerPeriodInTicks, xTimeNow, xMessage.xMessageValue ) == pdTRUE )
- {
- /* The timer expired before it was added to the active timer
- list. Process it now. */
- pxTimer->pxCallbackFunction( ( xTimerHandle ) pxTimer );
-
- if( pxTimer->uxAutoReload == ( unsigned portBASE_TYPE ) pdTRUE )
- {
- xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START, xMessage.xMessageValue + pxTimer->xTimerPeriodInTicks, NULL, tmrNO_DELAY );
- configASSERT( xResult );
- ( void ) xResult;
- }
- }
- break;
-
- case tmrCOMMAND_STOP :
- /* The timer has already been removed from the active list.
- There is nothing to do here. */
- break;
-
- case tmrCOMMAND_CHANGE_PERIOD :
- pxTimer->xTimerPeriodInTicks = xMessage.xMessageValue;
- configASSERT( ( pxTimer->xTimerPeriodInTicks > 0 ) );
- prvInsertTimerInActiveList( pxTimer, ( xTimeNow + pxTimer->xTimerPeriodInTicks ), xTimeNow, xTimeNow );
- break;
-
- case tmrCOMMAND_DELETE :
- /* The timer has already been removed from the active list,
- just free up the memory. */
- vPortFree( pxTimer );
- break;
-
- default :
- /* Don't expect to get here. */
- break;
- }
- }
-}
-/*-----------------------------------------------------------*/
-
-static void prvSwitchTimerLists( portTickType xLastTime )
-{
-portTickType xNextExpireTime, xReloadTime;
-xList *pxTemp;
-xTIMER *pxTimer;
-portBASE_TYPE xResult;
-
- /* Remove compiler warnings if configASSERT() is not defined. */
- ( void ) xLastTime;
-
- /* The tick count has overflowed. The timer lists must be switched.
- If there are any timers still referenced from the current timer list
- then they must have expired and should be processed before the lists
- are switched. */
- while( listLIST_IS_EMPTY( pxCurrentTimerList ) == pdFALSE )
- {
- xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList );
-
- /* Remove the timer from the list. */
- pxTimer = ( xTIMER * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTimerList );
- vListRemove( &( pxTimer->xTimerListItem ) );
-
- /* Execute its callback, then send a command to restart the timer if
- it is an auto-reload timer. It cannot be restarted here as the lists
- have not yet been switched. */
- pxTimer->pxCallbackFunction( ( xTimerHandle ) pxTimer );
-
- if( pxTimer->uxAutoReload == ( unsigned portBASE_TYPE ) pdTRUE )
- {
- /* Calculate the reload value, and if the reload value results in
- the timer going into the same timer list then it has already expired
- and the timer should be re-inserted into the current list so it is
- processed again within this loop. Otherwise a command should be sent
- to restart the timer to ensure it is only inserted into a list after
- the lists have been swapped. */
- xReloadTime = ( xNextExpireTime + pxTimer->xTimerPeriodInTicks );
- if( xReloadTime > xNextExpireTime )
- {
- listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xReloadTime );
- listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer );
- vListInsert( pxCurrentTimerList, &( pxTimer->xTimerListItem ) );
- }
- else
- {
- xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START, xNextExpireTime, NULL, tmrNO_DELAY );
- configASSERT( xResult );
- ( void ) xResult;
- }
- }
- }
-
- pxTemp = pxCurrentTimerList;
- pxCurrentTimerList = pxOverflowTimerList;
- pxOverflowTimerList = pxTemp;
-}
-/*-----------------------------------------------------------*/
-
-static void prvCheckForValidListAndQueue( void )
-{
- /* Check that the list from which active timers are referenced, and the
- queue used to communicate with the timer service, have been
- initialised. */
- taskENTER_CRITICAL();
- {
- if( xTimerQueue == NULL )
- {
- vListInitialise( &xActiveTimerList1 );
- vListInitialise( &xActiveTimerList2 );
- pxCurrentTimerList = &xActiveTimerList1;
- pxOverflowTimerList = &xActiveTimerList2;
- xTimerQueue = xQueueCreate( ( unsigned portBASE_TYPE ) configTIMER_QUEUE_LENGTH, sizeof( xTIMER_MESSAGE ) );
- }
- }
- taskEXIT_CRITICAL();
-}
-/*-----------------------------------------------------------*/
-
-portBASE_TYPE xTimerIsTimerActive( xTimerHandle xTimer )
-{
-portBASE_TYPE xTimerIsInActiveList;
-xTIMER *pxTimer = ( xTIMER * ) xTimer;
-
- /* Is the timer in the list of active timers? */
- taskENTER_CRITICAL();
- {
- /* Checking to see if it is in the NULL list in effect checks to see if
- it is referenced from either the current or the overflow timer lists in
- one go, but the logic has to be reversed, hence the '!'. */
- xTimerIsInActiveList = !( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) );
- }
- taskEXIT_CRITICAL();
-
- return xTimerIsInActiveList;
-}
-/*-----------------------------------------------------------*/
-
-void *pvTimerGetTimerID( xTimerHandle xTimer )
-{
-xTIMER *pxTimer = ( xTIMER * ) xTimer;
-
- return pxTimer->pvTimerID;
-}
-/*-----------------------------------------------------------*/
-
-/* This entire source file will be skipped if the application is not configured
-to include software timer functionality. If you want to include software timer
-functionality then ensure configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */
-#endif /* configUSE_TIMERS == 1 */
+/*
+ FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.
+
+
+ FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:
+ Atollic AB - Atollic provides professional embedded systems development
+ tools for C/C++ development, code analysis and test automation.
+ See http://www.atollic.com
+
+
+ ***************************************************************************
+ * *
+ * FreeRTOS tutorial books are available in pdf and paperback. *
+ * Complete, revised, and edited pdf reference manuals are also *
+ * available. *
+ * *
+ * Purchasing FreeRTOS documentation will not only help you, by *
+ * ensuring you get running as quickly as possible and with an *
+ * in-depth knowledge of how to use FreeRTOS, it will also help *
+ * the FreeRTOS project to continue with its mission of providing *
+ * professional grade, cross platform, de facto standard solutions *
+ * for microcontrollers - completely free of charge! *
+ * *
+ * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
+ * *
+ * Thank you for using FreeRTOS, and thank you for your support! *
+ * *
+ ***************************************************************************
+
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
+ >>>NOTE<<< The modification to the GPL is included to allow you to
+ distribute a combined work that includes FreeRTOS without being obliged to
+ provide the source code for proprietary components outside of the FreeRTOS
+ kernel. FreeRTOS is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details. You should have received a copy of the GNU General Public
+ License and the FreeRTOS license exception along with FreeRTOS; if not it
+ can be viewed here: http://www.freertos.org/a00114.html and also obtained
+ by writing to Richard Barry, contact details for whom are available on the
+ FreeRTOS WEB site.
+
+ 1 tab == 4 spaces!
+
+ http://www.FreeRTOS.org - Documentation, latest information, license and
+ contact details.
+
+ http://www.SafeRTOS.com - A version that is certified for use in safety
+ critical systems.
+
+ http://www.OpenRTOS.com - Commercial support, development, porting,
+ licensing and training services.
+*/
+
+/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
+all the API functions to use the MPU wrappers. That should only be done when
+task.h is included from an application file. */
+#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
+
+#include "FreeRTOS.h"
+#include "task.h"
+#include "queue.h"
+#include "timers.h"
+
+#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
+
+/* This entire source file will be skipped if the application is not configured
+to include software timer functionality. This #if is closed at the very bottom
+of this file. If you want to include software timer functionality then ensure
+configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */
+#if ( configUSE_TIMERS == 1 )
+
+/* Misc definitions. */
+#define tmrNO_DELAY ( portTickType ) 0U
+
+/* The definition of the timers themselves. */
+typedef struct tmrTimerControl
+{
+ const signed char *pcTimerName; /*<< Text name. This is not used by the kernel, it is included simply to make debugging easier. */
+ xListItem xTimerListItem; /*<< Standard linked list item as used by all kernel features for event management. */
+ portTickType xTimerPeriodInTicks;/*<< How quickly and often the timer expires. */
+ unsigned portBASE_TYPE uxAutoReload; /*<< Set to pdTRUE if the timer should be automatically restarted once expired. Set to pdFALSE if the timer is, in effect, a one shot timer. */
+ void *pvTimerID; /*<< An ID to identify the timer. This allows the timer to be identified when the same callback is used for multiple timers. */
+ tmrTIMER_CALLBACK pxCallbackFunction; /*<< The function that will be called when the timer expires. */
+} xTIMER;
+
+/* The definition of messages that can be sent and received on the timer
+queue. */
+typedef struct tmrTimerQueueMessage
+{
+ portBASE_TYPE xMessageID; /*<< The command being sent to the timer service task. */
+ portTickType xMessageValue; /*<< An optional value used by a subset of commands, for example, when changing the period of a timer. */
+ xTIMER * pxTimer; /*<< The timer to which the command will be applied. */
+} xTIMER_MESSAGE;
+
+
+/* The list in which active timers are stored. Timers are referenced in expire
+time order, with the nearest expiry time at the front of the list. Only the
+timer service task is allowed to access xActiveTimerList. */
+PRIVILEGED_DATA static xList xActiveTimerList1;
+PRIVILEGED_DATA static xList xActiveTimerList2;
+PRIVILEGED_DATA static xList *pxCurrentTimerList;
+PRIVILEGED_DATA static xList *pxOverflowTimerList;
+
+/* A queue that is used to send commands to the timer service task. */
+PRIVILEGED_DATA static xQueueHandle xTimerQueue = NULL;
+
+/*-----------------------------------------------------------*/
+
+/*
+ * Initialise the infrastructure used by the timer service task if it has not
+ * been initialised already.
+ */
+static void prvCheckForValidListAndQueue( void ) PRIVILEGED_FUNCTION;
+
+/*
+ * The timer service task (daemon). Timer functionality is controlled by this
+ * task. Other tasks communicate with the timer service task using the
+ * xTimerQueue queue.
+ */
+static void prvTimerTask( void *pvParameters ) PRIVILEGED_FUNCTION;
+
+/*
+ * Called by the timer service task to interpret and process a command it
+ * received on the timer queue.
+ */
+static void prvProcessReceivedCommands( void ) PRIVILEGED_FUNCTION;
+
+/*
+ * Insert the timer into either xActiveTimerList1, or xActiveTimerList2,
+ * depending on if the expire time causes a timer counter overflow.
+ */
+static portBASE_TYPE prvInsertTimerInActiveList( xTIMER *pxTimer, portTickType xNextExpiryTime, portTickType xTimeNow, portTickType xCommandTime ) PRIVILEGED_FUNCTION;
+
+/*
+ * An active timer has reached its expire time. Reload the timer if it is an
+ * auto reload timer, then call its callback.
+ */
+static void prvProcessExpiredTimer( portTickType xNextExpireTime, portTickType xTimeNow ) PRIVILEGED_FUNCTION;
+
+/*
+ * The tick count has overflowed. Switch the timer lists after ensuring the
+ * current timer list does not still reference some timers.
+ */
+static void prvSwitchTimerLists( portTickType xLastTime ) PRIVILEGED_FUNCTION;
+
+/*
+ * Obtain the current tick count, setting *pxTimerListsWereSwitched to pdTRUE
+ * if a tick count overflow occurred since prvSampleTimeNow() was last called.
+ */
+static portTickType prvSampleTimeNow( portBASE_TYPE *pxTimerListsWereSwitched ) PRIVILEGED_FUNCTION;
+
+/*
+ * If the timer list contains any active timers then return the expire time of
+ * the timer that will expire first and set *pxListWasEmpty to false. If the
+ * timer list does not contain any timers then return 0 and set *pxListWasEmpty
+ * to pdTRUE.
+ */
+static portTickType prvGetNextExpireTime( portBASE_TYPE *pxListWasEmpty ) PRIVILEGED_FUNCTION;
+
+/*
+ * If a timer has expired, process it. Otherwise, block the timer service task
+ * until either a timer does expire or a command is received.
+ */
+static void prvProcessTimerOrBlockTask( portTickType xNextExpireTime, portBASE_TYPE xListWasEmpty ) PRIVILEGED_FUNCTION;
+
+/*-----------------------------------------------------------*/
+
+portBASE_TYPE xTimerCreateTimerTask( void )
+{
+portBASE_TYPE xReturn = pdFAIL;
+
+ /* This function is called when the scheduler is started if
+ configUSE_TIMERS is set to 1. Check that the infrastructure used by the
+ timer service task has been created/initialised. If timers have already
+ been created then the initialisation will already have been performed. */
+ prvCheckForValidListAndQueue();
+
+ if( xTimerQueue != NULL )
+ {
+ xReturn = xTaskCreate( prvTimerTask, ( const signed char * ) "Tmr Svc", ( unsigned short ) configTIMER_TASK_STACK_DEPTH, NULL, ( unsigned portBASE_TYPE ) configTIMER_TASK_PRIORITY, NULL);
+ }
+
+ configASSERT( xReturn );
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+xTimerHandle xTimerCreate( const signed char *pcTimerName, portTickType xTimerPeriodInTicks, unsigned portBASE_TYPE uxAutoReload, void *pvTimerID, tmrTIMER_CALLBACK pxCallbackFunction )
+{
+xTIMER *pxNewTimer;
+
+ /* Allocate the timer structure. */
+ if( xTimerPeriodInTicks == ( portTickType ) 0U )
+ {
+ pxNewTimer = NULL;
+ configASSERT( ( xTimerPeriodInTicks > 0 ) );
+ }
+ else
+ {
+ pxNewTimer = ( xTIMER * ) pvPortMalloc( sizeof( xTIMER ) );
+ if( pxNewTimer != NULL )
+ {
+ /* Ensure the infrastructure used by the timer service task has been
+ created/initialised. */
+ prvCheckForValidListAndQueue();
+
+ /* Initialise the timer structure members using the function parameters. */
+ pxNewTimer->pcTimerName = pcTimerName;
+ pxNewTimer->xTimerPeriodInTicks = xTimerPeriodInTicks;
+ pxNewTimer->uxAutoReload = uxAutoReload;
+ pxNewTimer->pvTimerID = pvTimerID;
+ pxNewTimer->pxCallbackFunction = pxCallbackFunction;
+ vListInitialiseItem( &( pxNewTimer->xTimerListItem ) );
+
+ traceTIMER_CREATE( pxNewTimer );
+ }
+ else
+ {
+ traceTIMER_CREATE_FAILED();
+ }
+ }
+
+ return ( xTimerHandle ) pxNewTimer;
+}
+/*-----------------------------------------------------------*/
+
+portBASE_TYPE xTimerGenericCommand( xTimerHandle xTimer, portBASE_TYPE xCommandID, portTickType xOptionalValue, portBASE_TYPE *pxHigherPriorityTaskWoken, portTickType xBlockTime )
+{
+portBASE_TYPE xReturn = pdFAIL;
+xTIMER_MESSAGE xMessage;
+
+ /* Send a message to the timer service task to perform a particular action
+ on a particular timer definition. */
+ if( xTimerQueue != NULL )
+ {
+ /* Send a command to the timer service task to start the xTimer timer. */
+ xMessage.xMessageID = xCommandID;
+ xMessage.xMessageValue = xOptionalValue;
+ xMessage.pxTimer = ( xTIMER * ) xTimer;
+
+ if( pxHigherPriorityTaskWoken == NULL )
+ {
+ if( xTaskGetSchedulerState() == taskSCHEDULER_RUNNING )
+ {
+ xReturn = xQueueSendToBack( xTimerQueue, &xMessage, xBlockTime );
+ }
+ else
+ {
+ xReturn = xQueueSendToBack( xTimerQueue, &xMessage, tmrNO_DELAY );
+ }
+ }
+ else
+ {
+ xReturn = xQueueSendToBackFromISR( xTimerQueue, &xMessage, pxHigherPriorityTaskWoken );
+ }
+
+ traceTIMER_COMMAND_SEND( xTimer, xCommandID, xOptionalValue, xReturn );
+ }
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+static void prvProcessExpiredTimer( portTickType xNextExpireTime, portTickType xTimeNow )
+{
+xTIMER *pxTimer;
+portBASE_TYPE xResult;
+
+ /* Remove the timer from the list of active timers. A check has already
+ been performed to ensure the list is not empty. */
+ pxTimer = ( xTIMER * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTimerList );
+ vListRemove( &( pxTimer->xTimerListItem ) );
+ traceTIMER_EXPIRED( pxTimer );
+
+ /* If the timer is an auto reload timer then calculate the next
+ expiry time and re-insert the timer in the list of active timers. */
+ if( pxTimer->uxAutoReload == ( unsigned portBASE_TYPE ) pdTRUE )
+ {
+ /* This is the only time a timer is inserted into a list using
+ a time relative to anything other than the current time. It
+ will therefore be inserted into the correct list relative to
+ the time this task thinks it is now, even if a command to
+ switch lists due to a tick count overflow is already waiting in
+ the timer queue. */
+ if( prvInsertTimerInActiveList( pxTimer, ( xNextExpireTime + pxTimer->xTimerPeriodInTicks ), xTimeNow, xNextExpireTime ) == pdTRUE )
+ {
+ /* The timer expired before it was added to the active timer
+ list. Reload it now. */
+ xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START, xNextExpireTime, NULL, tmrNO_DELAY );
+ configASSERT( xResult );
+ ( void ) xResult;
+ }
+ }
+
+ /* Call the timer callback. */
+ pxTimer->pxCallbackFunction( ( xTimerHandle ) pxTimer );
+}
+/*-----------------------------------------------------------*/
+
+static void prvTimerTask( void *pvParameters )
+{
+portTickType xNextExpireTime;
+portBASE_TYPE xListWasEmpty;
+
+ /* Just to avoid compiler warnings. */
+ ( void ) pvParameters;
+
+ for( ;; )
+ {
+ /* Query the timers list to see if it contains any timers, and if so,
+ obtain the time at which the next timer will expire. */
+ xNextExpireTime = prvGetNextExpireTime( &xListWasEmpty );
+
+ /* If a timer has expired, process it. Otherwise, block this task
+ until either a timer does expire, or a command is received. */
+ prvProcessTimerOrBlockTask( xNextExpireTime, xListWasEmpty );
+
+ /* Empty the command queue. */
+ prvProcessReceivedCommands();
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvProcessTimerOrBlockTask( portTickType xNextExpireTime, portBASE_TYPE xListWasEmpty )
+{
+portTickType xTimeNow;
+portBASE_TYPE xTimerListsWereSwitched;
+
+ vTaskSuspendAll();
+ {
+ /* Obtain the time now to make an assessment as to whether the timer
+ has expired or not. If obtaining the time causes the lists to switch
+ then don't process this timer as any timers that remained in the list
+ when the lists were switched will have been processed within the
+ prvSampelTimeNow() function. */
+ xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched );
+ if( xTimerListsWereSwitched == pdFALSE )
+ {
+ /* The tick count has not overflowed, has the timer expired? */
+ if( ( xListWasEmpty == pdFALSE ) && ( xNextExpireTime <= xTimeNow ) )
+ {
+ xTaskResumeAll();
+ prvProcessExpiredTimer( xNextExpireTime, xTimeNow );
+ }
+ else
+ {
+ /* The tick count has not overflowed, and the next expire
+ time has not been reached yet. This task should therefore
+ block to wait for the next expire time or a command to be
+ received - whichever comes first. The following line cannot
+ be reached unless xNextExpireTime > xTimeNow, except in the
+ case when the current timer list is empty. */
+ vQueueWaitForMessageRestricted( xTimerQueue, ( xNextExpireTime - xTimeNow ) );
+
+ if( xTaskResumeAll() == pdFALSE )
+ {
+ /* Yield to wait for either a command to arrive, or the block time
+ to expire. If a command arrived between the critical section being
+ exited and this yield then the yield will not cause the task
+ to block. */
+ portYIELD_WITHIN_API();
+ }
+ }
+ }
+ else
+ {
+ xTaskResumeAll();
+ }
+ }
+}
+/*-----------------------------------------------------------*/
+
+static portTickType prvGetNextExpireTime( portBASE_TYPE *pxListWasEmpty )
+{
+portTickType xNextExpireTime;
+
+ /* Timers are listed in expiry time order, with the head of the list
+ referencing the task that will expire first. Obtain the time at which
+ the timer with the nearest expiry time will expire. If there are no
+ active timers then just set the next expire time to 0. That will cause
+ this task to unblock when the tick count overflows, at which point the
+ timer lists will be switched and the next expiry time can be
+ re-assessed. */
+ *pxListWasEmpty = listLIST_IS_EMPTY( pxCurrentTimerList );
+ if( *pxListWasEmpty == pdFALSE )
+ {
+ xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList );
+ }
+ else
+ {
+ /* Ensure the task unblocks when the tick count rolls over. */
+ xNextExpireTime = ( portTickType ) 0U;
+ }
+
+ return xNextExpireTime;
+}
+/*-----------------------------------------------------------*/
+
+static portTickType prvSampleTimeNow( portBASE_TYPE *pxTimerListsWereSwitched )
+{
+portTickType xTimeNow;
+static portTickType xLastTime = ( portTickType ) 0U;
+
+ xTimeNow = xTaskGetTickCount();
+
+ if( xTimeNow < xLastTime )
+ {
+ prvSwitchTimerLists( xLastTime );
+ *pxTimerListsWereSwitched = pdTRUE;
+ }
+ else
+ {
+ *pxTimerListsWereSwitched = pdFALSE;
+ }
+
+ xLastTime = xTimeNow;
+
+ return xTimeNow;
+}
+/*-----------------------------------------------------------*/
+
+static portBASE_TYPE prvInsertTimerInActiveList( xTIMER *pxTimer, portTickType xNextExpiryTime, portTickType xTimeNow, portTickType xCommandTime )
+{
+portBASE_TYPE xProcessTimerNow = pdFALSE;
+
+ listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xNextExpiryTime );
+ listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer );
+
+ if( xNextExpiryTime <= xTimeNow )
+ {
+ /* Has the expiry time elapsed between the command to start/reset a
+ timer was issued, and the time the command was processed? */
+ if( ( ( portTickType ) ( xTimeNow - xCommandTime ) ) >= pxTimer->xTimerPeriodInTicks )
+ {
+ /* The time between a command being issued and the command being
+ processed actually exceeds the timers period. */
+ xProcessTimerNow = pdTRUE;
+ }
+ else
+ {
+ vListInsert( pxOverflowTimerList, &( pxTimer->xTimerListItem ) );
+ }
+ }
+ else
+ {
+ if( ( xTimeNow < xCommandTime ) && ( xNextExpiryTime >= xCommandTime ) )
+ {
+ /* If, since the command was issued, the tick count has overflowed
+ but the expiry time has not, then the timer must have already passed
+ its expiry time and should be processed immediately. */
+ xProcessTimerNow = pdTRUE;
+ }
+ else
+ {
+ vListInsert( pxCurrentTimerList, &( pxTimer->xTimerListItem ) );
+ }
+ }
+
+ return xProcessTimerNow;
+}
+/*-----------------------------------------------------------*/
+
+static void prvProcessReceivedCommands( void )
+{
+xTIMER_MESSAGE xMessage;
+xTIMER *pxTimer;
+portBASE_TYPE xTimerListsWereSwitched, xResult;
+portTickType xTimeNow;
+
+ /* In this case the xTimerListsWereSwitched parameter is not used, but it
+ must be present in the function call. */
+ xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched );
+
+ while( xQueueReceive( xTimerQueue, &xMessage, tmrNO_DELAY ) != pdFAIL )
+ {
+ pxTimer = xMessage.pxTimer;
+
+ /* Is the timer already in a list of active timers? When the command
+ is trmCOMMAND_PROCESS_TIMER_OVERFLOW, the timer will be NULL as the
+ command is to the task rather than to an individual timer. */
+ if( pxTimer != NULL )
+ {
+ if( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) == pdFALSE )
+ {
+ /* The timer is in a list, remove it. */
+ vListRemove( &( pxTimer->xTimerListItem ) );
+ }
+ }
+
+ traceTIMER_COMMAND_RECEIVED( pxTimer, xMessage.xMessageID, xMessage.xMessageValue );
+
+ switch( xMessage.xMessageID )
+ {
+ case tmrCOMMAND_START :
+ /* Start or restart a timer. */
+ if( prvInsertTimerInActiveList( pxTimer, xMessage.xMessageValue + pxTimer->xTimerPeriodInTicks, xTimeNow, xMessage.xMessageValue ) == pdTRUE )
+ {
+ /* The timer expired before it was added to the active timer
+ list. Process it now. */
+ pxTimer->pxCallbackFunction( ( xTimerHandle ) pxTimer );
+
+ if( pxTimer->uxAutoReload == ( unsigned portBASE_TYPE ) pdTRUE )
+ {
+ xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START, xMessage.xMessageValue + pxTimer->xTimerPeriodInTicks, NULL, tmrNO_DELAY );
+ configASSERT( xResult );
+ ( void ) xResult;
+ }
+ }
+ break;
+
+ case tmrCOMMAND_STOP :
+ /* The timer has already been removed from the active list.
+ There is nothing to do here. */
+ break;
+
+ case tmrCOMMAND_CHANGE_PERIOD :
+ pxTimer->xTimerPeriodInTicks = xMessage.xMessageValue;
+ configASSERT( ( pxTimer->xTimerPeriodInTicks > 0 ) );
+ prvInsertTimerInActiveList( pxTimer, ( xTimeNow + pxTimer->xTimerPeriodInTicks ), xTimeNow, xTimeNow );
+ break;
+
+ case tmrCOMMAND_DELETE :
+ /* The timer has already been removed from the active list,
+ just free up the memory. */
+ vPortFree( pxTimer );
+ break;
+
+ default :
+ /* Don't expect to get here. */
+ break;
+ }
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvSwitchTimerLists( portTickType xLastTime )
+{
+portTickType xNextExpireTime, xReloadTime;
+xList *pxTemp;
+xTIMER *pxTimer;
+portBASE_TYPE xResult;
+
+ /* Remove compiler warnings if configASSERT() is not defined. */
+ ( void ) xLastTime;
+
+ /* The tick count has overflowed. The timer lists must be switched.
+ If there are any timers still referenced from the current timer list
+ then they must have expired and should be processed before the lists
+ are switched. */
+ while( listLIST_IS_EMPTY( pxCurrentTimerList ) == pdFALSE )
+ {
+ xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList );
+
+ /* Remove the timer from the list. */
+ pxTimer = ( xTIMER * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTimerList );
+ vListRemove( &( pxTimer->xTimerListItem ) );
+
+ /* Execute its callback, then send a command to restart the timer if
+ it is an auto-reload timer. It cannot be restarted here as the lists
+ have not yet been switched. */
+ pxTimer->pxCallbackFunction( ( xTimerHandle ) pxTimer );
+
+ if( pxTimer->uxAutoReload == ( unsigned portBASE_TYPE ) pdTRUE )
+ {
+ /* Calculate the reload value, and if the reload value results in
+ the timer going into the same timer list then it has already expired
+ and the timer should be re-inserted into the current list so it is
+ processed again within this loop. Otherwise a command should be sent
+ to restart the timer to ensure it is only inserted into a list after
+ the lists have been swapped. */
+ xReloadTime = ( xNextExpireTime + pxTimer->xTimerPeriodInTicks );
+ if( xReloadTime > xNextExpireTime )
+ {
+ listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xReloadTime );
+ listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer );
+ vListInsert( pxCurrentTimerList, &( pxTimer->xTimerListItem ) );
+ }
+ else
+ {
+ xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START, xNextExpireTime, NULL, tmrNO_DELAY );
+ configASSERT( xResult );
+ ( void ) xResult;
+ }
+ }
+ }
+
+ pxTemp = pxCurrentTimerList;
+ pxCurrentTimerList = pxOverflowTimerList;
+ pxOverflowTimerList = pxTemp;
+}
+/*-----------------------------------------------------------*/
+
+static void prvCheckForValidListAndQueue( void )
+{
+ /* Check that the list from which active timers are referenced, and the
+ queue used to communicate with the timer service, have been
+ initialised. */
+ taskENTER_CRITICAL();
+ {
+ if( xTimerQueue == NULL )
+ {
+ vListInitialise( &xActiveTimerList1 );
+ vListInitialise( &xActiveTimerList2 );
+ pxCurrentTimerList = &xActiveTimerList1;
+ pxOverflowTimerList = &xActiveTimerList2;
+ xTimerQueue = xQueueCreate( ( unsigned portBASE_TYPE ) configTIMER_QUEUE_LENGTH, sizeof( xTIMER_MESSAGE ) );
+ }
+ }
+ taskEXIT_CRITICAL();
+}
+/*-----------------------------------------------------------*/
+
+portBASE_TYPE xTimerIsTimerActive( xTimerHandle xTimer )
+{
+portBASE_TYPE xTimerIsInActiveList;
+xTIMER *pxTimer = ( xTIMER * ) xTimer;
+
+ /* Is the timer in the list of active timers? */
+ taskENTER_CRITICAL();
+ {
+ /* Checking to see if it is in the NULL list in effect checks to see if
+ it is referenced from either the current or the overflow timer lists in
+ one go, but the logic has to be reversed, hence the '!'. */
+ xTimerIsInActiveList = !( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) );
+ }
+ taskEXIT_CRITICAL();
+
+ return xTimerIsInActiveList;
+}
+/*-----------------------------------------------------------*/
+
+void *pvTimerGetTimerID( xTimerHandle xTimer )
+{
+xTIMER *pxTimer = ( xTIMER * ) xTimer;
+
+ return pxTimer->pvTimerID;
+}
+/*-----------------------------------------------------------*/
+
+/* This entire source file will be skipped if the application is not configured
+to include software timer functionality. If you want to include software timer
+functionality then ensure configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */
+#endif /* configUSE_TIMERS == 1 */
diff --git a/Libmaple/libmaple/libraries/FreeRTOS/utility/timers.h b/Libmaple/libmaple/libraries/FreeRTOS/utility/timers.h
index 3d78c0ae..f1bcb0d8 100644
--- a/Libmaple/libmaple/libraries/FreeRTOS/utility/timers.h
+++ b/Libmaple/libmaple/libraries/FreeRTOS/utility/timers.h
@@ -1,936 +1,936 @@
-/*
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.
-
-
- FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:
- Atollic AB - Atollic provides professional embedded systems development
- tools for C/C++ development, code analysis and test automation.
- See http://www.atollic.com
-
-
- ***************************************************************************
- * *
- * FreeRTOS tutorial books are available in pdf and paperback. *
- * Complete, revised, and edited pdf reference manuals are also *
- * available. *
- * *
- * Purchasing FreeRTOS documentation will not only help you, by *
- * ensuring you get running as quickly as possible and with an *
- * in-depth knowledge of how to use FreeRTOS, it will also help *
- * the FreeRTOS project to continue with its mission of providing *
- * professional grade, cross platform, de facto standard solutions *
- * for microcontrollers - completely free of charge! *
- * *
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
- * *
- * Thank you for using FreeRTOS, and thank you for your support! *
- * *
- ***************************************************************************
-
-
- This file is part of the FreeRTOS distribution.
-
- FreeRTOS is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License (version 2) as published by the
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
- >>>NOTE<<< The modification to the GPL is included to allow you to
- distribute a combined work that includes FreeRTOS without being obliged to
- provide the source code for proprietary components outside of the FreeRTOS
- kernel. FreeRTOS is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- more details. You should have received a copy of the GNU General Public
- License and the FreeRTOS license exception along with FreeRTOS; if not it
- can be viewed here: http://www.freertos.org/a00114.html and also obtained
- by writing to Richard Barry, contact details for whom are available on the
- FreeRTOS WEB site.
-
- 1 tab == 4 spaces!
-
- http://www.FreeRTOS.org - Documentation, latest information, license and
- contact details.
-
- http://www.SafeRTOS.com - A version that is certified for use in safety
- critical systems.
-
- http://www.OpenRTOS.com - Commercial support, development, porting,
- licensing and training services.
-*/
-
-
-#ifndef TIMERS_H
-#define TIMERS_H
-
-#ifndef INC_FREERTOS_H
- #error "include FreeRTOS.h must appear in source files before include timers.h"
-#endif
-
-#include "portable.h"
-#include "list.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* IDs for commands that can be sent/received on the timer queue. These are to
-be used solely through the macros that make up the public software timer API,
-as defined below. */
-#define tmrCOMMAND_START 0
-#define tmrCOMMAND_STOP 1
-#define tmrCOMMAND_CHANGE_PERIOD 2
-#define tmrCOMMAND_DELETE 3
-
-/*-----------------------------------------------------------
- * MACROS AND DEFINITIONS
- *----------------------------------------------------------*/
-
- /**
- * Type by which software timers are referenced. For example, a call to
- * xTimerCreate() returns an xTimerHandle variable that can then be used to
- * reference the subject timer in calls to other software timer API functions
- * (for example, xTimerStart(), xTimerReset(), etc.).
- */
-typedef void * xTimerHandle;
-
-/* Define the prototype to which timer callback functions must conform. */
-typedef void (*tmrTIMER_CALLBACK)( xTimerHandle xTimer );
-
-/**
- * xTimerHandle xTimerCreate( const signed char *pcTimerName,
- * portTickType xTimerPeriod,
- * unsigned portBASE_TYPE uxAutoReload,
- * void * pvTimerID,
- * tmrTIMER_CALLBACK pxCallbackFunction );
- *
- * Creates a new software timer instance. This allocates the storage required
- * by the new timer, initialises the new timers internal state, and returns a
- * handle by which the new timer can be referenced.
- *
- * Timers are created in the dormant state. The xTimerStart(), xTimerReset(),
- * xTimerStartFromISR(), xTimerResetFromISR(), xTimerChangePeriod() and
- * xTimerChangePeriodFromISR() API functions can all be used to transition a timer into the
- * active state.
- *
- * @param pcTimerName A text name that is assigned to the timer. This is done
- * purely to assist debugging. The kernel itself only ever references a timer by
- * its handle, and never by its name.
- *
- * @param xTimerPeriod The timer period. The time is defined in tick periods so
- * the constant portTICK_RATE_MS can be used to convert a time that has been
- * specified in milliseconds. For example, if the timer must expire after 100
- * ticks, then xTimerPeriod should be set to 100. Alternatively, if the timer
- * must expire after 500ms, then xPeriod can be set to ( 500 / portTICK_RATE_MS )
- * provided configTICK_RATE_HZ is less than or equal to 1000.
- *
- * @param uxAutoReload If uxAutoReload is set to pdTRUE then the timer will
- * expire repeatedly with a frequency set by the xTimerPeriod parameter. If
- * uxAutoReload is set to pdFALSE then the timer will be a one-shot timer and
- * enter the dormant state after it expires.
- *
- * @param pvTimerID An identifier that is assigned to the timer being created.
- * Typically this would be used in the timer callback function to identify which
- * timer expired when the same callback function is assigned to more than one
- * timer.
- *
- * @param pxCallbackFunction The function to call when the timer expires.
- * Callback functions must have the prototype defined by tmrTIMER_CALLBACK,
- * which is "void vCallbackFunction( xTIMER *xTimer );".
- *
- * @return If the timer is successfully create then a handle to the newly
- * created timer is returned. If the timer cannot be created (because either
- * there is insufficient FreeRTOS heap remaining to allocate the timer
- * structures, or the timer period was set to 0) then 0 is returned.
- *
- * Example usage:
- *
- *
- * #define NUM_TIMERS 5
- *
- * // An array to hold handles to the created timers.
- * xTimerHandle xTimers[ NUM_TIMERS ];
- *
- * // An array to hold a count of the number of times each timer expires.
- * long lExpireCounters[ NUM_TIMERS ] = { 0 };
- *
- * // Define a callback function that will be used by multiple timer instances.
- * // The callback function does nothing but count the number of times the
- * // associated timer expires, and stop the timer once the timer has expired
- * // 10 times.
- * void vTimerCallback( xTIMER *pxTimer )
- * {
- * long lArrayIndex;
- * const long xMaxExpiryCountBeforeStopping = 10;
- *
- * // Optionally do something if the pxTimer parameter is NULL.
- * configASSERT( pxTimer );
- *
- * // Which timer expired?
- * lArrayIndex = ( long ) pvTimerGetTimerID( pxTimer );
- *
- * // Increment the number of times that pxTimer has expired.
- * lExpireCounters[ lArrayIndex ] += 1;
- *
- * // If the timer has expired 10 times then stop it from running.
- * if( lExpireCounters[ lArrayIndex ] == xMaxExpiryCountBeforeStopping )
- * {
- * // Do not use a block time if calling a timer API function from a
- * // timer callback function, as doing so could cause a deadlock!
- * xTimerStop( pxTimer, 0 );
- * }
- * }
- *
- * void main( void )
- * {
- * long x;
- *
- * // Create then start some timers. Starting the timers before the scheduler
- * // has been started means the timers will start running immediately that
- * // the scheduler starts.
- * for( x = 0; x < NUM_TIMERS; x++ )
- * {
- * xTimers[ x ] = xTimerCreate( "Timer", // Just a text name, not used by the kernel.
- * ( 100 * x ), // The timer period in ticks.
- * pdTRUE, // The timers will auto-reload themselves when they expire.
- * ( void * ) x, // Assign each timer a unique id equal to its array index.
- * vTimerCallback // Each timer calls the same callback when it expires.
- * );
- *
- * if( xTimers[ x ] == NULL )
- * {
- * // The timer was not created.
- * }
- * else
- * {
- * // Start the timer. No block time is specified, and even if one was
- * // it would be ignored because the scheduler has not yet been
- * // started.
- * if( xTimerStart( xTimers[ x ], 0 ) != pdPASS )
- * {
- * // The timer could not be set into the Active state.
- * }
- * }
- * }
- *
- * // ...
- * // Create tasks here.
- * // ...
- *
- * // Starting the scheduler will start the timers running as they have already
- * // been set into the active state.
- * xTaskStartScheduler();
- *
- * // Should not reach here.
- * for( ;; );
- * }
- */
-xTimerHandle xTimerCreate( const signed char *pcTimerName, portTickType xTimerPeriodInTicks, unsigned portBASE_TYPE uxAutoReload, void * pvTimerID, tmrTIMER_CALLBACK pxCallbackFunction ) PRIVILEGED_FUNCTION;
-
-/**
- * void *pvTimerGetTimerID( xTimerHandle xTimer );
- *
- * Returns the ID assigned to the timer.
- *
- * IDs are assigned to timers using the pvTimerID parameter of the call to
- * xTimerCreated() that was used to create the timer.
- *
- * If the same callback function is assigned to multiple timers then the timer
- * ID can be used within the callback function to identify which timer actually
- * expired.
- *
- * @param xTimer The timer being queried.
- *
- * @return The ID assigned to the timer being queried.
- *
- * Example usage:
- *
- * See the xTimerCreate() API function example usage scenario.
- */
-void *pvTimerGetTimerID( xTimerHandle xTimer ) PRIVILEGED_FUNCTION;
-
-/**
- * portBASE_TYPE xTimerIsTimerActive( xTimerHandle xTimer );
- *
- * Queries a timer to see if it is active or dormant.
- *
- * A timer will be dormant if:
- * 1) It has been created but not started, or
- * 2) It is an expired on-shot timer that has not been restarted.
- *
- * Timers are created in the dormant state. The xTimerStart(), xTimerReset(),
- * xTimerStartFromISR(), xTimerResetFromISR(), xTimerChangePeriod() and
- * xTimerChangePeriodFromISR() API functions can all be used to transition a timer into the
- * active state.
- *
- * @param xTimer The timer being queried.
- *
- * @return pdFALSE will be returned if the timer is dormant. A value other than
- * pdFALSE will be returned if the timer is active.
- *
- * Example usage:
- *
- * // This function assumes xTimer has already been created.
- * void vAFunction( xTimerHandle xTimer )
- * {
- * if( xTimerIsTimerActive( xTimer ) != pdFALSE ) // or more simply and equivalently "if( xTimerIsTimerActive( xTimer ) )"
- * {
- * // xTimer is active, do something.
- * }
- * else
- * {
- * // xTimer is not active, do something else.
- * }
- * }
- */
-portBASE_TYPE xTimerIsTimerActive( xTimerHandle xTimer ) PRIVILEGED_FUNCTION;
-
-/**
- * portBASE_TYPE xTimerStart( xTimerHandle xTimer, portTickType xBlockTime );
- *
- * Timer functionality is provided by a timer service/daemon task. Many of the
- * public FreeRTOS timer API functions send commands to the timer service task
- * though a queue called the timer command queue. The timer command queue is
- * private to the kernel itself and is not directly accessible to application
- * code. The length of the timer command queue is set by the
- * configTIMER_QUEUE_LENGTH configuration constant.
- *
- * xTimerStart() starts a timer that was previously created using the
- * xTimerCreate() API function. If the timer had already been started and was
- * already in the active state, then xTimerStart() has equivalent functionality
- * to the xTimerReset() API function.
- *
- * Starting a timer ensures the timer is in the active state. If the timer
- * is not stopped, deleted, or reset in the mean time, the callback function
- * associated with the timer will get called 'n' ticks after xTimerStart() was
- * called, where 'n' is the timers defined period.
- *
- * It is valid to call xTimerStart() before the scheduler has been started, but
- * when this is done the timer will not actually start until the scheduler is
- * started, and the timers expiry time will be relative to when the scheduler is
- * started, not relative to when xTimerStart() was called.
- *
- * The configUSE_TIMERS configuration constant must be set to 1 for xTimerStart()
- * to be available.
- *
- * @param xTimer The handle of the timer being started/restarted.
- *
- * @param xBlockTime Specifies the time, in ticks, that the calling task should
- * be held in the Blocked state to wait for the start command to be successfully
- * sent to the timer command queue, should the queue already be full when
- * xTimerStart() was called. xBlockTime is ignored if xTimerStart() is called
- * before the scheduler is started.
- *
- * @return pdFAIL will be returned if the start command could not be sent to
- * the timer command queue even after xBlockTime ticks had passed. pdPASS will
- * be returned if the command was successfully sent to the timer command queue.
- * When the command is actually processed will depend on the priority of the
- * timer service/daemon task relative to other tasks in the system, although the
- * timers expiry time is relative to when xTimerStart() is actually called. The
- * timer service/daemon task priority is set by the configTIMER_TASK_PRIORITY
- * configuration constant.
- *
- * Example usage:
- *
- * See the xTimerCreate() API function example usage scenario.
- *
- */
-#define xTimerStart( xTimer, xBlockTime ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_START, ( xTaskGetTickCount() ), NULL, ( xBlockTime ) )
-
-/**
- * portBASE_TYPE xTimerStop( xTimerHandle xTimer, portTickType xBlockTime );
- *
- * Timer functionality is provided by a timer service/daemon task. Many of the
- * public FreeRTOS timer API functions send commands to the timer service task
- * though a queue called the timer command queue. The timer command queue is
- * private to the kernel itself and is not directly accessible to application
- * code. The length of the timer command queue is set by the
- * configTIMER_QUEUE_LENGTH configuration constant.
- *
- * xTimerStop() stops a timer that was previously started using either of the
- * The xTimerStart(), xTimerReset(), xTimerStartFromISR(), xTimerResetFromISR(),
- * xTimerChangePeriod() or xTimerChangePeriodFromISR() API functions.
- *
- * Stopping a timer ensures the timer is not in the active state.
- *
- * The configUSE_TIMERS configuration constant must be set to 1 for xTimerStop()
- * to be available.
- *
- * @param xTimer The handle of the timer being stopped.
- *
- * @param xBlockTime Specifies the time, in ticks, that the calling task should
- * be held in the Blocked state to wait for the stop command to be successfully
- * sent to the timer command queue, should the queue already be full when
- * xTimerStop() was called. xBlockTime is ignored if xTimerStop() is called
- * before the scheduler is started.
- *
- * @return pdFAIL will be returned if the stop command could not be sent to
- * the timer command queue even after xBlockTime ticks had passed. pdPASS will
- * be returned if the command was successfully sent to the timer command queue.
- * When the command is actually processed will depend on the priority of the
- * timer service/daemon task relative to other tasks in the system. The timer
- * service/daemon task priority is set by the configTIMER_TASK_PRIORITY
- * configuration constant.
- *
- * Example usage:
- *
- * See the xTimerCreate() API function example usage scenario.
- *
- */
-#define xTimerStop( xTimer, xBlockTime ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_STOP, 0U, NULL, ( xBlockTime ) )
-
-/**
- * portBASE_TYPE xTimerChangePeriod( xTimerHandle xTimer,
- * portTickType xNewPeriod,
- * portTickType xBlockTime );
- *
- * Timer functionality is provided by a timer service/daemon task. Many of the
- * public FreeRTOS timer API functions send commands to the timer service task
- * though a queue called the timer command queue. The timer command queue is
- * private to the kernel itself and is not directly accessible to application
- * code. The length of the timer command queue is set by the
- * configTIMER_QUEUE_LENGTH configuration constant.
- *
- * xTimerChangePeriod() changes the period of a timer that was previously
- * created using the xTimerCreate() API function.
- *
- * xTimerChangePeriod() can be called to change the period of an active or
- * dormant state timer.
- *
- * The configUSE_TIMERS configuration constant must be set to 1 for
- * xTimerChangePeriod() to be available.
- *
- * @param xTimer The handle of the timer that is having its period changed.
- *
- * @param xNewPeriod The new period for xTimer. Timer periods are specified in
- * tick periods, so the constant portTICK_RATE_MS can be used to convert a time
- * that has been specified in milliseconds. For example, if the timer must
- * expire after 100 ticks, then xNewPeriod should be set to 100. Alternatively,
- * if the timer must expire after 500ms, then xNewPeriod can be set to
- * ( 500 / portTICK_RATE_MS ) provided configTICK_RATE_HZ is less than
- * or equal to 1000.
- *
- * @param xBlockTime Specifies the time, in ticks, that the calling task should
- * be held in the Blocked state to wait for the change period command to be
- * successfully sent to the timer command queue, should the queue already be
- * full when xTimerChangePeriod() was called. xBlockTime is ignored if
- * xTimerChangePeriod() is called before the scheduler is started.
- *
- * @return pdFAIL will be returned if the change period command could not be
- * sent to the timer command queue even after xBlockTime ticks had passed.
- * pdPASS will be returned if the command was successfully sent to the timer
- * command queue. When the command is actually processed will depend on the
- * priority of the timer service/daemon task relative to other tasks in the
- * system. The timer service/daemon task priority is set by the
- * configTIMER_TASK_PRIORITY configuration constant.
- *
- * Example usage:
- *
- * // This function assumes xTimer has already been created. If the timer
- * // referenced by xTimer is already active when it is called, then the timer
- * // is deleted. If the timer referenced by xTimer is not active when it is
- * // called, then the period of the timer is set to 500ms and the timer is
- * // started.
- * void vAFunction( xTimerHandle xTimer )
- * {
- * if( xTimerIsTimerActive( xTimer ) != pdFALSE ) // or more simply and equivalently "if( xTimerIsTimerActive( xTimer ) )"
- * {
- * // xTimer is already active - delete it.
- * xTimerDelete( xTimer );
- * }
- * else
- * {
- * // xTimer is not active, change its period to 500ms. This will also
- * // cause the timer to start. Block for a maximum of 100 ticks if the
- * // change period command cannot immediately be sent to the timer
- * // command queue.
- * if( xTimerChangePeriod( xTimer, 500 / portTICK_RATE_MS, 100 ) == pdPASS )
- * {
- * // The command was successfully sent.
- * }
- * else
- * {
- * // The command could not be sent, even after waiting for 100 ticks
- * // to pass. Take appropriate action here.
- * }
- * }
- * }
- */
- #define xTimerChangePeriod( xTimer, xNewPeriod, xBlockTime ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_CHANGE_PERIOD, ( xNewPeriod ), NULL, ( xBlockTime ) )
-
-/**
- * portBASE_TYPE xTimerDelete( xTimerHandle xTimer, portTickType xBlockTime );
- *
- * Timer functionality is provided by a timer service/daemon task. Many of the
- * public FreeRTOS timer API functions send commands to the timer service task
- * though a queue called the timer command queue. The timer command queue is
- * private to the kernel itself and is not directly accessible to application
- * code. The length of the timer command queue is set by the
- * configTIMER_QUEUE_LENGTH configuration constant.
- *
- * xTimerDelete() deletes a timer that was previously created using the
- * xTimerCreate() API function.
- *
- * The configUSE_TIMERS configuration constant must be set to 1 for
- * xTimerDelete() to be available.
- *
- * @param xTimer The handle of the timer being deleted.
- *
- * @param xBlockTime Specifies the time, in ticks, that the calling task should
- * be held in the Blocked state to wait for the delete command to be
- * successfully sent to the timer command queue, should the queue already be
- * full when xTimerDelete() was called. xBlockTime is ignored if xTimerDelete()
- * is called before the scheduler is started.
- *
- * @return pdFAIL will be returned if the delete command could not be sent to
- * the timer command queue even after xBlockTime ticks had passed. pdPASS will
- * be returned if the command was successfully sent to the timer command queue.
- * When the command is actually processed will depend on the priority of the
- * timer service/daemon task relative to other tasks in the system. The timer
- * service/daemon task priority is set by the configTIMER_TASK_PRIORITY
- * configuration constant.
- *
- * Example usage:
- *
- * See the xTimerChangePeriod() API function example usage scenario.
- */
-#define xTimerDelete( xTimer, xBlockTime ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_DELETE, 0U, NULL, ( xBlockTime ) )
-
-/**
- * portBASE_TYPE xTimerReset( xTimerHandle xTimer, portTickType xBlockTime );
- *
- * Timer functionality is provided by a timer service/daemon task. Many of the
- * public FreeRTOS timer API functions send commands to the timer service task
- * though a queue called the timer command queue. The timer command queue is
- * private to the kernel itself and is not directly accessible to application
- * code. The length of the timer command queue is set by the
- * configTIMER_QUEUE_LENGTH configuration constant.
- *
- * xTimerReset() re-starts a timer that was previously created using the
- * xTimerCreate() API function. If the timer had already been started and was
- * already in the active state, then xTimerReset() will cause the timer to
- * re-evaluate its expiry time so that it is relative to when xTimerReset() was
- * called. If the timer was in the dormant state then xTimerReset() has
- * equivalent functionality to the xTimerStart() API function.
- *
- * Resetting a timer ensures the timer is in the active state. If the timer
- * is not stopped, deleted, or reset in the mean time, the callback function
- * associated with the timer will get called 'n' ticks after xTimerReset() was
- * called, where 'n' is the timers defined period.
- *
- * It is valid to call xTimerReset() before the scheduler has been started, but
- * when this is done the timer will not actually start until the scheduler is
- * started, and the timers expiry time will be relative to when the scheduler is
- * started, not relative to when xTimerReset() was called.
- *
- * The configUSE_TIMERS configuration constant must be set to 1 for xTimerReset()
- * to be available.
- *
- * @param xTimer The handle of the timer being reset/started/restarted.
- *
- * @param xBlockTime Specifies the time, in ticks, that the calling task should
- * be held in the Blocked state to wait for the reset command to be successfully
- * sent to the timer command queue, should the queue already be full when
- * xTimerReset() was called. xBlockTime is ignored if xTimerReset() is called
- * before the scheduler is started.
- *
- * @return pdFAIL will be returned if the reset command could not be sent to
- * the timer command queue even after xBlockTime ticks had passed. pdPASS will
- * be returned if the command was successfully sent to the timer command queue.
- * When the command is actually processed will depend on the priority of the
- * timer service/daemon task relative to other tasks in the system, although the
- * timers expiry time is relative to when xTimerStart() is actually called. The
- * timer service/daemon task priority is set by the configTIMER_TASK_PRIORITY
- * configuration constant.
- *
- * Example usage:
- *
- * // When a key is pressed, an LCD back-light is switched on. If 5 seconds pass
- * // without a key being pressed, then the LCD back-light is switched off. In
- * // this case, the timer is a one-shot timer.
- *
- * xTimerHandle xBacklightTimer = NULL;
- *
- * // The callback function assigned to the one-shot timer. In this case the
- * // parameter is not used.
- * void vBacklightTimerCallback( xTIMER *pxTimer )
- * {
- * // The timer expired, therefore 5 seconds must have passed since a key
- * // was pressed. Switch off the LCD back-light.
- * vSetBacklightState( BACKLIGHT_OFF );
- * }
- *
- * // The key press event handler.
- * void vKeyPressEventHandler( char cKey )
- * {
- * // Ensure the LCD back-light is on, then reset the timer that is
- * // responsible for turning the back-light off after 5 seconds of
- * // key inactivity. Wait 10 ticks for the command to be successfully sent
- * // if it cannot be sent immediately.
- * vSetBacklightState( BACKLIGHT_ON );
- * if( xTimerReset( xBacklightTimer, 100 ) != pdPASS )
- * {
- * // The reset command was not executed successfully. Take appropriate
- * // action here.
- * }
- *
- * // Perform the rest of the key processing here.
- * }
- *
- * void main( void )
- * {
- * long x;
- *
- * // Create then start the one-shot timer that is responsible for turning
- * // the back-light off if no keys are pressed within a 5 second period.
- * xBacklightTimer = xTimerCreate( "BacklightTimer", // Just a text name, not used by the kernel.
- * ( 5000 / portTICK_RATE_MS), // The timer period in ticks.
- * pdFALSE, // The timer is a one-shot timer.
- * 0, // The id is not used by the callback so can take any value.
- * vBacklightTimerCallback // The callback function that switches the LCD back-light off.
- * );
- *
- * if( xBacklightTimer == NULL )
- * {
- * // The timer was not created.
- * }
- * else
- * {
- * // Start the timer. No block time is specified, and even if one was
- * // it would be ignored because the scheduler has not yet been
- * // started.
- * if( xTimerStart( xBacklightTimer, 0 ) != pdPASS )
- * {
- * // The timer could not be set into the Active state.
- * }
- * }
- *
- * // ...
- * // Create tasks here.
- * // ...
- *
- * // Starting the scheduler will start the timer running as it has already
- * // been set into the active state.
- * xTaskStartScheduler();
- *
- * // Should not reach here.
- * for( ;; );
- * }
- */
-#define xTimerReset( xTimer, xBlockTime ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_START, ( xTaskGetTickCount() ), NULL, ( xBlockTime ) )
-
-/**
- * portBASE_TYPE xTimerStartFromISR( xTimerHandle xTimer,
- * portBASE_TYPE *pxHigherPriorityTaskWoken );
- *
- * A version of xTimerStart() that can be called from an interrupt service
- * routine.
- *
- * @param xTimer The handle of the timer being started/restarted.
- *
- * @param pxHigherPriorityTaskWoken The timer service/daemon task spends most
- * of its time in the Blocked state, waiting for messages to arrive on the timer
- * command queue. Calling xTimerStartFromISR() writes a message to the timer
- * command queue, so has the potential to transition the timer service/daemon
- * task out of the Blocked state. If calling xTimerStartFromISR() causes the
- * timer service/daemon task to leave the Blocked state, and the timer service/
- * daemon task has a priority equal to or greater than the currently executing
- * task (the task that was interrupted), then *pxHigherPriorityTaskWoken will
- * get set to pdTRUE internally within the xTimerStartFromISR() function. If
- * xTimerStartFromISR() sets this value to pdTRUE then a context switch should
- * be performed before the interrupt exits.
- *
- * @return pdFAIL will be returned if the start command could not be sent to
- * the timer command queue. pdPASS will be returned if the command was
- * successfully sent to the timer command queue. When the command is actually
- * processed will depend on the priority of the timer service/daemon task
- * relative to other tasks in the system, although the timers expiry time is
- * relative to when xTimerStartFromISR() is actually called. The timer service/daemon
- * task priority is set by the configTIMER_TASK_PRIORITY configuration constant.
- *
- * Example usage:
- *
- * // This scenario assumes xBacklightTimer has already been created. When a
- * // key is pressed, an LCD back-light is switched on. If 5 seconds pass
- * // without a key being pressed, then the LCD back-light is switched off. In
- * // this case, the timer is a one-shot timer, and unlike the example given for
- * // the xTimerReset() function, the key press event handler is an interrupt
- * // service routine.
- *
- * // The callback function assigned to the one-shot timer. In this case the
- * // parameter is not used.
- * void vBacklightTimerCallback( xTIMER *pxTimer )
- * {
- * // The timer expired, therefore 5 seconds must have passed since a key
- * // was pressed. Switch off the LCD back-light.
- * vSetBacklightState( BACKLIGHT_OFF );
- * }
- *
- * // The key press interrupt service routine.
- * void vKeyPressEventInterruptHandler( void )
- * {
- * portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
- *
- * // Ensure the LCD back-light is on, then restart the timer that is
- * // responsible for turning the back-light off after 5 seconds of
- * // key inactivity. This is an interrupt service routine so can only
- * // call FreeRTOS API functions that end in "FromISR".
- * vSetBacklightState( BACKLIGHT_ON );
- *
- * // xTimerStartFromISR() or xTimerResetFromISR() could be called here
- * // as both cause the timer to re-calculate its expiry time.
- * // xHigherPriorityTaskWoken was initialised to pdFALSE when it was
- * // declared (in this function).
- * if( xTimerStartFromISR( xBacklightTimer, &xHigherPriorityTaskWoken ) != pdPASS )
- * {
- * // The start command was not executed successfully. Take appropriate
- * // action here.
- * }
- *
- * // Perform the rest of the key processing here.
- *
- * // If xHigherPriorityTaskWoken equals pdTRUE, then a context switch
- * // should be performed. The syntax required to perform a context switch
- * // from inside an ISR varies from port to port, and from compiler to
- * // compiler. Inspect the demos for the port you are using to find the
- * // actual syntax required.
- * if( xHigherPriorityTaskWoken != pdFALSE )
- * {
- * // Call the interrupt safe yield function here (actual function
- * // depends on the FreeRTOS port being used.
- * }
- * }
- */
-#define xTimerStartFromISR( xTimer, pxHigherPriorityTaskWoken ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_START, ( xTaskGetTickCountFromISR() ), ( pxHigherPriorityTaskWoken ), 0U )
-
-/**
- * portBASE_TYPE xTimerStopFromISR( xTimerHandle xTimer,
- * portBASE_TYPE *pxHigherPriorityTaskWoken );
- *
- * A version of xTimerStop() that can be called from an interrupt service
- * routine.
- *
- * @param xTimer The handle of the timer being stopped.
- *
- * @param pxHigherPriorityTaskWoken The timer service/daemon task spends most
- * of its time in the Blocked state, waiting for messages to arrive on the timer
- * command queue. Calling xTimerStopFromISR() writes a message to the timer
- * command queue, so has the potential to transition the timer service/daemon
- * task out of the Blocked state. If calling xTimerStopFromISR() causes the
- * timer service/daemon task to leave the Blocked state, and the timer service/
- * daemon task has a priority equal to or greater than the currently executing
- * task (the task that was interrupted), then *pxHigherPriorityTaskWoken will
- * get set to pdTRUE internally within the xTimerStopFromISR() function. If
- * xTimerStopFromISR() sets this value to pdTRUE then a context switch should
- * be performed before the interrupt exits.
- *
- * @return pdFAIL will be returned if the stop command could not be sent to
- * the timer command queue. pdPASS will be returned if the command was
- * successfully sent to the timer command queue. When the command is actually
- * processed will depend on the priority of the timer service/daemon task
- * relative to other tasks in the system. The timer service/daemon task
- * priority is set by the configTIMER_TASK_PRIORITY configuration constant.
- *
- * Example usage:
- *
- * // This scenario assumes xTimer has already been created and started. When
- * // an interrupt occurs, the timer should be simply stopped.
- *
- * // The interrupt service routine that stops the timer.
- * void vAnExampleInterruptServiceRoutine( void )
- * {
- * portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
- *
- * // The interrupt has occurred - simply stop the timer.
- * // xHigherPriorityTaskWoken was set to pdFALSE where it was defined
- * // (within this function). As this is an interrupt service routine, only
- * // FreeRTOS API functions that end in "FromISR" can be used.
- * if( xTimerStopFromISR( xTimer, &xHigherPriorityTaskWoken ) != pdPASS )
- * {
- * // The stop command was not executed successfully. Take appropriate
- * // action here.
- * }
- *
- * // If xHigherPriorityTaskWoken equals pdTRUE, then a context switch
- * // should be performed. The syntax required to perform a context switch
- * // from inside an ISR varies from port to port, and from compiler to
- * // compiler. Inspect the demos for the port you are using to find the
- * // actual syntax required.
- * if( xHigherPriorityTaskWoken != pdFALSE )
- * {
- * // Call the interrupt safe yield function here (actual function
- * // depends on the FreeRTOS port being used.
- * }
- * }
- */
-#define xTimerStopFromISR( xTimer, pxHigherPriorityTaskWoken ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_STOP, 0, ( pxHigherPriorityTaskWoken ), 0U )
-
-/**
- * portBASE_TYPE xTimerChangePeriodFromISR( xTimerHandle xTimer,
- * portTickType xNewPeriod,
- * portBASE_TYPE *pxHigherPriorityTaskWoken );
- *
- * A version of xTimerChangePeriod() that can be called from an interrupt
- * service routine.
- *
- * @param xTimer The handle of the timer that is having its period changed.
- *
- * @param xNewPeriod The new period for xTimer. Timer periods are specified in
- * tick periods, so the constant portTICK_RATE_MS can be used to convert a time
- * that has been specified in milliseconds. For example, if the timer must
- * expire after 100 ticks, then xNewPeriod should be set to 100. Alternatively,
- * if the timer must expire after 500ms, then xNewPeriod can be set to
- * ( 500 / portTICK_RATE_MS ) provided configTICK_RATE_HZ is less than
- * or equal to 1000.
- *
- * @param pxHigherPriorityTaskWoken The timer service/daemon task spends most
- * of its time in the Blocked state, waiting for messages to arrive on the timer
- * command queue. Calling xTimerChangePeriodFromISR() writes a message to the
- * timer command queue, so has the potential to transition the timer service/
- * daemon task out of the Blocked state. If calling xTimerChangePeriodFromISR()
- * causes the timer service/daemon task to leave the Blocked state, and the
- * timer service/daemon task has a priority equal to or greater than the
- * currently executing task (the task that was interrupted), then
- * *pxHigherPriorityTaskWoken will get set to pdTRUE internally within the
- * xTimerChangePeriodFromISR() function. If xTimerChangePeriodFromISR() sets
- * this value to pdTRUE then a context switch should be performed before the
- * interrupt exits.
- *
- * @return pdFAIL will be returned if the command to change the timers period
- * could not be sent to the timer command queue. pdPASS will be returned if the
- * command was successfully sent to the timer command queue. When the command
- * is actually processed will depend on the priority of the timer service/daemon
- * task relative to other tasks in the system. The timer service/daemon task
- * priority is set by the configTIMER_TASK_PRIORITY configuration constant.
- *
- * Example usage:
- *
- * // This scenario assumes xTimer has already been created and started. When
- * // an interrupt occurs, the period of xTimer should be changed to 500ms.
- *
- * // The interrupt service routine that changes the period of xTimer.
- * void vAnExampleInterruptServiceRoutine( void )
- * {
- * portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
- *
- * // The interrupt has occurred - change the period of xTimer to 500ms.
- * // xHigherPriorityTaskWoken was set to pdFALSE where it was defined
- * // (within this function). As this is an interrupt service routine, only
- * // FreeRTOS API functions that end in "FromISR" can be used.
- * if( xTimerChangePeriodFromISR( xTimer, &xHigherPriorityTaskWoken ) != pdPASS )
- * {
- * // The command to change the timers period was not executed
- * // successfully. Take appropriate action here.
- * }
- *
- * // If xHigherPriorityTaskWoken equals pdTRUE, then a context switch
- * // should be performed. The syntax required to perform a context switch
- * // from inside an ISR varies from port to port, and from compiler to
- * // compiler. Inspect the demos for the port you are using to find the
- * // actual syntax required.
- * if( xHigherPriorityTaskWoken != pdFALSE )
- * {
- * // Call the interrupt safe yield function here (actual function
- * // depends on the FreeRTOS port being used.
- * }
- * }
- */
-#define xTimerChangePeriodFromISR( xTimer, xNewPeriod, pxHigherPriorityTaskWoken ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_CHANGE_PERIOD, ( xNewPeriod ), ( pxHigherPriorityTaskWoken ), 0U )
-
-/**
- * portBASE_TYPE xTimerResetFromISR( xTimerHandle xTimer,
- * portBASE_TYPE *pxHigherPriorityTaskWoken );
- *
- * A version of xTimerReset() that can be called from an interrupt service
- * routine.
- *
- * @param xTimer The handle of the timer that is to be started, reset, or
- * restarted.
- *
- * @param pxHigherPriorityTaskWoken The timer service/daemon task spends most
- * of its time in the Blocked state, waiting for messages to arrive on the timer
- * command queue. Calling xTimerResetFromISR() writes a message to the timer
- * command queue, so has the potential to transition the timer service/daemon
- * task out of the Blocked state. If calling xTimerResetFromISR() causes the
- * timer service/daemon task to leave the Blocked state, and the timer service/
- * daemon task has a priority equal to or greater than the currently executing
- * task (the task that was interrupted), then *pxHigherPriorityTaskWoken will
- * get set to pdTRUE internally within the xTimerResetFromISR() function. If
- * xTimerResetFromISR() sets this value to pdTRUE then a context switch should
- * be performed before the interrupt exits.
- *
- * @return pdFAIL will be returned if the reset command could not be sent to
- * the timer command queue. pdPASS will be returned if the command was
- * successfully sent to the timer command queue. When the command is actually
- * processed will depend on the priority of the timer service/daemon task
- * relative to other tasks in the system, although the timers expiry time is
- * relative to when xTimerResetFromISR() is actually called. The timer service/daemon
- * task priority is set by the configTIMER_TASK_PRIORITY configuration constant.
- *
- * Example usage:
- *
- * // This scenario assumes xBacklightTimer has already been created. When a
- * // key is pressed, an LCD back-light is switched on. If 5 seconds pass
- * // without a key being pressed, then the LCD back-light is switched off. In
- * // this case, the timer is a one-shot timer, and unlike the example given for
- * // the xTimerReset() function, the key press event handler is an interrupt
- * // service routine.
- *
- * // The callback function assigned to the one-shot timer. In this case the
- * // parameter is not used.
- * void vBacklightTimerCallback( xTIMER *pxTimer )
- * {
- * // The timer expired, therefore 5 seconds must have passed since a key
- * // was pressed. Switch off the LCD back-light.
- * vSetBacklightState( BACKLIGHT_OFF );
- * }
- *
- * // The key press interrupt service routine.
- * void vKeyPressEventInterruptHandler( void )
- * {
- * portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
- *
- * // Ensure the LCD back-light is on, then reset the timer that is
- * // responsible for turning the back-light off after 5 seconds of
- * // key inactivity. This is an interrupt service routine so can only
- * // call FreeRTOS API functions that end in "FromISR".
- * vSetBacklightState( BACKLIGHT_ON );
- *
- * // xTimerStartFromISR() or xTimerResetFromISR() could be called here
- * // as both cause the timer to re-calculate its expiry time.
- * // xHigherPriorityTaskWoken was initialised to pdFALSE when it was
- * // declared (in this function).
- * if( xTimerResetFromISR( xBacklightTimer, &xHigherPriorityTaskWoken ) != pdPASS )
- * {
- * // The reset command was not executed successfully. Take appropriate
- * // action here.
- * }
- *
- * // Perform the rest of the key processing here.
- *
- * // If xHigherPriorityTaskWoken equals pdTRUE, then a context switch
- * // should be performed. The syntax required to perform a context switch
- * // from inside an ISR varies from port to port, and from compiler to
- * // compiler. Inspect the demos for the port you are using to find the
- * // actual syntax required.
- * if( xHigherPriorityTaskWoken != pdFALSE )
- * {
- * // Call the interrupt safe yield function here (actual function
- * // depends on the FreeRTOS port being used.
- * }
- * }
- */
-#define xTimerResetFromISR( xTimer, pxHigherPriorityTaskWoken ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_START, ( xTaskGetTickCountFromISR() ), ( pxHigherPriorityTaskWoken ), 0U )
-
-/*
- * Functions beyond this part are not part of the public API and are intended
- * for use by the kernel only.
- */
-portBASE_TYPE xTimerCreateTimerTask( void ) PRIVILEGED_FUNCTION;
-portBASE_TYPE xTimerGenericCommand( xTimerHandle xTimer, portBASE_TYPE xCommandID, portTickType xOptionalValue, portBASE_TYPE *pxHigherPriorityTaskWoken, portTickType xBlockTime ) PRIVILEGED_FUNCTION;
-
-#ifdef __cplusplus
-}
-#endif
-#endif /* TIMERS_H */
-
-
-
+/*
+ FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.
+
+
+ FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:
+ Atollic AB - Atollic provides professional embedded systems development
+ tools for C/C++ development, code analysis and test automation.
+ See http://www.atollic.com
+
+
+ ***************************************************************************
+ * *
+ * FreeRTOS tutorial books are available in pdf and paperback. *
+ * Complete, revised, and edited pdf reference manuals are also *
+ * available. *
+ * *
+ * Purchasing FreeRTOS documentation will not only help you, by *
+ * ensuring you get running as quickly as possible and with an *
+ * in-depth knowledge of how to use FreeRTOS, it will also help *
+ * the FreeRTOS project to continue with its mission of providing *
+ * professional grade, cross platform, de facto standard solutions *
+ * for microcontrollers - completely free of charge! *
+ * *
+ * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
+ * *
+ * Thank you for using FreeRTOS, and thank you for your support! *
+ * *
+ ***************************************************************************
+
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
+ >>>NOTE<<< The modification to the GPL is included to allow you to
+ distribute a combined work that includes FreeRTOS without being obliged to
+ provide the source code for proprietary components outside of the FreeRTOS
+ kernel. FreeRTOS is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details. You should have received a copy of the GNU General Public
+ License and the FreeRTOS license exception along with FreeRTOS; if not it
+ can be viewed here: http://www.freertos.org/a00114.html and also obtained
+ by writing to Richard Barry, contact details for whom are available on the
+ FreeRTOS WEB site.
+
+ 1 tab == 4 spaces!
+
+ http://www.FreeRTOS.org - Documentation, latest information, license and
+ contact details.
+
+ http://www.SafeRTOS.com - A version that is certified for use in safety
+ critical systems.
+
+ http://www.OpenRTOS.com - Commercial support, development, porting,
+ licensing and training services.
+*/
+
+
+#ifndef TIMERS_H
+#define TIMERS_H
+
+#ifndef INC_FREERTOS_H
+ #error "include FreeRTOS.h must appear in source files before include timers.h"
+#endif
+
+#include "portable.h"
+#include "list.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* IDs for commands that can be sent/received on the timer queue. These are to
+be used solely through the macros that make up the public software timer API,
+as defined below. */
+#define tmrCOMMAND_START 0
+#define tmrCOMMAND_STOP 1
+#define tmrCOMMAND_CHANGE_PERIOD 2
+#define tmrCOMMAND_DELETE 3
+
+/*-----------------------------------------------------------
+ * MACROS AND DEFINITIONS
+ *----------------------------------------------------------*/
+
+ /**
+ * Type by which software timers are referenced. For example, a call to
+ * xTimerCreate() returns an xTimerHandle variable that can then be used to
+ * reference the subject timer in calls to other software timer API functions
+ * (for example, xTimerStart(), xTimerReset(), etc.).
+ */
+typedef void * xTimerHandle;
+
+/* Define the prototype to which timer callback functions must conform. */
+typedef void (*tmrTIMER_CALLBACK)( xTimerHandle xTimer );
+
+/**
+ * xTimerHandle xTimerCreate( const signed char *pcTimerName,
+ * portTickType xTimerPeriod,
+ * unsigned portBASE_TYPE uxAutoReload,
+ * void * pvTimerID,
+ * tmrTIMER_CALLBACK pxCallbackFunction );
+ *
+ * Creates a new software timer instance. This allocates the storage required
+ * by the new timer, initialises the new timers internal state, and returns a
+ * handle by which the new timer can be referenced.
+ *
+ * Timers are created in the dormant state. The xTimerStart(), xTimerReset(),
+ * xTimerStartFromISR(), xTimerResetFromISR(), xTimerChangePeriod() and
+ * xTimerChangePeriodFromISR() API functions can all be used to transition a timer into the
+ * active state.
+ *
+ * @param pcTimerName A text name that is assigned to the timer. This is done
+ * purely to assist debugging. The kernel itself only ever references a timer by
+ * its handle, and never by its name.
+ *
+ * @param xTimerPeriod The timer period. The time is defined in tick periods so
+ * the constant portTICK_RATE_MS can be used to convert a time that has been
+ * specified in milliseconds. For example, if the timer must expire after 100
+ * ticks, then xTimerPeriod should be set to 100. Alternatively, if the timer
+ * must expire after 500ms, then xPeriod can be set to ( 500 / portTICK_RATE_MS )
+ * provided configTICK_RATE_HZ is less than or equal to 1000.
+ *
+ * @param uxAutoReload If uxAutoReload is set to pdTRUE then the timer will
+ * expire repeatedly with a frequency set by the xTimerPeriod parameter. If
+ * uxAutoReload is set to pdFALSE then the timer will be a one-shot timer and
+ * enter the dormant state after it expires.
+ *
+ * @param pvTimerID An identifier that is assigned to the timer being created.
+ * Typically this would be used in the timer callback function to identify which
+ * timer expired when the same callback function is assigned to more than one
+ * timer.
+ *
+ * @param pxCallbackFunction The function to call when the timer expires.
+ * Callback functions must have the prototype defined by tmrTIMER_CALLBACK,
+ * which is "void vCallbackFunction( xTIMER *xTimer );".
+ *
+ * @return If the timer is successfully create then a handle to the newly
+ * created timer is returned. If the timer cannot be created (because either
+ * there is insufficient FreeRTOS heap remaining to allocate the timer
+ * structures, or the timer period was set to 0) then 0 is returned.
+ *
+ * Example usage:
+ *
+ *
+ * #define NUM_TIMERS 5
+ *
+ * // An array to hold handles to the created timers.
+ * xTimerHandle xTimers[ NUM_TIMERS ];
+ *
+ * // An array to hold a count of the number of times each timer expires.
+ * long lExpireCounters[ NUM_TIMERS ] = { 0 };
+ *
+ * // Define a callback function that will be used by multiple timer instances.
+ * // The callback function does nothing but count the number of times the
+ * // associated timer expires, and stop the timer once the timer has expired
+ * // 10 times.
+ * void vTimerCallback( xTIMER *pxTimer )
+ * {
+ * long lArrayIndex;
+ * const long xMaxExpiryCountBeforeStopping = 10;
+ *
+ * // Optionally do something if the pxTimer parameter is NULL.
+ * configASSERT( pxTimer );
+ *
+ * // Which timer expired?
+ * lArrayIndex = ( long ) pvTimerGetTimerID( pxTimer );
+ *
+ * // Increment the number of times that pxTimer has expired.
+ * lExpireCounters[ lArrayIndex ] += 1;
+ *
+ * // If the timer has expired 10 times then stop it from running.
+ * if( lExpireCounters[ lArrayIndex ] == xMaxExpiryCountBeforeStopping )
+ * {
+ * // Do not use a block time if calling a timer API function from a
+ * // timer callback function, as doing so could cause a deadlock!
+ * xTimerStop( pxTimer, 0 );
+ * }
+ * }
+ *
+ * void main( void )
+ * {
+ * long x;
+ *
+ * // Create then start some timers. Starting the timers before the scheduler
+ * // has been started means the timers will start running immediately that
+ * // the scheduler starts.
+ * for( x = 0; x < NUM_TIMERS; x++ )
+ * {
+ * xTimers[ x ] = xTimerCreate( "Timer", // Just a text name, not used by the kernel.
+ * ( 100 * x ), // The timer period in ticks.
+ * pdTRUE, // The timers will auto-reload themselves when they expire.
+ * ( void * ) x, // Assign each timer a unique id equal to its array index.
+ * vTimerCallback // Each timer calls the same callback when it expires.
+ * );
+ *
+ * if( xTimers[ x ] == NULL )
+ * {
+ * // The timer was not created.
+ * }
+ * else
+ * {
+ * // Start the timer. No block time is specified, and even if one was
+ * // it would be ignored because the scheduler has not yet been
+ * // started.
+ * if( xTimerStart( xTimers[ x ], 0 ) != pdPASS )
+ * {
+ * // The timer could not be set into the Active state.
+ * }
+ * }
+ * }
+ *
+ * // ...
+ * // Create tasks here.
+ * // ...
+ *
+ * // Starting the scheduler will start the timers running as they have already
+ * // been set into the active state.
+ * xTaskStartScheduler();
+ *
+ * // Should not reach here.
+ * for( ;; );
+ * }
+ */
+xTimerHandle xTimerCreate( const signed char *pcTimerName, portTickType xTimerPeriodInTicks, unsigned portBASE_TYPE uxAutoReload, void * pvTimerID, tmrTIMER_CALLBACK pxCallbackFunction ) PRIVILEGED_FUNCTION;
+
+/**
+ * void *pvTimerGetTimerID( xTimerHandle xTimer );
+ *
+ * Returns the ID assigned to the timer.
+ *
+ * IDs are assigned to timers using the pvTimerID parameter of the call to
+ * xTimerCreated() that was used to create the timer.
+ *
+ * If the same callback function is assigned to multiple timers then the timer
+ * ID can be used within the callback function to identify which timer actually
+ * expired.
+ *
+ * @param xTimer The timer being queried.
+ *
+ * @return The ID assigned to the timer being queried.
+ *
+ * Example usage:
+ *
+ * See the xTimerCreate() API function example usage scenario.
+ */
+void *pvTimerGetTimerID( xTimerHandle xTimer ) PRIVILEGED_FUNCTION;
+
+/**
+ * portBASE_TYPE xTimerIsTimerActive( xTimerHandle xTimer );
+ *
+ * Queries a timer to see if it is active or dormant.
+ *
+ * A timer will be dormant if:
+ * 1) It has been created but not started, or
+ * 2) It is an expired on-shot timer that has not been restarted.
+ *
+ * Timers are created in the dormant state. The xTimerStart(), xTimerReset(),
+ * xTimerStartFromISR(), xTimerResetFromISR(), xTimerChangePeriod() and
+ * xTimerChangePeriodFromISR() API functions can all be used to transition a timer into the
+ * active state.
+ *
+ * @param xTimer The timer being queried.
+ *
+ * @return pdFALSE will be returned if the timer is dormant. A value other than
+ * pdFALSE will be returned if the timer is active.
+ *
+ * Example usage:
+ *
+ * // This function assumes xTimer has already been created.
+ * void vAFunction( xTimerHandle xTimer )
+ * {
+ * if( xTimerIsTimerActive( xTimer ) != pdFALSE ) // or more simply and equivalently "if( xTimerIsTimerActive( xTimer ) )"
+ * {
+ * // xTimer is active, do something.
+ * }
+ * else
+ * {
+ * // xTimer is not active, do something else.
+ * }
+ * }
+ */
+portBASE_TYPE xTimerIsTimerActive( xTimerHandle xTimer ) PRIVILEGED_FUNCTION;
+
+/**
+ * portBASE_TYPE xTimerStart( xTimerHandle xTimer, portTickType xBlockTime );
+ *
+ * Timer functionality is provided by a timer service/daemon task. Many of the
+ * public FreeRTOS timer API functions send commands to the timer service task
+ * though a queue called the timer command queue. The timer command queue is
+ * private to the kernel itself and is not directly accessible to application
+ * code. The length of the timer command queue is set by the
+ * configTIMER_QUEUE_LENGTH configuration constant.
+ *
+ * xTimerStart() starts a timer that was previously created using the
+ * xTimerCreate() API function. If the timer had already been started and was
+ * already in the active state, then xTimerStart() has equivalent functionality
+ * to the xTimerReset() API function.
+ *
+ * Starting a timer ensures the timer is in the active state. If the timer
+ * is not stopped, deleted, or reset in the mean time, the callback function
+ * associated with the timer will get called 'n' ticks after xTimerStart() was
+ * called, where 'n' is the timers defined period.
+ *
+ * It is valid to call xTimerStart() before the scheduler has been started, but
+ * when this is done the timer will not actually start until the scheduler is
+ * started, and the timers expiry time will be relative to when the scheduler is
+ * started, not relative to when xTimerStart() was called.
+ *
+ * The configUSE_TIMERS configuration constant must be set to 1 for xTimerStart()
+ * to be available.
+ *
+ * @param xTimer The handle of the timer being started/restarted.
+ *
+ * @param xBlockTime Specifies the time, in ticks, that the calling task should
+ * be held in the Blocked state to wait for the start command to be successfully
+ * sent to the timer command queue, should the queue already be full when
+ * xTimerStart() was called. xBlockTime is ignored if xTimerStart() is called
+ * before the scheduler is started.
+ *
+ * @return pdFAIL will be returned if the start command could not be sent to
+ * the timer command queue even after xBlockTime ticks had passed. pdPASS will
+ * be returned if the command was successfully sent to the timer command queue.
+ * When the command is actually processed will depend on the priority of the
+ * timer service/daemon task relative to other tasks in the system, although the
+ * timers expiry time is relative to when xTimerStart() is actually called. The
+ * timer service/daemon task priority is set by the configTIMER_TASK_PRIORITY
+ * configuration constant.
+ *
+ * Example usage:
+ *
+ * See the xTimerCreate() API function example usage scenario.
+ *
+ */
+#define xTimerStart( xTimer, xBlockTime ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_START, ( xTaskGetTickCount() ), NULL, ( xBlockTime ) )
+
+/**
+ * portBASE_TYPE xTimerStop( xTimerHandle xTimer, portTickType xBlockTime );
+ *
+ * Timer functionality is provided by a timer service/daemon task. Many of the
+ * public FreeRTOS timer API functions send commands to the timer service task
+ * though a queue called the timer command queue. The timer command queue is
+ * private to the kernel itself and is not directly accessible to application
+ * code. The length of the timer command queue is set by the
+ * configTIMER_QUEUE_LENGTH configuration constant.
+ *
+ * xTimerStop() stops a timer that was previously started using either of the
+ * The xTimerStart(), xTimerReset(), xTimerStartFromISR(), xTimerResetFromISR(),
+ * xTimerChangePeriod() or xTimerChangePeriodFromISR() API functions.
+ *
+ * Stopping a timer ensures the timer is not in the active state.
+ *
+ * The configUSE_TIMERS configuration constant must be set to 1 for xTimerStop()
+ * to be available.
+ *
+ * @param xTimer The handle of the timer being stopped.
+ *
+ * @param xBlockTime Specifies the time, in ticks, that the calling task should
+ * be held in the Blocked state to wait for the stop command to be successfully
+ * sent to the timer command queue, should the queue already be full when
+ * xTimerStop() was called. xBlockTime is ignored if xTimerStop() is called
+ * before the scheduler is started.
+ *
+ * @return pdFAIL will be returned if the stop command could not be sent to
+ * the timer command queue even after xBlockTime ticks had passed. pdPASS will
+ * be returned if the command was successfully sent to the timer command queue.
+ * When the command is actually processed will depend on the priority of the
+ * timer service/daemon task relative to other tasks in the system. The timer
+ * service/daemon task priority is set by the configTIMER_TASK_PRIORITY
+ * configuration constant.
+ *
+ * Example usage:
+ *
+ * See the xTimerCreate() API function example usage scenario.
+ *
+ */
+#define xTimerStop( xTimer, xBlockTime ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_STOP, 0U, NULL, ( xBlockTime ) )
+
+/**
+ * portBASE_TYPE xTimerChangePeriod( xTimerHandle xTimer,
+ * portTickType xNewPeriod,
+ * portTickType xBlockTime );
+ *
+ * Timer functionality is provided by a timer service/daemon task. Many of the
+ * public FreeRTOS timer API functions send commands to the timer service task
+ * though a queue called the timer command queue. The timer command queue is
+ * private to the kernel itself and is not directly accessible to application
+ * code. The length of the timer command queue is set by the
+ * configTIMER_QUEUE_LENGTH configuration constant.
+ *
+ * xTimerChangePeriod() changes the period of a timer that was previously
+ * created using the xTimerCreate() API function.
+ *
+ * xTimerChangePeriod() can be called to change the period of an active or
+ * dormant state timer.
+ *
+ * The configUSE_TIMERS configuration constant must be set to 1 for
+ * xTimerChangePeriod() to be available.
+ *
+ * @param xTimer The handle of the timer that is having its period changed.
+ *
+ * @param xNewPeriod The new period for xTimer. Timer periods are specified in
+ * tick periods, so the constant portTICK_RATE_MS can be used to convert a time
+ * that has been specified in milliseconds. For example, if the timer must
+ * expire after 100 ticks, then xNewPeriod should be set to 100. Alternatively,
+ * if the timer must expire after 500ms, then xNewPeriod can be set to
+ * ( 500 / portTICK_RATE_MS ) provided configTICK_RATE_HZ is less than
+ * or equal to 1000.
+ *
+ * @param xBlockTime Specifies the time, in ticks, that the calling task should
+ * be held in the Blocked state to wait for the change period command to be
+ * successfully sent to the timer command queue, should the queue already be
+ * full when xTimerChangePeriod() was called. xBlockTime is ignored if
+ * xTimerChangePeriod() is called before the scheduler is started.
+ *
+ * @return pdFAIL will be returned if the change period command could not be
+ * sent to the timer command queue even after xBlockTime ticks had passed.
+ * pdPASS will be returned if the command was successfully sent to the timer
+ * command queue. When the command is actually processed will depend on the
+ * priority of the timer service/daemon task relative to other tasks in the
+ * system. The timer service/daemon task priority is set by the
+ * configTIMER_TASK_PRIORITY configuration constant.
+ *
+ * Example usage:
+ *
+ * // This function assumes xTimer has already been created. If the timer
+ * // referenced by xTimer is already active when it is called, then the timer
+ * // is deleted. If the timer referenced by xTimer is not active when it is
+ * // called, then the period of the timer is set to 500ms and the timer is
+ * // started.
+ * void vAFunction( xTimerHandle xTimer )
+ * {
+ * if( xTimerIsTimerActive( xTimer ) != pdFALSE ) // or more simply and equivalently "if( xTimerIsTimerActive( xTimer ) )"
+ * {
+ * // xTimer is already active - delete it.
+ * xTimerDelete( xTimer );
+ * }
+ * else
+ * {
+ * // xTimer is not active, change its period to 500ms. This will also
+ * // cause the timer to start. Block for a maximum of 100 ticks if the
+ * // change period command cannot immediately be sent to the timer
+ * // command queue.
+ * if( xTimerChangePeriod( xTimer, 500 / portTICK_RATE_MS, 100 ) == pdPASS )
+ * {
+ * // The command was successfully sent.
+ * }
+ * else
+ * {
+ * // The command could not be sent, even after waiting for 100 ticks
+ * // to pass. Take appropriate action here.
+ * }
+ * }
+ * }
+ */
+ #define xTimerChangePeriod( xTimer, xNewPeriod, xBlockTime ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_CHANGE_PERIOD, ( xNewPeriod ), NULL, ( xBlockTime ) )
+
+/**
+ * portBASE_TYPE xTimerDelete( xTimerHandle xTimer, portTickType xBlockTime );
+ *
+ * Timer functionality is provided by a timer service/daemon task. Many of the
+ * public FreeRTOS timer API functions send commands to the timer service task
+ * though a queue called the timer command queue. The timer command queue is
+ * private to the kernel itself and is not directly accessible to application
+ * code. The length of the timer command queue is set by the
+ * configTIMER_QUEUE_LENGTH configuration constant.
+ *
+ * xTimerDelete() deletes a timer that was previously created using the
+ * xTimerCreate() API function.
+ *
+ * The configUSE_TIMERS configuration constant must be set to 1 for
+ * xTimerDelete() to be available.
+ *
+ * @param xTimer The handle of the timer being deleted.
+ *
+ * @param xBlockTime Specifies the time, in ticks, that the calling task should
+ * be held in the Blocked state to wait for the delete command to be
+ * successfully sent to the timer command queue, should the queue already be
+ * full when xTimerDelete() was called. xBlockTime is ignored if xTimerDelete()
+ * is called before the scheduler is started.
+ *
+ * @return pdFAIL will be returned if the delete command could not be sent to
+ * the timer command queue even after xBlockTime ticks had passed. pdPASS will
+ * be returned if the command was successfully sent to the timer command queue.
+ * When the command is actually processed will depend on the priority of the
+ * timer service/daemon task relative to other tasks in the system. The timer
+ * service/daemon task priority is set by the configTIMER_TASK_PRIORITY
+ * configuration constant.
+ *
+ * Example usage:
+ *
+ * See the xTimerChangePeriod() API function example usage scenario.
+ */
+#define xTimerDelete( xTimer, xBlockTime ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_DELETE, 0U, NULL, ( xBlockTime ) )
+
+/**
+ * portBASE_TYPE xTimerReset( xTimerHandle xTimer, portTickType xBlockTime );
+ *
+ * Timer functionality is provided by a timer service/daemon task. Many of the
+ * public FreeRTOS timer API functions send commands to the timer service task
+ * though a queue called the timer command queue. The timer command queue is
+ * private to the kernel itself and is not directly accessible to application
+ * code. The length of the timer command queue is set by the
+ * configTIMER_QUEUE_LENGTH configuration constant.
+ *
+ * xTimerReset() re-starts a timer that was previously created using the
+ * xTimerCreate() API function. If the timer had already been started and was
+ * already in the active state, then xTimerReset() will cause the timer to
+ * re-evaluate its expiry time so that it is relative to when xTimerReset() was
+ * called. If the timer was in the dormant state then xTimerReset() has
+ * equivalent functionality to the xTimerStart() API function.
+ *
+ * Resetting a timer ensures the timer is in the active state. If the timer
+ * is not stopped, deleted, or reset in the mean time, the callback function
+ * associated with the timer will get called 'n' ticks after xTimerReset() was
+ * called, where 'n' is the timers defined period.
+ *
+ * It is valid to call xTimerReset() before the scheduler has been started, but
+ * when this is done the timer will not actually start until the scheduler is
+ * started, and the timers expiry time will be relative to when the scheduler is
+ * started, not relative to when xTimerReset() was called.
+ *
+ * The configUSE_TIMERS configuration constant must be set to 1 for xTimerReset()
+ * to be available.
+ *
+ * @param xTimer The handle of the timer being reset/started/restarted.
+ *
+ * @param xBlockTime Specifies the time, in ticks, that the calling task should
+ * be held in the Blocked state to wait for the reset command to be successfully
+ * sent to the timer command queue, should the queue already be full when
+ * xTimerReset() was called. xBlockTime is ignored if xTimerReset() is called
+ * before the scheduler is started.
+ *
+ * @return pdFAIL will be returned if the reset command could not be sent to
+ * the timer command queue even after xBlockTime ticks had passed. pdPASS will
+ * be returned if the command was successfully sent to the timer command queue.
+ * When the command is actually processed will depend on the priority of the
+ * timer service/daemon task relative to other tasks in the system, although the
+ * timers expiry time is relative to when xTimerStart() is actually called. The
+ * timer service/daemon task priority is set by the configTIMER_TASK_PRIORITY
+ * configuration constant.
+ *
+ * Example usage:
+ *
+ * // When a key is pressed, an LCD back-light is switched on. If 5 seconds pass
+ * // without a key being pressed, then the LCD back-light is switched off. In
+ * // this case, the timer is a one-shot timer.
+ *
+ * xTimerHandle xBacklightTimer = NULL;
+ *
+ * // The callback function assigned to the one-shot timer. In this case the
+ * // parameter is not used.
+ * void vBacklightTimerCallback( xTIMER *pxTimer )
+ * {
+ * // The timer expired, therefore 5 seconds must have passed since a key
+ * // was pressed. Switch off the LCD back-light.
+ * vSetBacklightState( BACKLIGHT_OFF );
+ * }
+ *
+ * // The key press event handler.
+ * void vKeyPressEventHandler( char cKey )
+ * {
+ * // Ensure the LCD back-light is on, then reset the timer that is
+ * // responsible for turning the back-light off after 5 seconds of
+ * // key inactivity. Wait 10 ticks for the command to be successfully sent
+ * // if it cannot be sent immediately.
+ * vSetBacklightState( BACKLIGHT_ON );
+ * if( xTimerReset( xBacklightTimer, 100 ) != pdPASS )
+ * {
+ * // The reset command was not executed successfully. Take appropriate
+ * // action here.
+ * }
+ *
+ * // Perform the rest of the key processing here.
+ * }
+ *
+ * void main( void )
+ * {
+ * long x;
+ *
+ * // Create then start the one-shot timer that is responsible for turning
+ * // the back-light off if no keys are pressed within a 5 second period.
+ * xBacklightTimer = xTimerCreate( "BacklightTimer", // Just a text name, not used by the kernel.
+ * ( 5000 / portTICK_RATE_MS), // The timer period in ticks.
+ * pdFALSE, // The timer is a one-shot timer.
+ * 0, // The id is not used by the callback so can take any value.
+ * vBacklightTimerCallback // The callback function that switches the LCD back-light off.
+ * );
+ *
+ * if( xBacklightTimer == NULL )
+ * {
+ * // The timer was not created.
+ * }
+ * else
+ * {
+ * // Start the timer. No block time is specified, and even if one was
+ * // it would be ignored because the scheduler has not yet been
+ * // started.
+ * if( xTimerStart( xBacklightTimer, 0 ) != pdPASS )
+ * {
+ * // The timer could not be set into the Active state.
+ * }
+ * }
+ *
+ * // ...
+ * // Create tasks here.
+ * // ...
+ *
+ * // Starting the scheduler will start the timer running as it has already
+ * // been set into the active state.
+ * xTaskStartScheduler();
+ *
+ * // Should not reach here.
+ * for( ;; );
+ * }
+ */
+#define xTimerReset( xTimer, xBlockTime ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_START, ( xTaskGetTickCount() ), NULL, ( xBlockTime ) )
+
+/**
+ * portBASE_TYPE xTimerStartFromISR( xTimerHandle xTimer,
+ * portBASE_TYPE *pxHigherPriorityTaskWoken );
+ *
+ * A version of xTimerStart() that can be called from an interrupt service
+ * routine.
+ *
+ * @param xTimer The handle of the timer being started/restarted.
+ *
+ * @param pxHigherPriorityTaskWoken The timer service/daemon task spends most
+ * of its time in the Blocked state, waiting for messages to arrive on the timer
+ * command queue. Calling xTimerStartFromISR() writes a message to the timer
+ * command queue, so has the potential to transition the timer service/daemon
+ * task out of the Blocked state. If calling xTimerStartFromISR() causes the
+ * timer service/daemon task to leave the Blocked state, and the timer service/
+ * daemon task has a priority equal to or greater than the currently executing
+ * task (the task that was interrupted), then *pxHigherPriorityTaskWoken will
+ * get set to pdTRUE internally within the xTimerStartFromISR() function. If
+ * xTimerStartFromISR() sets this value to pdTRUE then a context switch should
+ * be performed before the interrupt exits.
+ *
+ * @return pdFAIL will be returned if the start command could not be sent to
+ * the timer command queue. pdPASS will be returned if the command was
+ * successfully sent to the timer command queue. When the command is actually
+ * processed will depend on the priority of the timer service/daemon task
+ * relative to other tasks in the system, although the timers expiry time is
+ * relative to when xTimerStartFromISR() is actually called. The timer service/daemon
+ * task priority is set by the configTIMER_TASK_PRIORITY configuration constant.
+ *
+ * Example usage:
+ *
+ * // This scenario assumes xBacklightTimer has already been created. When a
+ * // key is pressed, an LCD back-light is switched on. If 5 seconds pass
+ * // without a key being pressed, then the LCD back-light is switched off. In
+ * // this case, the timer is a one-shot timer, and unlike the example given for
+ * // the xTimerReset() function, the key press event handler is an interrupt
+ * // service routine.
+ *
+ * // The callback function assigned to the one-shot timer. In this case the
+ * // parameter is not used.
+ * void vBacklightTimerCallback( xTIMER *pxTimer )
+ * {
+ * // The timer expired, therefore 5 seconds must have passed since a key
+ * // was pressed. Switch off the LCD back-light.
+ * vSetBacklightState( BACKLIGHT_OFF );
+ * }
+ *
+ * // The key press interrupt service routine.
+ * void vKeyPressEventInterruptHandler( void )
+ * {
+ * portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
+ *
+ * // Ensure the LCD back-light is on, then restart the timer that is
+ * // responsible for turning the back-light off after 5 seconds of
+ * // key inactivity. This is an interrupt service routine so can only
+ * // call FreeRTOS API functions that end in "FromISR".
+ * vSetBacklightState( BACKLIGHT_ON );
+ *
+ * // xTimerStartFromISR() or xTimerResetFromISR() could be called here
+ * // as both cause the timer to re-calculate its expiry time.
+ * // xHigherPriorityTaskWoken was initialised to pdFALSE when it was
+ * // declared (in this function).
+ * if( xTimerStartFromISR( xBacklightTimer, &xHigherPriorityTaskWoken ) != pdPASS )
+ * {
+ * // The start command was not executed successfully. Take appropriate
+ * // action here.
+ * }
+ *
+ * // Perform the rest of the key processing here.
+ *
+ * // If xHigherPriorityTaskWoken equals pdTRUE, then a context switch
+ * // should be performed. The syntax required to perform a context switch
+ * // from inside an ISR varies from port to port, and from compiler to
+ * // compiler. Inspect the demos for the port you are using to find the
+ * // actual syntax required.
+ * if( xHigherPriorityTaskWoken != pdFALSE )
+ * {
+ * // Call the interrupt safe yield function here (actual function
+ * // depends on the FreeRTOS port being used.
+ * }
+ * }
+ */
+#define xTimerStartFromISR( xTimer, pxHigherPriorityTaskWoken ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_START, ( xTaskGetTickCountFromISR() ), ( pxHigherPriorityTaskWoken ), 0U )
+
+/**
+ * portBASE_TYPE xTimerStopFromISR( xTimerHandle xTimer,
+ * portBASE_TYPE *pxHigherPriorityTaskWoken );
+ *
+ * A version of xTimerStop() that can be called from an interrupt service
+ * routine.
+ *
+ * @param xTimer The handle of the timer being stopped.
+ *
+ * @param pxHigherPriorityTaskWoken The timer service/daemon task spends most
+ * of its time in the Blocked state, waiting for messages to arrive on the timer
+ * command queue. Calling xTimerStopFromISR() writes a message to the timer
+ * command queue, so has the potential to transition the timer service/daemon
+ * task out of the Blocked state. If calling xTimerStopFromISR() causes the
+ * timer service/daemon task to leave the Blocked state, and the timer service/
+ * daemon task has a priority equal to or greater than the currently executing
+ * task (the task that was interrupted), then *pxHigherPriorityTaskWoken will
+ * get set to pdTRUE internally within the xTimerStopFromISR() function. If
+ * xTimerStopFromISR() sets this value to pdTRUE then a context switch should
+ * be performed before the interrupt exits.
+ *
+ * @return pdFAIL will be returned if the stop command could not be sent to
+ * the timer command queue. pdPASS will be returned if the command was
+ * successfully sent to the timer command queue. When the command is actually
+ * processed will depend on the priority of the timer service/daemon task
+ * relative to other tasks in the system. The timer service/daemon task
+ * priority is set by the configTIMER_TASK_PRIORITY configuration constant.
+ *
+ * Example usage:
+ *
+ * // This scenario assumes xTimer has already been created and started. When
+ * // an interrupt occurs, the timer should be simply stopped.
+ *
+ * // The interrupt service routine that stops the timer.
+ * void vAnExampleInterruptServiceRoutine( void )
+ * {
+ * portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
+ *
+ * // The interrupt has occurred - simply stop the timer.
+ * // xHigherPriorityTaskWoken was set to pdFALSE where it was defined
+ * // (within this function). As this is an interrupt service routine, only
+ * // FreeRTOS API functions that end in "FromISR" can be used.
+ * if( xTimerStopFromISR( xTimer, &xHigherPriorityTaskWoken ) != pdPASS )
+ * {
+ * // The stop command was not executed successfully. Take appropriate
+ * // action here.
+ * }
+ *
+ * // If xHigherPriorityTaskWoken equals pdTRUE, then a context switch
+ * // should be performed. The syntax required to perform a context switch
+ * // from inside an ISR varies from port to port, and from compiler to
+ * // compiler. Inspect the demos for the port you are using to find the
+ * // actual syntax required.
+ * if( xHigherPriorityTaskWoken != pdFALSE )
+ * {
+ * // Call the interrupt safe yield function here (actual function
+ * // depends on the FreeRTOS port being used.
+ * }
+ * }
+ */
+#define xTimerStopFromISR( xTimer, pxHigherPriorityTaskWoken ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_STOP, 0, ( pxHigherPriorityTaskWoken ), 0U )
+
+/**
+ * portBASE_TYPE xTimerChangePeriodFromISR( xTimerHandle xTimer,
+ * portTickType xNewPeriod,
+ * portBASE_TYPE *pxHigherPriorityTaskWoken );
+ *
+ * A version of xTimerChangePeriod() that can be called from an interrupt
+ * service routine.
+ *
+ * @param xTimer The handle of the timer that is having its period changed.
+ *
+ * @param xNewPeriod The new period for xTimer. Timer periods are specified in
+ * tick periods, so the constant portTICK_RATE_MS can be used to convert a time
+ * that has been specified in milliseconds. For example, if the timer must
+ * expire after 100 ticks, then xNewPeriod should be set to 100. Alternatively,
+ * if the timer must expire after 500ms, then xNewPeriod can be set to
+ * ( 500 / portTICK_RATE_MS ) provided configTICK_RATE_HZ is less than
+ * or equal to 1000.
+ *
+ * @param pxHigherPriorityTaskWoken The timer service/daemon task spends most
+ * of its time in the Blocked state, waiting for messages to arrive on the timer
+ * command queue. Calling xTimerChangePeriodFromISR() writes a message to the
+ * timer command queue, so has the potential to transition the timer service/
+ * daemon task out of the Blocked state. If calling xTimerChangePeriodFromISR()
+ * causes the timer service/daemon task to leave the Blocked state, and the
+ * timer service/daemon task has a priority equal to or greater than the
+ * currently executing task (the task that was interrupted), then
+ * *pxHigherPriorityTaskWoken will get set to pdTRUE internally within the
+ * xTimerChangePeriodFromISR() function. If xTimerChangePeriodFromISR() sets
+ * this value to pdTRUE then a context switch should be performed before the
+ * interrupt exits.
+ *
+ * @return pdFAIL will be returned if the command to change the timers period
+ * could not be sent to the timer command queue. pdPASS will be returned if the
+ * command was successfully sent to the timer command queue. When the command
+ * is actually processed will depend on the priority of the timer service/daemon
+ * task relative to other tasks in the system. The timer service/daemon task
+ * priority is set by the configTIMER_TASK_PRIORITY configuration constant.
+ *
+ * Example usage:
+ *
+ * // This scenario assumes xTimer has already been created and started. When
+ * // an interrupt occurs, the period of xTimer should be changed to 500ms.
+ *
+ * // The interrupt service routine that changes the period of xTimer.
+ * void vAnExampleInterruptServiceRoutine( void )
+ * {
+ * portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
+ *
+ * // The interrupt has occurred - change the period of xTimer to 500ms.
+ * // xHigherPriorityTaskWoken was set to pdFALSE where it was defined
+ * // (within this function). As this is an interrupt service routine, only
+ * // FreeRTOS API functions that end in "FromISR" can be used.
+ * if( xTimerChangePeriodFromISR( xTimer, &xHigherPriorityTaskWoken ) != pdPASS )
+ * {
+ * // The command to change the timers period was not executed
+ * // successfully. Take appropriate action here.
+ * }
+ *
+ * // If xHigherPriorityTaskWoken equals pdTRUE, then a context switch
+ * // should be performed. The syntax required to perform a context switch
+ * // from inside an ISR varies from port to port, and from compiler to
+ * // compiler. Inspect the demos for the port you are using to find the
+ * // actual syntax required.
+ * if( xHigherPriorityTaskWoken != pdFALSE )
+ * {
+ * // Call the interrupt safe yield function here (actual function
+ * // depends on the FreeRTOS port being used.
+ * }
+ * }
+ */
+#define xTimerChangePeriodFromISR( xTimer, xNewPeriod, pxHigherPriorityTaskWoken ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_CHANGE_PERIOD, ( xNewPeriod ), ( pxHigherPriorityTaskWoken ), 0U )
+
+/**
+ * portBASE_TYPE xTimerResetFromISR( xTimerHandle xTimer,
+ * portBASE_TYPE *pxHigherPriorityTaskWoken );
+ *
+ * A version of xTimerReset() that can be called from an interrupt service
+ * routine.
+ *
+ * @param xTimer The handle of the timer that is to be started, reset, or
+ * restarted.
+ *
+ * @param pxHigherPriorityTaskWoken The timer service/daemon task spends most
+ * of its time in the Blocked state, waiting for messages to arrive on the timer
+ * command queue. Calling xTimerResetFromISR() writes a message to the timer
+ * command queue, so has the potential to transition the timer service/daemon
+ * task out of the Blocked state. If calling xTimerResetFromISR() causes the
+ * timer service/daemon task to leave the Blocked state, and the timer service/
+ * daemon task has a priority equal to or greater than the currently executing
+ * task (the task that was interrupted), then *pxHigherPriorityTaskWoken will
+ * get set to pdTRUE internally within the xTimerResetFromISR() function. If
+ * xTimerResetFromISR() sets this value to pdTRUE then a context switch should
+ * be performed before the interrupt exits.
+ *
+ * @return pdFAIL will be returned if the reset command could not be sent to
+ * the timer command queue. pdPASS will be returned if the command was
+ * successfully sent to the timer command queue. When the command is actually
+ * processed will depend on the priority of the timer service/daemon task
+ * relative to other tasks in the system, although the timers expiry time is
+ * relative to when xTimerResetFromISR() is actually called. The timer service/daemon
+ * task priority is set by the configTIMER_TASK_PRIORITY configuration constant.
+ *
+ * Example usage:
+ *
+ * // This scenario assumes xBacklightTimer has already been created. When a
+ * // key is pressed, an LCD back-light is switched on. If 5 seconds pass
+ * // without a key being pressed, then the LCD back-light is switched off. In
+ * // this case, the timer is a one-shot timer, and unlike the example given for
+ * // the xTimerReset() function, the key press event handler is an interrupt
+ * // service routine.
+ *
+ * // The callback function assigned to the one-shot timer. In this case the
+ * // parameter is not used.
+ * void vBacklightTimerCallback( xTIMER *pxTimer )
+ * {
+ * // The timer expired, therefore 5 seconds must have passed since a key
+ * // was pressed. Switch off the LCD back-light.
+ * vSetBacklightState( BACKLIGHT_OFF );
+ * }
+ *
+ * // The key press interrupt service routine.
+ * void vKeyPressEventInterruptHandler( void )
+ * {
+ * portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
+ *
+ * // Ensure the LCD back-light is on, then reset the timer that is
+ * // responsible for turning the back-light off after 5 seconds of
+ * // key inactivity. This is an interrupt service routine so can only
+ * // call FreeRTOS API functions that end in "FromISR".
+ * vSetBacklightState( BACKLIGHT_ON );
+ *
+ * // xTimerStartFromISR() or xTimerResetFromISR() could be called here
+ * // as both cause the timer to re-calculate its expiry time.
+ * // xHigherPriorityTaskWoken was initialised to pdFALSE when it was
+ * // declared (in this function).
+ * if( xTimerResetFromISR( xBacklightTimer, &xHigherPriorityTaskWoken ) != pdPASS )
+ * {
+ * // The reset command was not executed successfully. Take appropriate
+ * // action here.
+ * }
+ *
+ * // Perform the rest of the key processing here.
+ *
+ * // If xHigherPriorityTaskWoken equals pdTRUE, then a context switch
+ * // should be performed. The syntax required to perform a context switch
+ * // from inside an ISR varies from port to port, and from compiler to
+ * // compiler. Inspect the demos for the port you are using to find the
+ * // actual syntax required.
+ * if( xHigherPriorityTaskWoken != pdFALSE )
+ * {
+ * // Call the interrupt safe yield function here (actual function
+ * // depends on the FreeRTOS port being used.
+ * }
+ * }
+ */
+#define xTimerResetFromISR( xTimer, pxHigherPriorityTaskWoken ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_START, ( xTaskGetTickCountFromISR() ), ( pxHigherPriorityTaskWoken ), 0U )
+
+/*
+ * Functions beyond this part are not part of the public API and are intended
+ * for use by the kernel only.
+ */
+portBASE_TYPE xTimerCreateTimerTask( void ) PRIVILEGED_FUNCTION;
+portBASE_TYPE xTimerGenericCommand( xTimerHandle xTimer, portBASE_TYPE xCommandID, portTickType xOptionalValue, portBASE_TYPE *pxHigherPriorityTaskWoken, portTickType xBlockTime ) PRIVILEGED_FUNCTION;
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* TIMERS_H */
+
+
+
diff --git a/Libmaple/libmaple/libraries/LiquidCrystal/LiquidCrystal.cpp b/Libmaple/libmaple/libraries/LiquidCrystal/LiquidCrystal.cpp
index fbfc54bc..85e19ef8 100644
--- a/Libmaple/libmaple/libraries/LiquidCrystal/LiquidCrystal.cpp
+++ b/Libmaple/libmaple/libraries/LiquidCrystal/LiquidCrystal.cpp
@@ -1,333 +1,333 @@
-#include "LiquidCrystal.h"
-
-#include
-#include
-#include "WProgram.h"
-
-// When the display powers up, it is configured as follows:
-//
-// 1. Display clear
-// 2. Function set:
-// DL = 1; 8-bit interface data
-// N = 0; 1-line display
-// F = 0; 5x8 dot character font
-// 3. Display on/off control:
-// D = 0; Display off
-// C = 0; Cursor off
-// B = 0; Blinking off
-// 4. Entry mode set:
-// I/D = 1; Increment by 1
-// S = 0; No shift
-//
-// Note, however, that resetting the Arduino doesn't reset the LCD, so we
-// can't assume that its in that state when a sketch starts (and the
-// LiquidCrystal constructor is called).
-
-// This library has been modified to be compatible with the LeafLabs Maple;
-// very conservative timing is used due to problems with delayMicroseconds()
-// that should be fixed in the 0.0.7 release of the libmaple. [bnewbold]
-
-LiquidCrystal::LiquidCrystal(uint8 rs, uint8 rw, uint8 enable,
- uint8 d0, uint8 d1, uint8 d2, uint8 d3,
- uint8 d4, uint8 d5, uint8 d6, uint8 d7)
-{
- init(0, rs, rw, enable, d0, d1, d2, d3, d4, d5, d6, d7);
-}
-
-LiquidCrystal::LiquidCrystal(uint8 rs, uint8 enable,
- uint8 d0, uint8 d1, uint8 d2, uint8 d3,
- uint8 d4, uint8 d5, uint8 d6, uint8 d7)
-{
- init(0, rs, 255, enable, d0, d1, d2, d3, d4, d5, d6, d7);
-}
-
-LiquidCrystal::LiquidCrystal(uint8 rs, uint8 rw, uint8 enable,
- uint8 d0, uint8 d1, uint8 d2, uint8 d3)
-{
- init(1, rs, rw, enable, d0, d1, d2, d3, 0, 0, 0, 0);
-}
-
-LiquidCrystal::LiquidCrystal(uint8 rs, uint8 enable,
- uint8 d0, uint8 d1, uint8 d2, uint8 d3)
-{
- init(1, rs, 255, enable, d0, d1, d2, d3, 0, 0, 0, 0);
-}
-
-void LiquidCrystal::init(uint8 fourbitmode, uint8 rs, uint8 rw, uint8 enable,
- uint8 d0, uint8 d1, uint8 d2, uint8 d3,
- uint8 d4, uint8 d5, uint8 d6, uint8 d7)
-{
- _rs_pin = rs;
- _rw_pin = rw;
- _enable_pin = enable;
-
- _data_pins[0] = d0;
- _data_pins[1] = d1;
- _data_pins[2] = d2;
- _data_pins[3] = d3;
- _data_pins[4] = d4;
- _data_pins[5] = d5;
- _data_pins[6] = d6;
- _data_pins[7] = d7;
-
- for (int i = 0; i < 8 - fourbitmode * 4; i++) {
- pinMode(_data_pins[i], OUTPUT);
- }
-
- pinMode(_rs_pin, OUTPUT);
- // we can save 1 pin by not using RW. Indicate by passing 255 instead of pin#
- if (_rw_pin != 255) {
- pinMode(_rw_pin, OUTPUT);
- }
- pinMode(_enable_pin, OUTPUT);
-
- if (fourbitmode)
- _displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
- else
- _displayfunction = LCD_8BITMODE | LCD_1LINE | LCD_5x8DOTS;
-
- // TODO: bnewbold, re-enable this?
- begin(16, 1);
-}
-
-void LiquidCrystal::begin(uint8 cols, uint8 lines, uint8 dotsize) {
- if (lines > 1) {
- _displayfunction |= LCD_2LINE;
- }
- _numlines = lines;
- _currline = 0;
-
- // for some 1 line displays you can select a 10 pixel high font
- if ((dotsize != 0) && (lines == 1)) {
- _displayfunction |= LCD_5x10DOTS;
- }
-
- // SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION! according to
- // datasheet, we need at least 40ms after power rises above 2.7V
- // before sending commands. Arduino can turn on way befer 4.5V so
- // we'll wait 50
- delay(50); // Maple mod
- //delayMicroseconds(50000);
- // Now we pull both RS and R/W low to begin commands
- digitalWrite(_rs_pin, LOW);
- digitalWrite(_enable_pin, LOW);
- if (_rw_pin != 255) {
- digitalWrite(_rw_pin, LOW);
- }
-
- //put the LCD into 4 bit or 8 bit mode
- if (! (_displayfunction & LCD_8BITMODE)) {
- // this is according to the hitachi HD44780 datasheet
- // figure 24, pg 46
-
- // we start in 8bit mode, try to set 4 bit mode
- write4bits(0x03);
- delay(5); // Maple mod
- //delayMicroseconds(4500); // wait min 4.1ms
-
- // second try
- write4bits(0x03);
- delay(5); // Maple mod
- //delayMicroseconds(4500); // wait min 4.1ms
-
- // third go!
- write4bits(0x03);
- delay(1); // Maple mod
- //delayMicroseconds(150);
-
- // finally, set to 8-bit interface
- write4bits(0x02);
- } else {
- // this is according to the hitachi HD44780 datasheet
- // page 45 figure 23
-
- // Send function set command sequence
- command(LCD_FUNCTIONSET | _displayfunction);
- delay(5); // Maple mod
- //delayMicroseconds(4500); // wait more than 4.1ms
-
- // second try
- command(LCD_FUNCTIONSET | _displayfunction);
- delay(1); // Maple mod
- //delayMicroseconds(150);
-
- // third go
- command(LCD_FUNCTIONSET | _displayfunction);
- }
-
- // finally, set # lines, font size, etc.
- command(LCD_FUNCTIONSET | _displayfunction);
-
- // turn the display on with no cursor or blinking default
- _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
- display();
-
- // clear it off
- clear();
-
- // Initialize to default text direction (for romance languages)
- _displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
- // set the entry mode
- command(LCD_ENTRYMODESET | _displaymode);
-
-}
-
-/********** high level commands, for the user! */
-void LiquidCrystal::clear()
-{
- command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero
- delay(2); // Maple mod
- //delayMicroseconds(2000); // this command takes a long time!
-}
-
-void LiquidCrystal::home()
-{
- command(LCD_RETURNHOME); // set cursor position to zero
- delay(2); // Maple mod
- //delayMicroseconds(2000); // this command takes a long time!
-}
-
-void LiquidCrystal::setCursor(uint8 col, uint8 row)
-{
- int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 };
- if ( row > _numlines ) {
- row = _numlines-1; // we count rows starting w/0
- }
-
- command(LCD_SETDDRAMADDR | (col + row_offsets[row]));
-}
-
-// Turn the display on/off (quickly)
-void LiquidCrystal::noDisplay() {
- _displaycontrol &= ~LCD_DISPLAYON;
- command(LCD_DISPLAYCONTROL | _displaycontrol);
-}
-void LiquidCrystal::display() {
- _displaycontrol |= LCD_DISPLAYON;
- command(LCD_DISPLAYCONTROL | _displaycontrol);
-}
-
-// Turns the underline cursor on/off
-void LiquidCrystal::noCursor() {
- _displaycontrol &= ~LCD_CURSORON;
- command(LCD_DISPLAYCONTROL | _displaycontrol);
-}
-void LiquidCrystal::cursor() {
- _displaycontrol |= LCD_CURSORON;
- command(LCD_DISPLAYCONTROL | _displaycontrol);
-}
-
-// Turn on and off the blinking cursor
-void LiquidCrystal::noBlink() {
- _displaycontrol &= ~LCD_BLINKON;
- command(LCD_DISPLAYCONTROL | _displaycontrol);
-}
-void LiquidCrystal::blink() {
- _displaycontrol |= LCD_BLINKON;
- command(LCD_DISPLAYCONTROL | _displaycontrol);
-}
-
-// These commands scroll the display without changing the RAM
-void LiquidCrystal::scrollDisplayLeft(void) {
- command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);
-}
-void LiquidCrystal::scrollDisplayRight(void) {
- command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);
-}
-
-// This is for text that flows Left to Right
-void LiquidCrystal::leftToRight(void) {
- _displaymode |= LCD_ENTRYLEFT;
- command(LCD_ENTRYMODESET | _displaymode);
-}
-
-// This is for text that flows Right to Left
-void LiquidCrystal::rightToLeft(void) {
- _displaymode &= ~LCD_ENTRYLEFT;
- command(LCD_ENTRYMODESET | _displaymode);
-}
-
-// This will 'right justify' text from the cursor
-void LiquidCrystal::autoscroll(void) {
- _displaymode |= LCD_ENTRYSHIFTINCREMENT;
- command(LCD_ENTRYMODESET | _displaymode);
-}
-
-// This will 'left justify' text from the cursor
-void LiquidCrystal::noAutoscroll(void) {
- _displaymode &= ~LCD_ENTRYSHIFTINCREMENT;
- command(LCD_ENTRYMODESET | _displaymode);
-}
-
-// Allows us to fill the first 8 CGRAM locations
-// with custom characters
-void LiquidCrystal::createChar(uint8 location, uint8 charmap[]) {
- location &= 0x7; // we only have 8 locations 0-7
- command(LCD_SETCGRAMADDR | (location << 3));
- for (int i=0; i<8; i++) {
- write(charmap[i]);
- }
-}
-
-/*********** mid level commands, for sending data/cmds */
-
-inline void LiquidCrystal::command(uint8 value) {
- send(value, LOW);
-}
-
-inline void LiquidCrystal::write(uint8 value) {
- send(value, HIGH);
-}
-
-/************ low level data pushing commands **********/
-
-// write either command or data, with automatic 4/8-bit selection
-void LiquidCrystal::send(uint8 value, uint8 mode) {
- digitalWrite(_rs_pin, mode);
-
- // if there is a RW pin indicated, set it low to Write
- if (_rw_pin != 255) {
- digitalWrite(_rw_pin, LOW);
- }
-
- if (_displayfunction & LCD_8BITMODE) {
- write8bits(value);
- } else {
- write4bits(value>>4);
- write4bits(value);
- }
-}
-
-void LiquidCrystal::pulseEnable(void) {
- // _enable_pin should already be LOW (unless someone else messed
- // with it), so don't sit around waiting for long.
- digitalWrite(_enable_pin, LOW);
- delayMicroseconds(1);
-
- // Enable pulse must be > 450 ns. Value chosen here according to
- // the following threads:
- // http://forums.leaflabs.com/topic.php?id=640
- // http://forums.leaflabs.com/topic.php?id=512
- togglePin(_enable_pin);
- delayMicroseconds(1);
- togglePin(_enable_pin);
-
- // Commands needs > 37us to settle.
- delayMicroseconds(42);
-}
-
-void LiquidCrystal::write4bits(uint8 value) {
- for (int i = 0; i < 4; i++) {
- digitalWrite(_data_pins[i], (value >> i) & 0x01);
- }
-
- pulseEnable();
-}
-
-void LiquidCrystal::write8bits(uint8 value) {
- for (int i = 0; i < 8; i++) {
- digitalWrite(_data_pins[i], (value >> i) & 0x01);
- }
-
- pulseEnable();
-}
+#include "LiquidCrystal.h"
+
+#include
+#include
+#include "WProgram.h"
+
+// When the display powers up, it is configured as follows:
+//
+// 1. Display clear
+// 2. Function set:
+// DL = 1; 8-bit interface data
+// N = 0; 1-line display
+// F = 0; 5x8 dot character font
+// 3. Display on/off control:
+// D = 0; Display off
+// C = 0; Cursor off
+// B = 0; Blinking off
+// 4. Entry mode set:
+// I/D = 1; Increment by 1
+// S = 0; No shift
+//
+// Note, however, that resetting the Arduino doesn't reset the LCD, so we
+// can't assume that its in that state when a sketch starts (and the
+// LiquidCrystal constructor is called).
+
+// This library has been modified to be compatible with the LeafLabs Maple;
+// very conservative timing is used due to problems with delayMicroseconds()
+// that should be fixed in the 0.0.7 release of the libmaple. [bnewbold]
+
+LiquidCrystal::LiquidCrystal(uint8 rs, uint8 rw, uint8 enable,
+ uint8 d0, uint8 d1, uint8 d2, uint8 d3,
+ uint8 d4, uint8 d5, uint8 d6, uint8 d7)
+{
+ init(0, rs, rw, enable, d0, d1, d2, d3, d4, d5, d6, d7);
+}
+
+LiquidCrystal::LiquidCrystal(uint8 rs, uint8 enable,
+ uint8 d0, uint8 d1, uint8 d2, uint8 d3,
+ uint8 d4, uint8 d5, uint8 d6, uint8 d7)
+{
+ init(0, rs, 255, enable, d0, d1, d2, d3, d4, d5, d6, d7);
+}
+
+LiquidCrystal::LiquidCrystal(uint8 rs, uint8 rw, uint8 enable,
+ uint8 d0, uint8 d1, uint8 d2, uint8 d3)
+{
+ init(1, rs, rw, enable, d0, d1, d2, d3, 0, 0, 0, 0);
+}
+
+LiquidCrystal::LiquidCrystal(uint8 rs, uint8 enable,
+ uint8 d0, uint8 d1, uint8 d2, uint8 d3)
+{
+ init(1, rs, 255, enable, d0, d1, d2, d3, 0, 0, 0, 0);
+}
+
+void LiquidCrystal::init(uint8 fourbitmode, uint8 rs, uint8 rw, uint8 enable,
+ uint8 d0, uint8 d1, uint8 d2, uint8 d3,
+ uint8 d4, uint8 d5, uint8 d6, uint8 d7)
+{
+ _rs_pin = rs;
+ _rw_pin = rw;
+ _enable_pin = enable;
+
+ _data_pins[0] = d0;
+ _data_pins[1] = d1;
+ _data_pins[2] = d2;
+ _data_pins[3] = d3;
+ _data_pins[4] = d4;
+ _data_pins[5] = d5;
+ _data_pins[6] = d6;
+ _data_pins[7] = d7;
+
+ for (int i = 0; i < 8 - fourbitmode * 4; i++) {
+ pinMode(_data_pins[i], OUTPUT);
+ }
+
+ pinMode(_rs_pin, OUTPUT);
+ // we can save 1 pin by not using RW. Indicate by passing 255 instead of pin#
+ if (_rw_pin != 255) {
+ pinMode(_rw_pin, OUTPUT);
+ }
+ pinMode(_enable_pin, OUTPUT);
+
+ if (fourbitmode)
+ _displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
+ else
+ _displayfunction = LCD_8BITMODE | LCD_1LINE | LCD_5x8DOTS;
+
+ // TODO: bnewbold, re-enable this?
+ begin(16, 1);
+}
+
+void LiquidCrystal::begin(uint8 cols, uint8 lines, uint8 dotsize) {
+ if (lines > 1) {
+ _displayfunction |= LCD_2LINE;
+ }
+ _numlines = lines;
+ _currline = 0;
+
+ // for some 1 line displays you can select a 10 pixel high font
+ if ((dotsize != 0) && (lines == 1)) {
+ _displayfunction |= LCD_5x10DOTS;
+ }
+
+ // SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION! according to
+ // datasheet, we need at least 40ms after power rises above 2.7V
+ // before sending commands. Arduino can turn on way befer 4.5V so
+ // we'll wait 50
+ delay(50); // Maple mod
+ //delayMicroseconds(50000);
+ // Now we pull both RS and R/W low to begin commands
+ digitalWrite(_rs_pin, LOW);
+ digitalWrite(_enable_pin, LOW);
+ if (_rw_pin != 255) {
+ digitalWrite(_rw_pin, LOW);
+ }
+
+ //put the LCD into 4 bit or 8 bit mode
+ if (! (_displayfunction & LCD_8BITMODE)) {
+ // this is according to the hitachi HD44780 datasheet
+ // figure 24, pg 46
+
+ // we start in 8bit mode, try to set 4 bit mode
+ write4bits(0x03);
+ delay(5); // Maple mod
+ //delayMicroseconds(4500); // wait min 4.1ms
+
+ // second try
+ write4bits(0x03);
+ delay(5); // Maple mod
+ //delayMicroseconds(4500); // wait min 4.1ms
+
+ // third go!
+ write4bits(0x03);
+ delay(1); // Maple mod
+ //delayMicroseconds(150);
+
+ // finally, set to 8-bit interface
+ write4bits(0x02);
+ } else {
+ // this is according to the hitachi HD44780 datasheet
+ // page 45 figure 23
+
+ // Send function set command sequence
+ command(LCD_FUNCTIONSET | _displayfunction);
+ delay(5); // Maple mod
+ //delayMicroseconds(4500); // wait more than 4.1ms
+
+ // second try
+ command(LCD_FUNCTIONSET | _displayfunction);
+ delay(1); // Maple mod
+ //delayMicroseconds(150);
+
+ // third go
+ command(LCD_FUNCTIONSET | _displayfunction);
+ }
+
+ // finally, set # lines, font size, etc.
+ command(LCD_FUNCTIONSET | _displayfunction);
+
+ // turn the display on with no cursor or blinking default
+ _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
+ display();
+
+ // clear it off
+ clear();
+
+ // Initialize to default text direction (for romance languages)
+ _displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
+ // set the entry mode
+ command(LCD_ENTRYMODESET | _displaymode);
+
+}
+
+/********** high level commands, for the user! */
+void LiquidCrystal::clear()
+{
+ command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero
+ delay(2); // Maple mod
+ //delayMicroseconds(2000); // this command takes a long time!
+}
+
+void LiquidCrystal::home()
+{
+ command(LCD_RETURNHOME); // set cursor position to zero
+ delay(2); // Maple mod
+ //delayMicroseconds(2000); // this command takes a long time!
+}
+
+void LiquidCrystal::setCursor(uint8 col, uint8 row)
+{
+ int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 };
+ if ( row > _numlines ) {
+ row = _numlines-1; // we count rows starting w/0
+ }
+
+ command(LCD_SETDDRAMADDR | (col + row_offsets[row]));
+}
+
+// Turn the display on/off (quickly)
+void LiquidCrystal::noDisplay() {
+ _displaycontrol &= ~LCD_DISPLAYON;
+ command(LCD_DISPLAYCONTROL | _displaycontrol);
+}
+void LiquidCrystal::display() {
+ _displaycontrol |= LCD_DISPLAYON;
+ command(LCD_DISPLAYCONTROL | _displaycontrol);
+}
+
+// Turns the underline cursor on/off
+void LiquidCrystal::noCursor() {
+ _displaycontrol &= ~LCD_CURSORON;
+ command(LCD_DISPLAYCONTROL | _displaycontrol);
+}
+void LiquidCrystal::cursor() {
+ _displaycontrol |= LCD_CURSORON;
+ command(LCD_DISPLAYCONTROL | _displaycontrol);
+}
+
+// Turn on and off the blinking cursor
+void LiquidCrystal::noBlink() {
+ _displaycontrol &= ~LCD_BLINKON;
+ command(LCD_DISPLAYCONTROL | _displaycontrol);
+}
+void LiquidCrystal::blink() {
+ _displaycontrol |= LCD_BLINKON;
+ command(LCD_DISPLAYCONTROL | _displaycontrol);
+}
+
+// These commands scroll the display without changing the RAM
+void LiquidCrystal::scrollDisplayLeft(void) {
+ command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);
+}
+void LiquidCrystal::scrollDisplayRight(void) {
+ command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);
+}
+
+// This is for text that flows Left to Right
+void LiquidCrystal::leftToRight(void) {
+ _displaymode |= LCD_ENTRYLEFT;
+ command(LCD_ENTRYMODESET | _displaymode);
+}
+
+// This is for text that flows Right to Left
+void LiquidCrystal::rightToLeft(void) {
+ _displaymode &= ~LCD_ENTRYLEFT;
+ command(LCD_ENTRYMODESET | _displaymode);
+}
+
+// This will 'right justify' text from the cursor
+void LiquidCrystal::autoscroll(void) {
+ _displaymode |= LCD_ENTRYSHIFTINCREMENT;
+ command(LCD_ENTRYMODESET | _displaymode);
+}
+
+// This will 'left justify' text from the cursor
+void LiquidCrystal::noAutoscroll(void) {
+ _displaymode &= ~LCD_ENTRYSHIFTINCREMENT;
+ command(LCD_ENTRYMODESET | _displaymode);
+}
+
+// Allows us to fill the first 8 CGRAM locations
+// with custom characters
+void LiquidCrystal::createChar(uint8 location, uint8 charmap[]) {
+ location &= 0x7; // we only have 8 locations 0-7
+ command(LCD_SETCGRAMADDR | (location << 3));
+ for (int i=0; i<8; i++) {
+ write(charmap[i]);
+ }
+}
+
+/*********** mid level commands, for sending data/cmds */
+
+inline void LiquidCrystal::command(uint8 value) {
+ send(value, LOW);
+}
+
+inline void LiquidCrystal::write(uint8 value) {
+ send(value, HIGH);
+}
+
+/************ low level data pushing commands **********/
+
+// write either command or data, with automatic 4/8-bit selection
+void LiquidCrystal::send(uint8 value, uint8 mode) {
+ digitalWrite(_rs_pin, mode);
+
+ // if there is a RW pin indicated, set it low to Write
+ if (_rw_pin != 255) {
+ digitalWrite(_rw_pin, LOW);
+ }
+
+ if (_displayfunction & LCD_8BITMODE) {
+ write8bits(value);
+ } else {
+ write4bits(value>>4);
+ write4bits(value);
+ }
+}
+
+void LiquidCrystal::pulseEnable(void) {
+ // _enable_pin should already be LOW (unless someone else messed
+ // with it), so don't sit around waiting for long.
+ digitalWrite(_enable_pin, LOW);
+ delayMicroseconds(1);
+
+ // Enable pulse must be > 450 ns. Value chosen here according to
+ // the following threads:
+ // http://forums.leaflabs.com/topic.php?id=640
+ // http://forums.leaflabs.com/topic.php?id=512
+ togglePin(_enable_pin);
+ delayMicroseconds(1);
+ togglePin(_enable_pin);
+
+ // Commands needs > 37us to settle.
+ delayMicroseconds(42);
+}
+
+void LiquidCrystal::write4bits(uint8 value) {
+ for (int i = 0; i < 4; i++) {
+ digitalWrite(_data_pins[i], (value >> i) & 0x01);
+ }
+
+ pulseEnable();
+}
+
+void LiquidCrystal::write8bits(uint8 value) {
+ for (int i = 0; i < 8; i++) {
+ digitalWrite(_data_pins[i], (value >> i) & 0x01);
+ }
+
+ pulseEnable();
+}
diff --git a/Libmaple/libmaple/libraries/LiquidCrystal/LiquidCrystal.h b/Libmaple/libmaple/libraries/LiquidCrystal/LiquidCrystal.h
index 1115fa92..0baf5433 100644
--- a/Libmaple/libmaple/libraries/LiquidCrystal/LiquidCrystal.h
+++ b/Libmaple/libmaple/libraries/LiquidCrystal/LiquidCrystal.h
@@ -1,105 +1,105 @@
-#ifndef LiquidCrystal_h
-#define LiquidCrystal_h
-
-//#include
-#include "wirish.h"
-#include "Print.h"
-
-// commands
-#define LCD_CLEARDISPLAY 0x01
-#define LCD_RETURNHOME 0x02
-#define LCD_ENTRYMODESET 0x04
-#define LCD_DISPLAYCONTROL 0x08
-#define LCD_CURSORSHIFT 0x10
-#define LCD_FUNCTIONSET 0x20
-#define LCD_SETCGRAMADDR 0x40
-#define LCD_SETDDRAMADDR 0x80
-
-// flags for display entry mode
-#define LCD_ENTRYRIGHT 0x00
-#define LCD_ENTRYLEFT 0x02
-#define LCD_ENTRYSHIFTINCREMENT 0x01
-#define LCD_ENTRYSHIFTDECREMENT 0x00
-
-// flags for display on/off control
-#define LCD_DISPLAYON 0x04
-#define LCD_DISPLAYOFF 0x00
-#define LCD_CURSORON 0x02
-#define LCD_CURSOROFF 0x00
-#define LCD_BLINKON 0x01
-#define LCD_BLINKOFF 0x00
-
-// flags for display/cursor shift
-#define LCD_DISPLAYMOVE 0x08
-#define LCD_CURSORMOVE 0x00
-#define LCD_MOVERIGHT 0x04
-#define LCD_MOVELEFT 0x00
-
-// flags for function set
-#define LCD_8BITMODE 0x10
-#define LCD_4BITMODE 0x00
-#define LCD_2LINE 0x08
-#define LCD_1LINE 0x00
-#define LCD_5x10DOTS 0x04
-#define LCD_5x8DOTS 0x00
-
-class LiquidCrystal : public Print {
-public:
- LiquidCrystal(uint8 rs, uint8 enable,
- uint8 d0, uint8 d1, uint8 d2, uint8 d3,
- uint8 d4, uint8 d5, uint8 d6, uint8 d7);
- LiquidCrystal(uint8 rs, uint8 rw, uint8 enable,
- uint8 d0, uint8 d1, uint8 d2, uint8 d3,
- uint8 d4, uint8 d5, uint8 d6, uint8 d7);
- LiquidCrystal(uint8 rs, uint8 rw, uint8 enable,
- uint8 d0, uint8 d1, uint8 d2, uint8 d3);
- LiquidCrystal(uint8 rs, uint8 enable,
- uint8 d0, uint8 d1, uint8 d2, uint8 d3);
-
- void init(uint8 fourbitmode, uint8 rs, uint8 rw, uint8 enable,
- uint8 d0, uint8 d1, uint8 d2, uint8 d3,
- uint8 d4, uint8 d5, uint8 d6, uint8 d7);
-
- void begin(uint8 cols, uint8 rows, uint8 charsize = LCD_5x8DOTS);
-
- void clear();
- void home();
-
- void noDisplay();
- void display();
- void noBlink();
- void blink();
- void noCursor();
- void cursor();
- void scrollDisplayLeft();
- void scrollDisplayRight();
- void leftToRight();
- void rightToLeft();
- void autoscroll();
- void noAutoscroll();
-
- void createChar(uint8, uint8[]);
- void setCursor(uint8, uint8);
- virtual void write(uint8);
- void command(uint8);
-private:
- void send(uint8, uint8);
- void write4bits(uint8);
- void write8bits(uint8);
- void pulseEnable();
-
- uint8 _rs_pin; // LOW: command. HIGH: character.
- uint8 _rw_pin; // LOW: write to LCD. HIGH: read from LCD.
- uint8 _enable_pin; // activated by a HIGH pulse.
- uint8 _data_pins[8];
-
- uint8 _displayfunction;
- uint8 _displaycontrol;
- uint8 _displaymode;
-
- uint8 _initialized;
-
- uint8 _numlines,_currline;
-};
-
-#endif
+#ifndef LiquidCrystal_h
+#define LiquidCrystal_h
+
+//#include
+#include "wirish.h"
+#include "Print.h"
+
+// commands
+#define LCD_CLEARDISPLAY 0x01
+#define LCD_RETURNHOME 0x02
+#define LCD_ENTRYMODESET 0x04
+#define LCD_DISPLAYCONTROL 0x08
+#define LCD_CURSORSHIFT 0x10
+#define LCD_FUNCTIONSET 0x20
+#define LCD_SETCGRAMADDR 0x40
+#define LCD_SETDDRAMADDR 0x80
+
+// flags for display entry mode
+#define LCD_ENTRYRIGHT 0x00
+#define LCD_ENTRYLEFT 0x02
+#define LCD_ENTRYSHIFTINCREMENT 0x01
+#define LCD_ENTRYSHIFTDECREMENT 0x00
+
+// flags for display on/off control
+#define LCD_DISPLAYON 0x04
+#define LCD_DISPLAYOFF 0x00
+#define LCD_CURSORON 0x02
+#define LCD_CURSOROFF 0x00
+#define LCD_BLINKON 0x01
+#define LCD_BLINKOFF 0x00
+
+// flags for display/cursor shift
+#define LCD_DISPLAYMOVE 0x08
+#define LCD_CURSORMOVE 0x00
+#define LCD_MOVERIGHT 0x04
+#define LCD_MOVELEFT 0x00
+
+// flags for function set
+#define LCD_8BITMODE 0x10
+#define LCD_4BITMODE 0x00
+#define LCD_2LINE 0x08
+#define LCD_1LINE 0x00
+#define LCD_5x10DOTS 0x04
+#define LCD_5x8DOTS 0x00
+
+class LiquidCrystal : public Print {
+public:
+ LiquidCrystal(uint8 rs, uint8 enable,
+ uint8 d0, uint8 d1, uint8 d2, uint8 d3,
+ uint8 d4, uint8 d5, uint8 d6, uint8 d7);
+ LiquidCrystal(uint8 rs, uint8 rw, uint8 enable,
+ uint8 d0, uint8 d1, uint8 d2, uint8 d3,
+ uint8 d4, uint8 d5, uint8 d6, uint8 d7);
+ LiquidCrystal(uint8 rs, uint8 rw, uint8 enable,
+ uint8 d0, uint8 d1, uint8 d2, uint8 d3);
+ LiquidCrystal(uint8 rs, uint8 enable,
+ uint8 d0, uint8 d1, uint8 d2, uint8 d3);
+
+ void init(uint8 fourbitmode, uint8 rs, uint8 rw, uint8 enable,
+ uint8 d0, uint8 d1, uint8 d2, uint8 d3,
+ uint8 d4, uint8 d5, uint8 d6, uint8 d7);
+
+ void begin(uint8 cols, uint8 rows, uint8 charsize = LCD_5x8DOTS);
+
+ void clear();
+ void home();
+
+ void noDisplay();
+ void display();
+ void noBlink();
+ void blink();
+ void noCursor();
+ void cursor();
+ void scrollDisplayLeft();
+ void scrollDisplayRight();
+ void leftToRight();
+ void rightToLeft();
+ void autoscroll();
+ void noAutoscroll();
+
+ void createChar(uint8, uint8[]);
+ void setCursor(uint8, uint8);
+ virtual void write(uint8);
+ void command(uint8);
+private:
+ void send(uint8, uint8);
+ void write4bits(uint8);
+ void write8bits(uint8);
+ void pulseEnable();
+
+ uint8 _rs_pin; // LOW: command. HIGH: character.
+ uint8 _rw_pin; // LOW: write to LCD. HIGH: read from LCD.
+ uint8 _enable_pin; // activated by a HIGH pulse.
+ uint8 _data_pins[8];
+
+ uint8 _displayfunction;
+ uint8 _displaycontrol;
+ uint8 _displaymode;
+
+ uint8 _initialized;
+
+ uint8 _numlines,_currline;
+};
+
+#endif
diff --git a/Libmaple/libmaple/libraries/LiquidCrystal/rules.mk b/Libmaple/libmaple/libraries/LiquidCrystal/rules.mk
index ddb77a3c..7b18203b 100644
--- a/Libmaple/libmaple/libraries/LiquidCrystal/rules.mk
+++ b/Libmaple/libmaple/libraries/LiquidCrystal/rules.mk
@@ -1,29 +1,29 @@
-# Standard things
-sp := $(sp).x
-dirstack_$(sp) := $(d)
-d := $(dir)
-BUILDDIRS += $(BUILD_PATH)/$(d)
-
-# Local flags
-CFLAGS_$(d) := $(WIRISH_INCLUDES) $(LIBMAPLE_INCLUDES)
-
-# Local rules and targets
-cSRCS_$(d) :=
-
-cppSRCS_$(d) := LiquidCrystal.cpp
-
-cFILES_$(d) := $(cSRCS_$(d):%=$(d)/%)
-cppFILES_$(d) := $(cppSRCS_$(d):%=$(d)/%)
-
-OBJS_$(d) := $(cFILES_$(d):%.c=$(BUILD_PATH)/%.o) \
- $(cppFILES_$(d):%.cpp=$(BUILD_PATH)/%.o)
-DEPS_$(d) := $(OBJS_$(d):%.o=%.d)
-
-$(OBJS_$(d)): TGT_CFLAGS := $(CFLAGS_$(d))
-
-TGT_BIN += $(OBJS_$(d))
-
-# Standard things
--include $(DEPS_$(d))
-d := $(dirstack_$(sp))
+# Standard things
+sp := $(sp).x
+dirstack_$(sp) := $(d)
+d := $(dir)
+BUILDDIRS += $(BUILD_PATH)/$(d)
+
+# Local flags
+CFLAGS_$(d) := $(WIRISH_INCLUDES) $(LIBMAPLE_INCLUDES)
+
+# Local rules and targets
+cSRCS_$(d) :=
+
+cppSRCS_$(d) := LiquidCrystal.cpp
+
+cFILES_$(d) := $(cSRCS_$(d):%=$(d)/%)
+cppFILES_$(d) := $(cppSRCS_$(d):%=$(d)/%)
+
+OBJS_$(d) := $(cFILES_$(d):%.c=$(BUILD_PATH)/%.o) \
+ $(cppFILES_$(d):%.cpp=$(BUILD_PATH)/%.o)
+DEPS_$(d) := $(OBJS_$(d):%.o=%.d)
+
+$(OBJS_$(d)): TGT_CFLAGS := $(CFLAGS_$(d))
+
+TGT_BIN += $(OBJS_$(d))
+
+# Standard things
+-include $(DEPS_$(d))
+d := $(dirstack_$(sp))
sp := $(basename $(sp))
\ No newline at end of file
diff --git a/Libmaple/libmaple/libraries/Servo/Servo.cpp b/Libmaple/libmaple/libraries/Servo/Servo.cpp
index 9aafac1a..8fbd3660 100644
--- a/Libmaple/libmaple/libraries/Servo/Servo.cpp
+++ b/Libmaple/libmaple/libraries/Servo/Servo.cpp
@@ -1,150 +1,150 @@
-/******************************************************************************
- * The MIT License
- *
- * Copyright (c) 2010, LeafLabs, LLC.
- *
- * Permission is hereby granted, free of charge, to any person
- * obtaining a copy of this software and associated documentation
- * files (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use, copy,
- * modify, merge, publish, distribute, sublicense, and/or sell copies
- * of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *****************************************************************************/
-
-#include "Servo.h"
-
-#include "boards.h"
-#include "io.h"
-#include "pwm.h"
-#include "wirish_math.h"
-
-// 20 millisecond period config. For a 1-based prescaler,
-//
-// (prescaler * overflow / CYC_MSEC) msec = 1 timer cycle = 20 msec
-// => prescaler * overflow = 20 * CYC_MSEC
-//
-// This picks the smallest prescaler that allows an overflow < 2^16.
-#define MAX_OVERFLOW ((1 << 16) - 1)
-#define CYC_MSEC (1000 * CYCLES_PER_MICROSECOND)
-#define TAU_MSEC 20
-#define TAU_USEC (TAU_MSEC * 1000)
-#define TAU_CYC (TAU_MSEC * CYC_MSEC)
-#define SERVO_PRESCALER (TAU_CYC / MAX_OVERFLOW + 1)
-#define SERVO_OVERFLOW ((uint16)round((double)TAU_CYC / SERVO_PRESCALER))
-
-// Unit conversions
-#define US_TO_COMPARE(us) ((uint16)map((us), 0, TAU_USEC, 0, SERVO_OVERFLOW))
-#define COMPARE_TO_US(c) ((uint32)map((c), 0, SERVO_OVERFLOW, 0, TAU_USEC))
-#define ANGLE_TO_US(a) ((uint16)(map((a), this->minAngle, this->maxAngle, \
- this->minPW, this->maxPW)))
-#define US_TO_ANGLE(us) ((int16)(map((us), this->minPW, this->maxPW, \
- this->minAngle, this->maxAngle)))
-
-Servo::Servo() {
- this->resetFields();
-}
-
-bool Servo::attach(uint8 pin,
- uint16 minPW,
- uint16 maxPW,
- int16 minAngle,
- int16 maxAngle) {
- timer_dev *tdev = PIN_MAP[pin].timer_device;
-
- if (tdev == NULL) {
- // don't reset any fields or ASSERT(0), to keep driving any
- // previously attach()ed servo.
- return false;
- }
-
- if (this->attached()) {
- this->detach();
- }
-
- this->pin = pin;
- this->minPW = minPW;
- this->maxPW = maxPW;
- this->minAngle = minAngle;
- this->maxAngle = maxAngle;
-
- pinMode(pin, PWM);
-
- timer_pause(tdev);
- timer_set_prescaler(tdev, SERVO_PRESCALER - 1); // prescaler is 1-based
- timer_set_reload(tdev, SERVO_OVERFLOW);
- timer_generate_update(tdev);
- timer_resume(tdev);
-
- return true;
-}
-
-bool Servo::detach() {
- if (!this->attached()) {
- return false;
- }
-
- timer_dev *tdev = PIN_MAP[this->pin].timer_device;
- uint8 tchan = PIN_MAP[this->pin].timer_channel;
- timer_set_mode(tdev, tchan, TIMER_DISABLED);
-
- this->resetFields();
-
- return true;
-}
-
-void Servo::write(int degrees) {
- degrees = constrain(degrees, this->minAngle, this->maxAngle);
- this->writeMicroseconds(ANGLE_TO_US(degrees));
-}
-
-int Servo::read() const {
- int a = US_TO_ANGLE(this->readMicroseconds());
- // map() round-trips in a weird way we mostly correct for here;
- // the round-trip is still sometimes off-by-one for write(1) and
- // write(179).
- return a == this->minAngle || a == this->maxAngle ? a : a + 1;
-}
-
-void Servo::writeMicroseconds(uint16 pulseWidth) {
- if (!this->attached()) {
- ASSERT(0);
- return;
- }
-
- pulseWidth = constrain(pulseWidth, this->minPW, this->maxPW);
- pwmWrite(this->pin, US_TO_COMPARE(pulseWidth));
-}
-
-uint16 Servo::readMicroseconds() const {
- if (!this->attached()) {
- ASSERT(0);
- return 0;
- }
-
- stm32_pin_info pin_info = PIN_MAP[this->pin];
- uint16 compare = timer_get_compare(pin_info.timer_device,
- pin_info.timer_channel);
-
- return COMPARE_TO_US(compare);
-}
-
-void Servo::resetFields(void) {
- this->pin = NOT_ATTACHED;
- this->minAngle = SERVO_DEFAULT_MIN_ANGLE;
- this->maxAngle = SERVO_DEFAULT_MAX_ANGLE;
- this->minPW = SERVO_DEFAULT_MIN_PW;
- this->maxPW = SERVO_DEFAULT_MAX_PW;
-}
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010, LeafLabs, LLC.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *****************************************************************************/
+
+#include "Servo.h"
+
+#include "boards.h"
+#include "io.h"
+#include "pwm.h"
+#include "wirish_math.h"
+
+// 20 millisecond period config. For a 1-based prescaler,
+//
+// (prescaler * overflow / CYC_MSEC) msec = 1 timer cycle = 20 msec
+// => prescaler * overflow = 20 * CYC_MSEC
+//
+// This picks the smallest prescaler that allows an overflow < 2^16.
+#define MAX_OVERFLOW ((1 << 16) - 1)
+#define CYC_MSEC (1000 * CYCLES_PER_MICROSECOND)
+#define TAU_MSEC 20
+#define TAU_USEC (TAU_MSEC * 1000)
+#define TAU_CYC (TAU_MSEC * CYC_MSEC)
+#define SERVO_PRESCALER (TAU_CYC / MAX_OVERFLOW + 1)
+#define SERVO_OVERFLOW ((uint16)round((double)TAU_CYC / SERVO_PRESCALER))
+
+// Unit conversions
+#define US_TO_COMPARE(us) ((uint16)map((us), 0, TAU_USEC, 0, SERVO_OVERFLOW))
+#define COMPARE_TO_US(c) ((uint32)map((c), 0, SERVO_OVERFLOW, 0, TAU_USEC))
+#define ANGLE_TO_US(a) ((uint16)(map((a), this->minAngle, this->maxAngle, \
+ this->minPW, this->maxPW)))
+#define US_TO_ANGLE(us) ((int16)(map((us), this->minPW, this->maxPW, \
+ this->minAngle, this->maxAngle)))
+
+Servo::Servo() {
+ this->resetFields();
+}
+
+bool Servo::attach(uint8 pin,
+ uint16 minPW,
+ uint16 maxPW,
+ int16 minAngle,
+ int16 maxAngle) {
+ timer_dev *tdev = PIN_MAP[pin].timer_device;
+
+ if (tdev == NULL) {
+ // don't reset any fields or ASSERT(0), to keep driving any
+ // previously attach()ed servo.
+ return false;
+ }
+
+ if (this->attached()) {
+ this->detach();
+ }
+
+ this->pin = pin;
+ this->minPW = minPW;
+ this->maxPW = maxPW;
+ this->minAngle = minAngle;
+ this->maxAngle = maxAngle;
+
+ pinMode(pin, PWM);
+
+ timer_pause(tdev);
+ timer_set_prescaler(tdev, SERVO_PRESCALER - 1); // prescaler is 1-based
+ timer_set_reload(tdev, SERVO_OVERFLOW);
+ timer_generate_update(tdev);
+ timer_resume(tdev);
+
+ return true;
+}
+
+bool Servo::detach() {
+ if (!this->attached()) {
+ return false;
+ }
+
+ timer_dev *tdev = PIN_MAP[this->pin].timer_device;
+ uint8 tchan = PIN_MAP[this->pin].timer_channel;
+ timer_set_mode(tdev, tchan, TIMER_DISABLED);
+
+ this->resetFields();
+
+ return true;
+}
+
+void Servo::write(int degrees) {
+ degrees = constrain(degrees, this->minAngle, this->maxAngle);
+ this->writeMicroseconds(ANGLE_TO_US(degrees));
+}
+
+int Servo::read() const {
+ int a = US_TO_ANGLE(this->readMicroseconds());
+ // map() round-trips in a weird way we mostly correct for here;
+ // the round-trip is still sometimes off-by-one for write(1) and
+ // write(179).
+ return a == this->minAngle || a == this->maxAngle ? a : a + 1;
+}
+
+void Servo::writeMicroseconds(uint16 pulseWidth) {
+ if (!this->attached()) {
+ ASSERT(0);
+ return;
+ }
+
+ pulseWidth = constrain(pulseWidth, this->minPW, this->maxPW);
+ pwmWrite(this->pin, US_TO_COMPARE(pulseWidth));
+}
+
+uint16 Servo::readMicroseconds() const {
+ if (!this->attached()) {
+ ASSERT(0);
+ return 0;
+ }
+
+ stm32_pin_info pin_info = PIN_MAP[this->pin];
+ uint16 compare = timer_get_compare(pin_info.timer_device,
+ pin_info.timer_channel);
+
+ return COMPARE_TO_US(compare);
+}
+
+void Servo::resetFields(void) {
+ this->pin = NOT_ATTACHED;
+ this->minAngle = SERVO_DEFAULT_MIN_ANGLE;
+ this->maxAngle = SERVO_DEFAULT_MAX_ANGLE;
+ this->minPW = SERVO_DEFAULT_MIN_PW;
+ this->maxPW = SERVO_DEFAULT_MAX_PW;
+}
diff --git a/Libmaple/libmaple/libraries/Servo/Servo.h b/Libmaple/libmaple/libraries/Servo/Servo.h
index ec2e4aaa..7753b4be 100644
--- a/Libmaple/libmaple/libraries/Servo/Servo.h
+++ b/Libmaple/libmaple/libraries/Servo/Servo.h
@@ -1,200 +1,200 @@
-/******************************************************************************
- * The MIT License
- *
- * Copyright (c) 2010, LeafLabs, LLC.
- *
- * Permission is hereby granted, free of charge, to any person
- * obtaining a copy of this software and associated documentation
- * files (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use, copy,
- * modify, merge, publish, distribute, sublicense, and/or sell copies
- * of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *****************************************************************************/
-
-#ifndef _SERVO_H_
-#define _SERVO_H_
-
-#include "libmaple_types.h"
-#include "timer.h"
-
-#include "wirish_types.h"
-
-#ifdef MAPLE_IDE
-#include "wirish.h" /* hack for IDE compile */
-#endif
-
-/*
- * Note on Arduino compatibility:
- *
- * In the Arduino implementation, PWM is done "by hand" in the sense
- * that timer channels are hijacked in groups and an ISR is set which
- * toggles Servo::attach()ed pins using digitalWrite().
- *
- * While this scheme allows any pin to drive a servo, it chews up
- * cycles and complicates the programmer's notion of when a particular
- * timer channel will be in use.
- *
- * This implementation only allows Servo instances to attach() to pins
- * that already have a timer channel associated with them, and just
- * uses pwmWrite() to drive the wave.
- *
- * This introduces an incompatibility: while the Arduino
- * implementation of attach() returns the affected channel on success
- * and 0 on failure, this one returns true on success and false on
- * failure.
- *
- * RC Servos expect a pulse every 20ms. Since periods are set for
- * entire timers, rather than individual channels, attach()ing a Servo
- * to a pin can interfere with other pins associated with the same
- * timer. As always, your board's pin map is your friend.
- */
-
-// Pin number of unattached pins
-#define NOT_ATTACHED (-1)
-
-// Default min/max pulse widths (in microseconds) and angles (in
-// degrees). Values chosen for Arduino compatibility. These values
-// are part of the public API; DO NOT CHANGE THEM.
-#define SERVO_DEFAULT_MIN_PW 544
-#define SERVO_DEFAULT_MAX_PW 2400
-#define SERVO_DEFAULT_MIN_ANGLE 0
-#define SERVO_DEFAULT_MAX_ANGLE 180
-
-/** Class for interfacing with RC servomotors. */
-class Servo {
-public:
- /**
- * @brief Construct a new Servo instance.
- *
- * The new instance will not be attached to any pin.
- */
- Servo();
-
- /**
- * @brief Associate this instance with a servomotor whose input is
- * connected to pin.
- *
- * If this instance is already attached to a pin, it will be
- * detached before being attached to the new pin. This function
- * doesn't detach any interrupt attached with the pin's timer
- * channel.
- *
- * @param pin Pin connected to the servo pulse wave input. This
- * pin must be capable of PWM output.
- *
- * @param minPulseWidth Minimum pulse width to write to pin, in
- * microseconds. This will be associated
- * with a minAngle degree angle. Defaults to
- * SERVO_DEFAULT_MIN_PW = 544.
- *
- * @param maxPulseWidth Maximum pulse width to write to pin, in
- * microseconds. This will be associated
- * with a maxAngle degree angle. Defaults to
- * SERVO_DEFAULT_MAX_PW = 2400.
- *
- * @param minAngle Target angle (in degrees) associated with
- * minPulseWidth. Defaults to
- * SERVO_DEFAULT_MIN_ANGLE = 0.
- *
- * @param maxAngle Target angle (in degrees) associated with
- * maxPulseWidth. Defaults to
- * SERVO_DEFAULT_MAX_ANGLE = 180.
- *
- * @sideeffect May set pinMode(pin, PWM).
- *
- * @return true if successful, false when pin doesn't support PWM.
- */
- bool attach(uint8 pin,
- uint16 minPulseWidth=SERVO_DEFAULT_MIN_PW,
- uint16 maxPulseWidth=SERVO_DEFAULT_MAX_PW,
- int16 minAngle=SERVO_DEFAULT_MIN_ANGLE,
- int16 maxAngle=SERVO_DEFAULT_MAX_ANGLE);
-
- /**
- * @brief Check if this instance is attached to a servo.
- * @return true if this instance is attached to a servo, false otherwise.
- * @see Servo::attachedPin()
- */
- bool attached() const { return this->pin != NOT_ATTACHED; }
-
- /**
- * @brief Get the pin this instance is attached to.
- * @return Pin number if currently attached to a pin, NOT_ATTACHED
- * otherwise.
- * @see Servo::attach()
- */
- int attachedPin() const { return this->pin; }
-
- /**
- * @brief Stop driving the servo pulse train.
- *
- * If not currently attached to a motor, this function has no effect.
- *
- * @return true if this call did anything, false otherwise.
- */
- bool detach();
-
- /**
- * @brief Set the servomotor target angle.
- *
- * @param angle Target angle, in degrees. If the target angle is
- * outside the range specified at attach() time, it
- * will be clamped to lie in that range.
- *
- * @see Servo::attach()
- */
- void write(int angle);
-
-
- /**
- * Get the servomotor's target angle, in degrees. This will
- * lie inside the range specified at attach() time.
- *
- * @see Servo::attach()
- */
- int read() const;
-
- /**
- * @brief Set the pulse width, in microseconds.
- *
- * @param pulseWidth Pulse width to send to the servomotor, in
- * microseconds. If outside of the range
- * specified at attach() time, it is clamped to
- * lie in that range.
- *
- * @see Servo::attach()
- */
- void writeMicroseconds(uint16 pulseWidth);
-
- /**
- * Get the current pulse width, in microseconds. This will
- * lie within the range specified at attach() time.
- *
- * @see Servo::attach()
- */
- uint16 readMicroseconds() const;
-
-private:
- int16 pin;
- uint16 minPW;
- uint16 maxPW;
- int16 minAngle;
- int16 maxAngle;
-
- void resetFields(void);
-};
-
-#endif /* _SERVO_H_ */
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010, LeafLabs, LLC.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *****************************************************************************/
+
+#ifndef _SERVO_H_
+#define _SERVO_H_
+
+#include "libmaple_types.h"
+#include "timer.h"
+
+#include "wirish_types.h"
+
+#ifdef MAPLE_IDE
+#include "wirish.h" /* hack for IDE compile */
+#endif
+
+/*
+ * Note on Arduino compatibility:
+ *
+ * In the Arduino implementation, PWM is done "by hand" in the sense
+ * that timer channels are hijacked in groups and an ISR is set which
+ * toggles Servo::attach()ed pins using digitalWrite().
+ *
+ * While this scheme allows any pin to drive a servo, it chews up
+ * cycles and complicates the programmer's notion of when a particular
+ * timer channel will be in use.
+ *
+ * This implementation only allows Servo instances to attach() to pins
+ * that already have a timer channel associated with them, and just
+ * uses pwmWrite() to drive the wave.
+ *
+ * This introduces an incompatibility: while the Arduino
+ * implementation of attach() returns the affected channel on success
+ * and 0 on failure, this one returns true on success and false on
+ * failure.
+ *
+ * RC Servos expect a pulse every 20ms. Since periods are set for
+ * entire timers, rather than individual channels, attach()ing a Servo
+ * to a pin can interfere with other pins associated with the same
+ * timer. As always, your board's pin map is your friend.
+ */
+
+// Pin number of unattached pins
+#define NOT_ATTACHED (-1)
+
+// Default min/max pulse widths (in microseconds) and angles (in
+// degrees). Values chosen for Arduino compatibility. These values
+// are part of the public API; DO NOT CHANGE THEM.
+#define SERVO_DEFAULT_MIN_PW 544
+#define SERVO_DEFAULT_MAX_PW 2400
+#define SERVO_DEFAULT_MIN_ANGLE 0
+#define SERVO_DEFAULT_MAX_ANGLE 180
+
+/** Class for interfacing with RC servomotors. */
+class Servo {
+public:
+ /**
+ * @brief Construct a new Servo instance.
+ *
+ * The new instance will not be attached to any pin.
+ */
+ Servo();
+
+ /**
+ * @brief Associate this instance with a servomotor whose input is
+ * connected to pin.
+ *
+ * If this instance is already attached to a pin, it will be
+ * detached before being attached to the new pin. This function
+ * doesn't detach any interrupt attached with the pin's timer
+ * channel.
+ *
+ * @param pin Pin connected to the servo pulse wave input. This
+ * pin must be capable of PWM output.
+ *
+ * @param minPulseWidth Minimum pulse width to write to pin, in
+ * microseconds. This will be associated
+ * with a minAngle degree angle. Defaults to
+ * SERVO_DEFAULT_MIN_PW = 544.
+ *
+ * @param maxPulseWidth Maximum pulse width to write to pin, in
+ * microseconds. This will be associated
+ * with a maxAngle degree angle. Defaults to
+ * SERVO_DEFAULT_MAX_PW = 2400.
+ *
+ * @param minAngle Target angle (in degrees) associated with
+ * minPulseWidth. Defaults to
+ * SERVO_DEFAULT_MIN_ANGLE = 0.
+ *
+ * @param maxAngle Target angle (in degrees) associated with
+ * maxPulseWidth. Defaults to
+ * SERVO_DEFAULT_MAX_ANGLE = 180.
+ *
+ * @sideeffect May set pinMode(pin, PWM).
+ *
+ * @return true if successful, false when pin doesn't support PWM.
+ */
+ bool attach(uint8 pin,
+ uint16 minPulseWidth=SERVO_DEFAULT_MIN_PW,
+ uint16 maxPulseWidth=SERVO_DEFAULT_MAX_PW,
+ int16 minAngle=SERVO_DEFAULT_MIN_ANGLE,
+ int16 maxAngle=SERVO_DEFAULT_MAX_ANGLE);
+
+ /**
+ * @brief Check if this instance is attached to a servo.
+ * @return true if this instance is attached to a servo, false otherwise.
+ * @see Servo::attachedPin()
+ */
+ bool attached() const { return this->pin != NOT_ATTACHED; }
+
+ /**
+ * @brief Get the pin this instance is attached to.
+ * @return Pin number if currently attached to a pin, NOT_ATTACHED
+ * otherwise.
+ * @see Servo::attach()
+ */
+ int attachedPin() const { return this->pin; }
+
+ /**
+ * @brief Stop driving the servo pulse train.
+ *
+ * If not currently attached to a motor, this function has no effect.
+ *
+ * @return true if this call did anything, false otherwise.
+ */
+ bool detach();
+
+ /**
+ * @brief Set the servomotor target angle.
+ *
+ * @param angle Target angle, in degrees. If the target angle is
+ * outside the range specified at attach() time, it
+ * will be clamped to lie in that range.
+ *
+ * @see Servo::attach()
+ */
+ void write(int angle);
+
+
+ /**
+ * Get the servomotor's target angle, in degrees. This will
+ * lie inside the range specified at attach() time.
+ *
+ * @see Servo::attach()
+ */
+ int read() const;
+
+ /**
+ * @brief Set the pulse width, in microseconds.
+ *
+ * @param pulseWidth Pulse width to send to the servomotor, in
+ * microseconds. If outside of the range
+ * specified at attach() time, it is clamped to
+ * lie in that range.
+ *
+ * @see Servo::attach()
+ */
+ void writeMicroseconds(uint16 pulseWidth);
+
+ /**
+ * Get the current pulse width, in microseconds. This will
+ * lie within the range specified at attach() time.
+ *
+ * @see Servo::attach()
+ */
+ uint16 readMicroseconds() const;
+
+private:
+ int16 pin;
+ uint16 minPW;
+ uint16 maxPW;
+ int16 minAngle;
+ int16 maxAngle;
+
+ void resetFields(void);
+};
+
+#endif /* _SERVO_H_ */
diff --git a/Libmaple/libmaple/libraries/Servo/rules.mk b/Libmaple/libmaple/libraries/Servo/rules.mk
index cd6ba218..e013754a 100644
--- a/Libmaple/libmaple/libraries/Servo/rules.mk
+++ b/Libmaple/libmaple/libraries/Servo/rules.mk
@@ -1,29 +1,29 @@
-# Standard things
-sp := $(sp).x
-dirstack_$(sp) := $(d)
-d := $(dir)
-BUILDDIRS += $(BUILD_PATH)/$(d)
-
-# Local flags
-CXXFLAGS_$(d) := $(WIRISH_INCLUDES) $(LIBMAPLE_INCLUDES)
-
-# Local rules and targets
-cSRCS_$(d) :=
-
-cppSRCS_$(d) := Servo.cpp
-
-cFILES_$(d) := $(cSRCS_$(d):%=$(d)/%)
-cppFILES_$(d) := $(cppSRCS_$(d):%=$(d)/%)
-
-OBJS_$(d) := $(cFILES_$(d):%.c=$(BUILD_PATH)/%.o) \
- $(cppFILES_$(d):%.cpp=$(BUILD_PATH)/%.o)
-DEPS_$(d) := $(OBJS_$(d):%.o=%.d)
-
-$(OBJS_$(d)): TGT_CXXFLAGS := $(CXXFLAGS_$(d))
-
-TGT_BIN += $(OBJS_$(d))
-
-# Standard things
--include $(DEPS_$(d))
-d := $(dirstack_$(sp))
+# Standard things
+sp := $(sp).x
+dirstack_$(sp) := $(d)
+d := $(dir)
+BUILDDIRS += $(BUILD_PATH)/$(d)
+
+# Local flags
+CXXFLAGS_$(d) := $(WIRISH_INCLUDES) $(LIBMAPLE_INCLUDES)
+
+# Local rules and targets
+cSRCS_$(d) :=
+
+cppSRCS_$(d) := Servo.cpp
+
+cFILES_$(d) := $(cSRCS_$(d):%=$(d)/%)
+cppFILES_$(d) := $(cppSRCS_$(d):%=$(d)/%)
+
+OBJS_$(d) := $(cFILES_$(d):%.c=$(BUILD_PATH)/%.o) \
+ $(cppFILES_$(d):%.cpp=$(BUILD_PATH)/%.o)
+DEPS_$(d) := $(OBJS_$(d):%.o=%.d)
+
+$(OBJS_$(d)): TGT_CXXFLAGS := $(CXXFLAGS_$(d))
+
+TGT_BIN += $(OBJS_$(d))
+
+# Standard things
+-include $(DEPS_$(d))
+d := $(dirstack_$(sp))
sp := $(basename $(sp))
\ No newline at end of file
diff --git a/Libmaple/libmaple/libraries/Wire/README b/Libmaple/libmaple/libraries/Wire/README
index 2b86fe04..353d51a3 100644
--- a/Libmaple/libmaple/libraries/Wire/README
+++ b/Libmaple/libmaple/libraries/Wire/README
@@ -1,5 +1,5 @@
-Wirish soft (bit-banged) implementation of the Wire I2C library.
-
-This implementation is synchronous, and thus supports only a subset of
-the full Wire interface. An asynchronous hardware version implemented
-with DMA is expected for Maple IDE release 0.1.0.
+Wirish soft (bit-banged) implementation of the Wire I2C library.
+
+This implementation is synchronous, and thus supports only a subset of
+the full Wire interface. An asynchronous hardware version implemented
+with DMA is expected for Maple IDE release 0.1.0.
diff --git a/Libmaple/libmaple/libraries/Wire/Wire.cpp b/Libmaple/libmaple/libraries/Wire/Wire.cpp
index a6b15f67..7344d5ee 100644
--- a/Libmaple/libmaple/libraries/Wire/Wire.cpp
+++ b/Libmaple/libmaple/libraries/Wire/Wire.cpp
@@ -1,323 +1,323 @@
-/******************************************************************************
-* The MIT License
-*
-* Copyright (c) 2010 LeafLabs LLC.
-*
-* Permission is hereby granted, free of charge, to any person obtaining a copy
-* of this software and associated documentation files (the "Software"), to deal
-* in the Software without restriction, including without limitation the rights
-* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-* copies of the Software, and to permit persons to whom the Software is
-* furnished to do so, subject to the following conditions:
-*
-* The above copyright notice and this permission notice shall be included in
-* all copies or substantial portions of the Software.
-*
-* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-* THE SOFTWARE.
-*****************************************************************************/
-
-/**
-* @brief Wire library, ported from Arduino. Provides a simplistic
-* interface to i2c.
-*/
-
-#include "Wire.h"
-#include "wirish.h"
-
-/* low level conventions:
-* - SDA/SCL idle high (expected high)
-* - always start with i2c_delay rather than end
-*/
-uint32 i2c_delay = 1;
-
-void i2c_scl_low(Port port) {
- digitalWrite(port.scl,LOW);
- I2C_DELAY_SCL;
-}
-
-void i2c_scl_high(Port port) {
- digitalWrite(port.scl,HIGH);
- while(digitalRead(port.scl) == 0)
- ;
- I2C_DELAY_SCL;
-}
-
-void i2c_sda_high(Port port) {
- digitalWrite(port.sda,HIGH);
- I2C_DELAY_SDA;
-}
-
-void i2c_sda_low(Port port) {
- digitalWrite(port.sda,LOW);
- I2C_DELAY_SDA;
-}
-
-void i2c_start(Port port) {
- i2c_sda_high(port);
- i2c_scl_high(port);
- i2c_sda_low(port);
- i2c_scl_low(port);
-}
-
-void i2c_stop(Port port) {
- i2c_sda_low(port);
- i2c_scl_high(port);
- i2c_sda_high(port);
-}
-
-boolean i2c_get_ack(Port port) {
- i2c_sda_high(port);
- i2c_scl_high(port);
-
- bool ret =!digitalRead(port.sda);
- i2c_scl_low(port);
- return ret;
-}
-
-void i2c_send_ack(Port port) {
- i2c_sda_low(port);
- i2c_scl_high(port);
- i2c_scl_low(port);
-}
-
-void i2c_send_nack(Port port) {
- i2c_sda_high(port);
- i2c_scl_high(port);
- i2c_scl_low(port);
-}
-
-uint8 i2c_shift_in(Port port) {
- uint8 data = 0;
- i2c_sda_high(port);
-
- int i;
- for (i=0; i<8; i++) {
- data <<= 1;
- i2c_scl_high(port);
- if(digitalRead(port.sda)) {
- data |= 1;
- }
- i2c_scl_low(port);
- }
-
- return data;
-}
-
-void i2c_shift_out(Port port, uint8 val) {
- int i;
- for (i=0;i<8;i++) {
- if((val & 0x80) != 0) {
- i2c_sda_high(port);
- } else {
- i2c_sda_low(port);
- }
- val <<= 1;
- i2c_scl_high(port);
- i2c_scl_low(port);
- }
- /*
- i2c_sda_high(port);
- i2c_scl_high(port);
- bool nack = digitalRead(port.sda);
- i2c_scl_low(port);
- */
-
-}
-
-TwoWire::TwoWire() {
- i2c_delay = 0;
- rx_buf_idx = 0;
- rx_buf_len = 0;
- tx_addr = 0;
- tx_buf_idx = 0;
- tx_buf_overflow = false;
-}
-
-/*
-* Sets pins SDA and SCL to OUPTUT_OPEN_DRAIN, joining I2C bus as
-* master. If you want them to be some other pins, use begin(uint8,
-* uint8);
-*/
-void TwoWire::begin() {
- begin(SDA, SCL);
-}
-
-/*
-* Joins I2C bus as master on given SDA and SCL pins.
-*/
-void TwoWire::begin(uint8 sda, uint8 scl) {
- port.sda = sda;
- port.scl = scl;
- pinMode(scl, OUTPUT_OPEN_DRAIN);
- pinMode(sda, OUTPUT_OPEN_DRAIN);
- digitalWrite(scl, HIGH);
- digitalWrite(sda, HIGH);
-/*
- long t0 = systick_get_count();
- i2c_scl_high(port);
- long t1 = systick_get_count();
- Serial2.print("i2c_scl_high: ");
- Serial2.print(t1-t0);
- Serial2.println();
-*/
-}
-
-void TwoWire::beginTransmission(uint8 slave_address) {
- tx_addr = slave_address;
- tx_buf_idx = 0;
- tx_buf_overflow = false;
- rx_buf_idx = 0;
- rx_buf_len = 0;
-}
-
-void TwoWire::beginTransmission(int slave_address) {
- beginTransmission((uint8)slave_address);
-}
-
-uint8 TwoWire::endTransmission(void) {
- if (tx_buf_overflow) return EDATA;
-
- i2c_start(port);
-
- i2c_shift_out(port, (tx_addr << 1) | I2C_WRITE);
- if (!i2c_get_ack(port)) return ENACKADDR;
-
- // shift out the address we're transmitting to
- for (uint8 i = 0; i < tx_buf_idx; i++) {
- uint8 ret = writeOneByte(tx_buf[i]);
- if (ret) {
- //Serial1.println("endTransmission failed");
- return ret; // SUCCESS is 0
- }
- }
-
- i2c_stop(port);
-
- tx_buf_idx = 0;
- tx_buf_overflow = false;
- return SUCCESS;
-}
-
-#if 0
-uint8 TwoWire::requestFromOld(uint8 address, int num_bytes) {
- if (num_bytes > WIRE_BUFSIZ) num_bytes = WIRE_BUFSIZ;
-
- rx_buf_idx = 0;
- rx_buf_len = 0;
- while (rx_buf_len < num_bytes) {
- if(!readOneByte(address, rx_buf + rx_buf_len))
- rx_buf_len++;
- else {
- Serial1.print("requestFrom failed at byte ");
- Serial1.print(rx_buf_len,10);
- Serial1.println();
- break;
- }
- }
- return rx_buf_len;
-}
-#endif
-
-uint8 TwoWire::requestFrom(uint8 address, int num_bytes) {
- if (num_bytes > WIRE_BUFSIZ) num_bytes = WIRE_BUFSIZ;
-
- rx_buf_idx = 0;
- rx_buf_len = 0;
-
- i2c_start(port);
-
- i2c_shift_out(port, (address << 1) | I2C_READ);
- if (!i2c_get_ack(port)) {
- //Serial1.print("requestFrom failed at byte ");
- //Serial1.print(rx_buf_len,10);
- //Serial1.println();
- return 0;
- }
-
- while (rx_buf_len < num_bytes) {
- rx_buf[rx_buf_len++] = i2c_shift_in(port);
- if(rx_buf_len < num_bytes) {
- i2c_send_ack(port);
- }
- }
-
- i2c_send_nack(port);
- i2c_stop(port);
-
- return rx_buf_len;
-}
-
-uint8 TwoWire::requestFrom(int address, int numBytes) {
- return TwoWire::requestFrom((uint8)address, (uint8) numBytes);
-}
-
-void TwoWire::send(uint8 value) {
- if (tx_buf_idx == WIRE_BUFSIZ) {
- tx_buf_overflow = true;
- return;
- }
-
- tx_buf[tx_buf_idx++] = value;
-}
-
-void TwoWire::send(uint8* buf, int len) {
- for (uint8 i = 0; i < len; i++) send(buf[i]);
-}
-
-void TwoWire::send(int value) {
- send((uint8)value);
-}
-
-void TwoWire::send(int* buf, int len) {
- send((uint8*)buf, (uint8)len);
-}
-
-void TwoWire::send(char* buf) {
- uint8 *ptr = (uint8*)buf;
- while(*ptr) {
- send(*ptr);
- ptr++;
- }
-}
-
-uint8 TwoWire::available() {
- return rx_buf_len - rx_buf_idx;
-}
-
-uint8 TwoWire::receive() {
- if (rx_buf_idx == rx_buf_len) return 0;
- return rx_buf[rx_buf_idx++];
-}
-
-// private methods
-
-uint8 TwoWire::writeOneByte(uint8 byte) {
- i2c_shift_out(port, byte);
- if (!i2c_get_ack(port)) return ENACKTRNS;
-
- return SUCCESS;
-}
-
-uint8 TwoWire::readOneByte(uint8 address, uint8 *byte) {
- i2c_start(port);
-
- i2c_shift_out(port, (address << 1) | I2C_READ);
- if (!i2c_get_ack(port)) return ENACKADDR;
-
- *byte = i2c_shift_in(port);
-
- i2c_send_nack(port);
- i2c_stop(port);
-
- return SUCCESS; // no real way of knowing, but be optimistic!
-}
-
-// Declare the instance that the users of the library can use
-TwoWire Wire;
-
+/******************************************************************************
+* The MIT License
+*
+* Copyright (c) 2010 LeafLabs LLC.
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to deal
+* in the Software without restriction, including without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+* THE SOFTWARE.
+*****************************************************************************/
+
+/**
+* @brief Wire library, ported from Arduino. Provides a simplistic
+* interface to i2c.
+*/
+
+#include "Wire.h"
+#include "wirish.h"
+
+/* low level conventions:
+* - SDA/SCL idle high (expected high)
+* - always start with i2c_delay rather than end
+*/
+uint32 i2c_delay = 1;
+
+void i2c_scl_low(Port port) {
+ digitalWrite(port.scl,LOW);
+ I2C_DELAY_SCL;
+}
+
+void i2c_scl_high(Port port) {
+ digitalWrite(port.scl,HIGH);
+ while(digitalRead(port.scl) == 0)
+ ;
+ I2C_DELAY_SCL;
+}
+
+void i2c_sda_high(Port port) {
+ digitalWrite(port.sda,HIGH);
+ I2C_DELAY_SDA;
+}
+
+void i2c_sda_low(Port port) {
+ digitalWrite(port.sda,LOW);
+ I2C_DELAY_SDA;
+}
+
+void i2c_start(Port port) {
+ i2c_sda_high(port);
+ i2c_scl_high(port);
+ i2c_sda_low(port);
+ i2c_scl_low(port);
+}
+
+void i2c_stop(Port port) {
+ i2c_sda_low(port);
+ i2c_scl_high(port);
+ i2c_sda_high(port);
+}
+
+boolean i2c_get_ack(Port port) {
+ i2c_sda_high(port);
+ i2c_scl_high(port);
+
+ bool ret =!digitalRead(port.sda);
+ i2c_scl_low(port);
+ return ret;
+}
+
+void i2c_send_ack(Port port) {
+ i2c_sda_low(port);
+ i2c_scl_high(port);
+ i2c_scl_low(port);
+}
+
+void i2c_send_nack(Port port) {
+ i2c_sda_high(port);
+ i2c_scl_high(port);
+ i2c_scl_low(port);
+}
+
+uint8 i2c_shift_in(Port port) {
+ uint8 data = 0;
+ i2c_sda_high(port);
+
+ int i;
+ for (i=0; i<8; i++) {
+ data <<= 1;
+ i2c_scl_high(port);
+ if(digitalRead(port.sda)) {
+ data |= 1;
+ }
+ i2c_scl_low(port);
+ }
+
+ return data;
+}
+
+void i2c_shift_out(Port port, uint8 val) {
+ int i;
+ for (i=0;i<8;i++) {
+ if((val & 0x80) != 0) {
+ i2c_sda_high(port);
+ } else {
+ i2c_sda_low(port);
+ }
+ val <<= 1;
+ i2c_scl_high(port);
+ i2c_scl_low(port);
+ }
+ /*
+ i2c_sda_high(port);
+ i2c_scl_high(port);
+ bool nack = digitalRead(port.sda);
+ i2c_scl_low(port);
+ */
+
+}
+
+TwoWire::TwoWire() {
+ i2c_delay = 0;
+ rx_buf_idx = 0;
+ rx_buf_len = 0;
+ tx_addr = 0;
+ tx_buf_idx = 0;
+ tx_buf_overflow = false;
+}
+
+/*
+* Sets pins SDA and SCL to OUPTUT_OPEN_DRAIN, joining I2C bus as
+* master. If you want them to be some other pins, use begin(uint8,
+* uint8);
+*/
+void TwoWire::begin() {
+ begin(SDA, SCL);
+}
+
+/*
+* Joins I2C bus as master on given SDA and SCL pins.
+*/
+void TwoWire::begin(uint8 sda, uint8 scl) {
+ port.sda = sda;
+ port.scl = scl;
+ pinMode(scl, OUTPUT_OPEN_DRAIN);
+ pinMode(sda, OUTPUT_OPEN_DRAIN);
+ digitalWrite(scl, HIGH);
+ digitalWrite(sda, HIGH);
+/*
+ long t0 = systick_get_count();
+ i2c_scl_high(port);
+ long t1 = systick_get_count();
+ Serial2.print("i2c_scl_high: ");
+ Serial2.print(t1-t0);
+ Serial2.println();
+*/
+}
+
+void TwoWire::beginTransmission(uint8 slave_address) {
+ tx_addr = slave_address;
+ tx_buf_idx = 0;
+ tx_buf_overflow = false;
+ rx_buf_idx = 0;
+ rx_buf_len = 0;
+}
+
+void TwoWire::beginTransmission(int slave_address) {
+ beginTransmission((uint8)slave_address);
+}
+
+uint8 TwoWire::endTransmission(void) {
+ if (tx_buf_overflow) return EDATA;
+
+ i2c_start(port);
+
+ i2c_shift_out(port, (tx_addr << 1) | I2C_WRITE);
+ if (!i2c_get_ack(port)) return ENACKADDR;
+
+ // shift out the address we're transmitting to
+ for (uint8 i = 0; i < tx_buf_idx; i++) {
+ uint8 ret = writeOneByte(tx_buf[i]);
+ if (ret) {
+ //Serial1.println("endTransmission failed");
+ return ret; // SUCCESS is 0
+ }
+ }
+
+ i2c_stop(port);
+
+ tx_buf_idx = 0;
+ tx_buf_overflow = false;
+ return SUCCESS;
+}
+
+#if 0
+uint8 TwoWire::requestFromOld(uint8 address, int num_bytes) {
+ if (num_bytes > WIRE_BUFSIZ) num_bytes = WIRE_BUFSIZ;
+
+ rx_buf_idx = 0;
+ rx_buf_len = 0;
+ while (rx_buf_len < num_bytes) {
+ if(!readOneByte(address, rx_buf + rx_buf_len))
+ rx_buf_len++;
+ else {
+ Serial1.print("requestFrom failed at byte ");
+ Serial1.print(rx_buf_len,10);
+ Serial1.println();
+ break;
+ }
+ }
+ return rx_buf_len;
+}
+#endif
+
+uint8 TwoWire::requestFrom(uint8 address, int num_bytes) {
+ if (num_bytes > WIRE_BUFSIZ) num_bytes = WIRE_BUFSIZ;
+
+ rx_buf_idx = 0;
+ rx_buf_len = 0;
+
+ i2c_start(port);
+
+ i2c_shift_out(port, (address << 1) | I2C_READ);
+ if (!i2c_get_ack(port)) {
+ //Serial1.print("requestFrom failed at byte ");
+ //Serial1.print(rx_buf_len,10);
+ //Serial1.println();
+ return 0;
+ }
+
+ while (rx_buf_len < num_bytes) {
+ rx_buf[rx_buf_len++] = i2c_shift_in(port);
+ if(rx_buf_len < num_bytes) {
+ i2c_send_ack(port);
+ }
+ }
+
+ i2c_send_nack(port);
+ i2c_stop(port);
+
+ return rx_buf_len;
+}
+
+uint8 TwoWire::requestFrom(int address, int numBytes) {
+ return TwoWire::requestFrom((uint8)address, (uint8) numBytes);
+}
+
+void TwoWire::send(uint8 value) {
+ if (tx_buf_idx == WIRE_BUFSIZ) {
+ tx_buf_overflow = true;
+ return;
+ }
+
+ tx_buf[tx_buf_idx++] = value;
+}
+
+void TwoWire::send(uint8* buf, int len) {
+ for (uint8 i = 0; i < len; i++) send(buf[i]);
+}
+
+void TwoWire::send(int value) {
+ send((uint8)value);
+}
+
+void TwoWire::send(int* buf, int len) {
+ send((uint8*)buf, (uint8)len);
+}
+
+void TwoWire::send(char* buf) {
+ uint8 *ptr = (uint8*)buf;
+ while(*ptr) {
+ send(*ptr);
+ ptr++;
+ }
+}
+
+uint8 TwoWire::available() {
+ return rx_buf_len - rx_buf_idx;
+}
+
+uint8 TwoWire::receive() {
+ if (rx_buf_idx == rx_buf_len) return 0;
+ return rx_buf[rx_buf_idx++];
+}
+
+// private methods
+
+uint8 TwoWire::writeOneByte(uint8 byte) {
+ i2c_shift_out(port, byte);
+ if (!i2c_get_ack(port)) return ENACKTRNS;
+
+ return SUCCESS;
+}
+
+uint8 TwoWire::readOneByte(uint8 address, uint8 *byte) {
+ i2c_start(port);
+
+ i2c_shift_out(port, (address << 1) | I2C_READ);
+ if (!i2c_get_ack(port)) return ENACKADDR;
+
+ *byte = i2c_shift_in(port);
+
+ i2c_send_nack(port);
+ i2c_stop(port);
+
+ return SUCCESS; // no real way of knowing, but be optimistic!
+}
+
+// Declare the instance that the users of the library can use
+TwoWire Wire;
+
diff --git a/Libmaple/libmaple/libraries/Wire/Wire.h b/Libmaple/libmaple/libraries/Wire/Wire.h
index e399e988..ce3dd3e7 100644
--- a/Libmaple/libmaple/libraries/Wire/Wire.h
+++ b/Libmaple/libmaple/libraries/Wire/Wire.h
@@ -1,112 +1,112 @@
-/* *****************************************************************************
- * The MIT License
- *
- * Copyright (c) 2010 LeafLabs LLC.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- * ****************************************************************************/
-
-/**
- * @brief Wire library, ported from Arduino. Provides a lean
- * interface to I2C (two-wire) communication.
- */
-
-#include "wirish.h"
-
-#ifndef _WIRE_H_
-#define _WIRE_H_
-
-typedef struct {
- uint8 scl;
- uint8 sda;
-} Port;
-
-/* You must update the online docs if you change this value. */
-#define WIRE_BUFSIZ 32
-
-/* return codes from endTransmission() */
-#define SUCCESS 0 /* transmission was successful */
-#define EDATA 1 /* too much data */
-#define ENACKADDR 2 /* received nack on transmit of address */
-#define ENACKTRNS 3 /* received nack on transmit of data */
-#define EOTHER 4 /* other error */
-
-#define SDA 20
-#define SCL 21
-
-#define I2C_WRITE 0
-#define I2C_READ 1
-
-#if (F_CPU == 168000000)
- #define I2C_DELAY_SCL delay_ns100(6)
- #define I2C_DELAY_SDA delay_ns100(2)
-#else
- #define I2C_DELAY_SCL
- #define I2C_DELAY_SDA
-#endif
-
-class TwoWire {
- private:
- uint8 rx_buf[WIRE_BUFSIZ]; /* receive buffer */
- uint8 rx_buf_idx; /* first unread idx in rx_buf */
- uint8 rx_buf_len; /* number of bytes read */
-
- uint8 tx_addr; /* address transmitting to */
- uint8 tx_buf[WIRE_BUFSIZ]; /* transmit buffer */
- uint8 tx_buf_idx; /* next idx available in tx_buf, -1 overflow */
- boolean tx_buf_overflow;
- Port port;
- uint8 writeOneByte(uint8);
- uint8 readOneByte(uint8, uint8*);
- public:
- TwoWire();
- void begin();
- void begin(uint8, uint8);
- void beginTransmission(uint8);
- void beginTransmission(int);
- uint8 endTransmission(void);
- uint8 requestFrom(uint8, int);
- uint8 requestFrom(int, int);
- void send(uint8);
- void send(uint8*, int);
- void send(int);
- void send(int*, int);
- void send(char*);
- uint8 available();
- uint8 receive();
-
- uint8 read() { return receive(); };
- void write(uint8 data) { send(data); };
- void write(uint8* buf, int len) { send(buf, len); };
- void write(int data) { send(data); };
- void write(int* buf, int len) { send(buf, len); };
- void write(char* buf) { send(buf); };
-};
-
-void i2c_start(Port port);
-void i2c_stop(Port port);
-boolean i2c_get_ack(Port port);
-void i2c_send_ack(Port port);
-void i2c_send_nack(Port port);
-uint8 i2c_shift_in(Port port);
-void i2c_shift_out(Port port, uint8 val);
-
-extern TwoWire Wire;
-
-#endif // _WIRE_H_
+/* *****************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 LeafLabs LLC.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ * ****************************************************************************/
+
+/**
+ * @brief Wire library, ported from Arduino. Provides a lean
+ * interface to I2C (two-wire) communication.
+ */
+
+#include "wirish.h"
+
+#ifndef _WIRE_H_
+#define _WIRE_H_
+
+typedef struct {
+ uint8 scl;
+ uint8 sda;
+} Port;
+
+/* You must update the online docs if you change this value. */
+#define WIRE_BUFSIZ 32
+
+/* return codes from endTransmission() */
+#define SUCCESS 0 /* transmission was successful */
+#define EDATA 1 /* too much data */
+#define ENACKADDR 2 /* received nack on transmit of address */
+#define ENACKTRNS 3 /* received nack on transmit of data */
+#define EOTHER 4 /* other error */
+
+#define SDA 20
+#define SCL 21
+
+#define I2C_WRITE 0
+#define I2C_READ 1
+
+#if (F_CPU == 168000000)
+ #define I2C_DELAY_SCL delay_ns100(6)
+ #define I2C_DELAY_SDA delay_ns100(2)
+#else
+ #define I2C_DELAY_SCL
+ #define I2C_DELAY_SDA
+#endif
+
+class TwoWire {
+ private:
+ uint8 rx_buf[WIRE_BUFSIZ]; /* receive buffer */
+ uint8 rx_buf_idx; /* first unread idx in rx_buf */
+ uint8 rx_buf_len; /* number of bytes read */
+
+ uint8 tx_addr; /* address transmitting to */
+ uint8 tx_buf[WIRE_BUFSIZ]; /* transmit buffer */
+ uint8 tx_buf_idx; /* next idx available in tx_buf, -1 overflow */
+ boolean tx_buf_overflow;
+ Port port;
+ uint8 writeOneByte(uint8);
+ uint8 readOneByte(uint8, uint8*);
+ public:
+ TwoWire();
+ void begin();
+ void begin(uint8, uint8);
+ void beginTransmission(uint8);
+ void beginTransmission(int);
+ uint8 endTransmission(void);
+ uint8 requestFrom(uint8, int);
+ uint8 requestFrom(int, int);
+ void send(uint8);
+ void send(uint8*, int);
+ void send(int);
+ void send(int*, int);
+ void send(char*);
+ uint8 available();
+ uint8 receive();
+
+ uint8 read() { return receive(); };
+ void write(uint8 data) { send(data); };
+ void write(uint8* buf, int len) { send(buf, len); };
+ void write(int data) { send(data); };
+ void write(int* buf, int len) { send(buf, len); };
+ void write(char* buf) { send(buf); };
+};
+
+void i2c_start(Port port);
+void i2c_stop(Port port);
+boolean i2c_get_ack(Port port);
+void i2c_send_ack(Port port);
+void i2c_send_nack(Port port);
+uint8 i2c_shift_in(Port port);
+void i2c_shift_out(Port port, uint8 val);
+
+extern TwoWire Wire;
+
+#endif // _WIRE_H_
diff --git a/Libmaple/libmaple/libraries/Wire/rules.mk b/Libmaple/libmaple/libraries/Wire/rules.mk
index f442564b..71f5e75b 100644
--- a/Libmaple/libmaple/libraries/Wire/rules.mk
+++ b/Libmaple/libmaple/libraries/Wire/rules.mk
@@ -1,29 +1,29 @@
-# Standard things
-sp := $(sp).x
-dirstack_$(sp) := $(d)
-d := $(dir)
-BUILDDIRS += $(BUILD_PATH)/$(d)
-
-# Local flags
-CFLAGS_$(d) := $(WIRISH_INCLUDES) $(LIBMAPLE_INCLUDES)
-
-# Local rules and targets
-cSRCS_$(d) :=
-
-cppSRCS_$(d) := Wire.cpp
-
-cFILES_$(d) := $(cSRCS_$(d):%=$(d)/%)
-cppFILES_$(d) := $(cppSRCS_$(d):%=$(d)/%)
-
-OBJS_$(d) := $(cFILES_$(d):%.c=$(BUILD_PATH)/%.o) \
- $(cppFILES_$(d):%.cpp=$(BUILD_PATH)/%.o)
-DEPS_$(d) := $(OBJS_$(d):%.o=%.d)
-
-$(OBJS_$(d)): TGT_CFLAGS := $(CFLAGS_$(d))
-
-TGT_BIN += $(OBJS_$(d))
-
-# Standard things
--include $(DEPS_$(d))
-d := $(dirstack_$(sp))
+# Standard things
+sp := $(sp).x
+dirstack_$(sp) := $(d)
+d := $(dir)
+BUILDDIRS += $(BUILD_PATH)/$(d)
+
+# Local flags
+CFLAGS_$(d) := $(WIRISH_INCLUDES) $(LIBMAPLE_INCLUDES)
+
+# Local rules and targets
+cSRCS_$(d) :=
+
+cppSRCS_$(d) := Wire.cpp
+
+cFILES_$(d) := $(cSRCS_$(d):%=$(d)/%)
+cppFILES_$(d) := $(cppSRCS_$(d):%=$(d)/%)
+
+OBJS_$(d) := $(cFILES_$(d):%.c=$(BUILD_PATH)/%.o) \
+ $(cppFILES_$(d):%.cpp=$(BUILD_PATH)/%.o)
+DEPS_$(d) := $(OBJS_$(d):%.o=%.d)
+
+$(OBJS_$(d)): TGT_CFLAGS := $(CFLAGS_$(d))
+
+TGT_BIN += $(OBJS_$(d))
+
+# Standard things
+-include $(DEPS_$(d))
+d := $(dirstack_$(sp))
sp := $(basename $(sp))
\ No newline at end of file
diff --git a/Libmaple/libmaple/libraries/mapleSDfat/Document1.txt b/Libmaple/libmaple/libraries/mapleSDfat/Document1.txt
index 9c61eb34..9a5d8851 100644
--- a/Libmaple/libmaple/libraries/mapleSDfat/Document1.txt
+++ b/Libmaple/libmaple/libraries/mapleSDfat/Document1.txt
@@ -1,38 +1,38 @@
-EB 3C 90
-4D 53 44 4F 53 35 2E 30
-0 2
-40
-8 0
-2 fat count
-0 2
-0 0 F8 F0 0 3F 0 FF 0 3F 0 0 0
-C1 FF 3B 0 80 0 29 4D C5 39 80 4E 4F 20 4E 41
-4D 45 20 20 20 20 46 41 54 31 36 20 20 20 33 C9
-8E D1 BC F0 7B 8E D9 B8 0 20 8E C0 FC BD 0 7C
-38 4E 24 7D 24 8B C1 99 E8 3C 1 72 1C 83 EB 3A
-66 A1 1C 7C 26 66 3B 7 26 8A 57 FC 75 6 80 CA
-2 88 56 2 80 C3 10 73 EB 33 C9 8A 46 10 98 F7
-66 16 3 46 1C 13 56 1E 3 46 E 13 D1 8B 76 11
-60 89 46 FC 89 56 FE B8 20 0 F7 E6 8B 5E B 3
-C3 48 F7 F3 1 46 FC 11 4E FE 61 BF 0 0 E8 E6
-0 72 39 26 38 2D 74 17 60 B1 B BE A1 7D F3 A6
-61 74 32 4E 74 9 83 C7 20 3B FB 72 E6 EB DC A0
-FB 7D B4 7D 8B F0 AC 98 40 74 C 48 74 13 B4 E
-BB 7 0 CD 10 EB EF A0 FD 7D EB E6 A0 FC 7D EB
-E1 CD 16 CD 19 26 8B 55 1A 52 B0 1 BB 0 0 E8
-3B 0 72 E8 5B 8A 56 24 BE B 7C 8B FC C7 46 F0
-3D 7D C7 46 F4 29 7D 8C D9 89 4E F2 89 4E F6 C6
-6 96 7D CB EA 3 0 0 20 F B6 C8 66 8B 46 F8
-66 3 46 1C 66 8B D0 66 C1 EA 10 EB 5E F B6 C8
-4A 4A 8A 46 D 32 E4 F7 E2 3 46 FC 13 56 FE EB
-4A 52 50 6 53 6A 1 6A 10 91 8B 46 18 96 92 33
-D2 F7 F6 91 F7 F6 42 87 CA F7 76 1A 8A F2 8A E8
-C0 CC 2 A CC B8 1 2 80 7E 2 E 75 4 B4 42
-8B F4 8A 56 24 CD 13 61 61 72 B 40 75 1 42 3
-5E B 49 75 6 F8 C3 41 BB 0 0 60 66 6A 0 EB
-B0 4E 54 4C 44 52 20 20 20 20 20 20 D A 52 65
-6D 6F 76 65 20 64 69 73 6B 73 20 6F 72 20 6F 74
-68 65 72 20 6D 65 64 69 61 2E FF D A 44 69 73
-6B 20 65 72 72 6F 72 FF D A 50 72 65 73 73 20
-61 6E 79 20 6B 65 79 20 74 6F 20 72 65 73 74 61
+EB 3C 90
+4D 53 44 4F 53 35 2E 30
+0 2
+40
+8 0
+2 fat count
+0 2
+0 0 F8 F0 0 3F 0 FF 0 3F 0 0 0
+C1 FF 3B 0 80 0 29 4D C5 39 80 4E 4F 20 4E 41
+4D 45 20 20 20 20 46 41 54 31 36 20 20 20 33 C9
+8E D1 BC F0 7B 8E D9 B8 0 20 8E C0 FC BD 0 7C
+38 4E 24 7D 24 8B C1 99 E8 3C 1 72 1C 83 EB 3A
+66 A1 1C 7C 26 66 3B 7 26 8A 57 FC 75 6 80 CA
+2 88 56 2 80 C3 10 73 EB 33 C9 8A 46 10 98 F7
+66 16 3 46 1C 13 56 1E 3 46 E 13 D1 8B 76 11
+60 89 46 FC 89 56 FE B8 20 0 F7 E6 8B 5E B 3
+C3 48 F7 F3 1 46 FC 11 4E FE 61 BF 0 0 E8 E6
+0 72 39 26 38 2D 74 17 60 B1 B BE A1 7D F3 A6
+61 74 32 4E 74 9 83 C7 20 3B FB 72 E6 EB DC A0
+FB 7D B4 7D 8B F0 AC 98 40 74 C 48 74 13 B4 E
+BB 7 0 CD 10 EB EF A0 FD 7D EB E6 A0 FC 7D EB
+E1 CD 16 CD 19 26 8B 55 1A 52 B0 1 BB 0 0 E8
+3B 0 72 E8 5B 8A 56 24 BE B 7C 8B FC C7 46 F0
+3D 7D C7 46 F4 29 7D 8C D9 89 4E F2 89 4E F6 C6
+6 96 7D CB EA 3 0 0 20 F B6 C8 66 8B 46 F8
+66 3 46 1C 66 8B D0 66 C1 EA 10 EB 5E F B6 C8
+4A 4A 8A 46 D 32 E4 F7 E2 3 46 FC 13 56 FE EB
+4A 52 50 6 53 6A 1 6A 10 91 8B 46 18 96 92 33
+D2 F7 F6 91 F7 F6 42 87 CA F7 76 1A 8A F2 8A E8
+C0 CC 2 A CC B8 1 2 80 7E 2 E 75 4 B4 42
+8B F4 8A 56 24 CD 13 61 61 72 B 40 75 1 42 3
+5E B 49 75 6 F8 C3 41 BB 0 0 60 66 6A 0 EB
+B0 4E 54 4C 44 52 20 20 20 20 20 20 D A 52 65
+6D 6F 76 65 20 64 69 73 6B 73 20 6F 72 20 6F 74
+68 65 72 20 6D 65 64 69 61 2E FF D A 44 69 73
+6B 20 65 72 72 6F 72 FF D A 50 72 65 73 73 20
+61 6E 79 20 6B 65 79 20 74 6F 20 72 65 73 74 61
72 74 D A 0 0 0 0 0 0 0 AC CB D8 55 AA
\ No newline at end of file
diff --git a/Libmaple/libmaple/libraries/mapleSDfat/FatStructs.h b/Libmaple/libmaple/libraries/mapleSDfat/FatStructs.h
index e6ef84c2..b775c7e5 100644
--- a/Libmaple/libmaple/libraries/mapleSDfat/FatStructs.h
+++ b/Libmaple/libmaple/libraries/mapleSDfat/FatStructs.h
@@ -1,420 +1,420 @@
-/* Arduino SdFat Library
- * Copyright (C) 2009 by William Greiman
- *
- * This file is part of the Arduino SdFat Library
- *
- * This Library is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This Library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with the Arduino SdFat Library. If not, see
- * .
- */
-#ifndef FatStructs_h
-#define FatStructs_h
-
-/**
- * \file
- * FAT file structures
- */
-/*
- * mostly from Microsoft document fatgen103.doc
- * http://www.microsoft.com/whdc/system/platform/firmware/fatgen.mspx
- */
-//------------------------------------------------------------------------------
-/** Value for byte 510 of boot block or MBR */
-uint8_t const BOOTSIG0 = 0X55;
-/** Value for byte 511 of boot block or MBR */
-uint8_t const BOOTSIG1 = 0XAA;
-//------------------------------------------------------------------------------
-/**
- * \struct partitionTable
- * \brief MBR partition table entry
- *
- * A partition table entry for a MBR formatted storage device.
- * The MBR partition table has four entries.
- */
-struct partitionTable {
- /**
- * Boot Indicator . Indicates whether the volume is the active
- * partition. Legal values include: 0X00. Do not use for booting.
- * 0X80 Active partition.
- */
- uint8_t boot;
- /**
- * Head part of Cylinder-head-sector address of the first block in
- * the partition. Legal values are 0-255. Only used in old PC BIOS.
- */
- uint8_t beginHead;
- /**
- * Sector part of Cylinder-head-sector address of the first block in
- * the partition. Legal values are 1-63. Only used in old PC BIOS.
- */
-
- uint8_t beginSector : 6;
- /** High bits cylinder for first block in partition. */
- uint8_t beginCylinderHigh : 2;
- /**
- * Combine beginCylinderLow with beginCylinderHigh. Legal values
- * are 0-1023. Only used in old PC BIOS.
- */
- uint8_t beginCylinderLow;
- /**
- * Partition type. See defines that begin with PART_TYPE_ for
- * some Microsoft partition types.
- */
- uint8_t type;
- /**
- * head part of cylinder-head-sector address of the last sector in the
- * partition. Legal values are 0-255. Only used in old PC BIOS.
- */
- uint8_t endHead;
- /**
- * Sector part of cylinder-head-sector address of the last sector in
- * the partition. Legal values are 1-63. Only used in old PC BIOS.
- */
- uint8_t endSector : 6;
- /** High bits of end cylinder */
- uint8_t endCylinderHigh : 2;
- /**
- * Combine endCylinderLow with endCylinderHigh. Legal values
- * are 0-1023. Only used in old PC BIOS.
- */
- uint8_t endCylinderLow;
- /** Logical block address of the first block in the partition. */
- uint32_t firstSector;
- /** Length of the partition, in blocks. */
- uint32_t totalSectors;
-}__attribute__ ((packed));
-/** Type name for partitionTable */
-typedef struct partitionTable part_t;
-//------------------------------------------------------------------------------
-/**
- * \struct masterBootRecord
- *
- * \brief Master Boot Record
- *
- * The first block of a storage device that is formatted with a MBR.
- */
-struct masterBootRecord {
- /** Code Area for master boot program. */
- uint8_t codeArea[440];
- /** Optional WindowsNT disk signature. May contain more boot code. */
- uint32_t diskSignature;
- /** Usually zero but may be more boot code. */
- uint16_t usuallyZero;
- /** Partition tables. */
- part_t part[4];
- /** First MBR signature byte. Must be 0X55 */
- uint8_t mbrSig0;
- /** Second MBR signature byte. Must be 0XAA */
- uint8_t mbrSig1;
-}__attribute__ ((packed));
-/** Type name for masterBootRecord */
-typedef struct masterBootRecord mbr_t;
-//------------------------------------------------------------------------------
-/**
- * \struct biosParmBlock
- *
- * \brief BIOS parameter block
- *
- * The BIOS parameter block describes the physical layout of a FAT volume.
- */
-struct biosParmBlock {
- /**
- * Count of bytes per sector. This value may take on only the
- * following values: 512, 1024, 2048 or 4096
- */
- uint16_t bytesPerSector;
- /**
- * Number of sectors per allocation unit. This value must be a
- * power of 2 that is greater than 0. The legal values are
- * 1, 2, 4, 8, 16, 32, 64, and 128.
- */
- uint8_t sectorsPerCluster;
- /**
- * Number of sectors before the first FAT.
- * This value must not be zero.
- */
- uint16_t reservedSectorCount;
- /** The count of FAT data structures on the volume. This field should
- * always contain the value 2 for any FAT volume of any type.
- */
- uint8_t fatCount;
- /**
- * For FAT12 and FAT16 volumes, this field contains the count of
- * 32-byte directory entries in the root directory. For FAT32 volumes,
- * this field must be set to 0. For FAT12 and FAT16 volumes, this
- * value should always specify a count that when multiplied by 32
- * results in a multiple of bytesPerSector. FAT16 volumes should
- * use the value 512.
- */
- uint16_t rootDirEntryCount;
- /**
- * This field is the old 16-bit total count of sectors on the volume.
- * This count includes the count of all sectors in all four regions
- * of the volume. This field can be 0; if it is 0, then totalSectors32
- * must be non-zero. For FAT32 volumes, this field must be 0. For
- * FAT12 and FAT16 volumes, this field contains the sector count, and
- * totalSectors32 is 0 if the total sector count fits
- * (is less than 0x10000).
- */
- uint16_t totalSectors16;
- /**
- * This dates back to the old MS-DOS 1.x media determination and is
- * no longer usually used for anything. 0xF8 is the standard value
- * for fixed (non-removable) media. For removable media, 0xF0 is
- * frequently used. Legal values are 0xF0 or 0xF8-0xFF.
- */
- uint8_t mediaType;
- /**
- * Count of sectors occupied by one FAT on FAT12/FAT16 volumes.
- * On FAT32 volumes this field must be 0, and sectorsPerFat32
- * contains the FAT size count.
- */
- uint16_t sectorsPerFat16;
- /** Sectors per track for interrupt 0x13. Not used otherwise. */
- uint16_t sectorsPerTrtack;
- /** Number of heads for interrupt 0x13. Not used otherwise. */
- uint16_t headCount;
- /**
- * Count of hidden sectors preceding the partition that contains this
- * FAT volume. This field is generally only relevant for media
- * visible on interrupt 0x13.
- */
- uint32_t hidddenSectors;
- /**
- * This field is the new 32-bit total count of sectors on the volume.
- * This count includes the count of all sectors in all four regions
- * of the volume. This field can be 0; if it is 0, then
- * totalSectors16 must be non-zero.
- */
- uint32_t totalSectors32;
- /**
- * Count of sectors occupied by one FAT on FAT32 volumes.
- */
- uint32_t sectorsPerFat32;
- /**
- * This field is only defined for FAT32 media and does not exist on
- * FAT12 and FAT16 media.
- * Bits 0-3 -- Zero-based number of active FAT.
- * Only valid if mirroring is disabled.
- * Bits 4-6 -- Reserved.
- * Bit 7 -- 0 means the FAT is mirrored at runtime into all FATs.
- * -- 1 means only one FAT is active; it is the one referenced in bits 0-3.
- * Bits 8-15 -- Reserved.
- */
- uint16_t fat32Flags;
- /**
- * FAT32 version. High byte is major revision number.
- * Low byte is minor revision number. Only 0.0 define.
- */
- uint16_t fat32Version;
- /**
- * Cluster number of the first cluster of the root directory for FAT32.
- * This usually 2 but not required to be 2.
- */
- uint32_t fat32RootCluster;
- /**
- * Sector number of FSINFO structure in the reserved area of the
- * FAT32 volume. Usually 1.
- */
- uint16_t fat32FSInfo;
- /**
- * If non-zero, indicates the sector number in the reserved area
- * of the volume of a copy of the boot record. Usually 6.
- * No value other than 6 is recommended.
- */
- uint16_t fat32BackBootBlock;
- /**
- * Reserved for future expansion. Code that formats FAT32 volumes
- * should always set all of the bytes of this field to 0.
- */
- uint8_t fat32Reserved[12];
-}__attribute__ ((packed));
-/** Type name for biosParmBlock */
-typedef struct biosParmBlock bpb_t;
-//------------------------------------------------------------------------------
-/**
- * \struct fat32BootSector
- *
- * \brief Boot sector for a FAT16 or FAT32 volume.
- *
- */
-struct fat32BootSector {
- /** X86 jmp to boot program */
- uint8_t jmpToBootCode[3];
- /** informational only - don't depend on it */
- uint8_t oemName[8];
- /** BIOS Parameter Block */
- bpb_t bpb;
- /** for int0x13 use value 0X80 for hard drive */
- uint8_t driveNumber;
- /** used by Windows NT - should be zero for FAT */
- uint8_t reserved1;
- /** 0X29 if next three fields are valid */
- uint8_t bootSignature;
- /** usually generated by combining date and time */
- uint32_t volumeSerialNumber;
- /** should match volume label in root dir */
- uint8_t volumeLabel[11];
- /** informational only - don't depend on it */
- uint8_t fileSystemType[8];
- /** X86 boot code */
- uint8_t bootCode[420];
- /** must be 0X55 */
- uint8_t bootSectorSig0;
- /** must be 0XAA */
- uint8_t bootSectorSig1;
-}__attribute__ ((packed));
-//------------------------------------------------------------------------------
-// End Of Chain values for FAT entries
-/** FAT16 end of chain value used by Microsoft. */
-uint16_t const FAT16EOC = 0XFFFF;
-/** Minimum value for FAT16 EOC. Use to test for EOC. */
-uint16_t const FAT16EOC_MIN = 0XFFF8;
-/** FAT32 end of chain value used by Microsoft. */
-uint32_t const FAT32EOC = 0X0FFFFFFF;
-/** Minimum value for FAT32 EOC. Use to test for EOC. */
-uint32_t const FAT32EOC_MIN = 0X0FFFFFF8;
-/** Mask a for FAT32 entry. Entries are 28 bits. */
-uint32_t const FAT32MASK = 0X0FFFFFFF;
-
-/** Type name for fat32BootSector */
-typedef struct fat32BootSector fbs_t;
-//------------------------------------------------------------------------------
-/**
- * \struct directoryEntry
- * \brief FAT short directory entry
- *
- * Short means short 8.3 name, not the entry size.
- *
- * Date Format. A FAT directory entry date stamp is a 16-bit field that is
- * basically a date relative to the MS-DOS epoch of 01/01/1980. Here is the
- * format (bit 0 is the LSB of the 16-bit word, bit 15 is the MSB of the
- * 16-bit word):
- *
- * Bits 9-15: Count of years from 1980, valid value range 0-127
- * inclusive (1980-2107).
- *
- * Bits 5-8: Month of year, 1 = January, valid value range 1-12 inclusive.
- *
- * Bits 0-4: Day of month, valid value range 1-31 inclusive.
- *
- * Time Format. A FAT directory entry time stamp is a 16-bit field that has
- * a granularity of 2 seconds. Here is the format (bit 0 is the LSB of the
- * 16-bit word, bit 15 is the MSB of the 16-bit word).
- *
- * Bits 11-15: Hours, valid value range 0-23 inclusive.
- *
- * Bits 5-10: Minutes, valid value range 0-59 inclusive.
- *
- * Bits 0-4: 2-second count, valid value range 0-29 inclusive (0 - 58 seconds).
- *
- * The valid time range is from Midnight 00:00:00 to 23:59:58.
- */
-struct directoryEntry {
- /**
- * Short 8.3 name.
- * The first eight bytes contain the file name with blank fill.
- * The last three bytes contain the file extension with blank fill.
- */
- uint8_t name[11];
- /** Entry attributes.
- *
- * The upper two bits of the attribute byte are reserved and should
- * always be set to 0 when a file is created and never modified or
- * looked at after that. See defines that begin with DIR_ATT_.
- */
- uint8_t attributes;
- /**
- * Reserved for use by Windows NT. Set value to 0 when a file is
- * created and never modify or look at it after that.
- */
- uint8_t reservedNT;
- /**
- * The granularity of the seconds part of creationTime is 2 seconds
- * so this field is a count of tenths of a second and its valid
- * value range is 0-199 inclusive. (WHG note - seems to be hundredths)
- */
- uint8_t creationTimeTenths;
- /** Time file was created. */
- uint16_t creationTime;
- /** Date file was created. */
- uint16_t creationDate;
- /**
- * Last access date. Note that there is no last access time, only
- * a date. This is the date of last read or write. In the case of
- * a write, this should be set to the same date as lastWriteDate.
- */
- uint16_t lastAccessDate;
- /**
- * High word of this entry's first cluster number (always 0 for a
- * FAT12 or FAT16 volume).
- */
- uint16_t firstClusterHigh;
- /** Time of last write. File creation is considered a write. */
- uint16_t lastWriteTime;
- /** Date of last write. File creation is considered a write. */
- uint16_t lastWriteDate;
- /** Low word of this entry's first cluster number. */
- uint16_t firstClusterLow;
- /** 32-bit unsigned holding this file's size in bytes. */
- uint32_t fileSize;
-}__attribute__ ((packed));
-//------------------------------------------------------------------------------
-// Definitions for directory entries
-//
-/** Type name for directoryEntry */
-typedef struct directoryEntry dir_t;
-/** escape for name[0] = 0XE5 */
-uint8_t const DIR_NAME_0XE5 = 0X05;
-/** name[0] value for entry that is free after being "deleted" */
-uint8_t const DIR_NAME_DELETED = 0XE5;
-/** name[0] value for entry that is free and no allocated entries follow */
-uint8_t const DIR_NAME_FREE = 0X00;
-/** file is read-only */
-uint8_t const DIR_ATT_READ_ONLY = 0X01;
-/** File should hidden in directory listings */
-uint8_t const DIR_ATT_HIDDEN = 0X02;
-/** Entry is for a system file */
-uint8_t const DIR_ATT_SYSTEM = 0X04;
-/** Directory entry contains the volume label */
-uint8_t const DIR_ATT_VOLUME_ID = 0X08;
-/** Entry is for a directory */
-uint8_t const DIR_ATT_DIRECTORY = 0X10;
-/** Old DOS archive bit for backup support */
-uint8_t const DIR_ATT_ARCHIVE = 0X20;
-/** Test value for long name entry. Test is
- (d->attributes & DIR_ATT_LONG_NAME_MASK) == DIR_ATT_LONG_NAME. */
-uint8_t const DIR_ATT_LONG_NAME = 0X0F;
-/** Test mask for long name entry */
-uint8_t const DIR_ATT_LONG_NAME_MASK = 0X3F;
-/** defined attribute bits */
-uint8_t const DIR_ATT_DEFINED_BITS = 0X3F;
-/** Directory entry is part of a long name */
-static inline uint8_t DIR_IS_LONG_NAME(const dir_t* dir) {
- return (dir->attributes & DIR_ATT_LONG_NAME_MASK) == DIR_ATT_LONG_NAME;
-}
-/** Mask for file/subdirectory tests */
-uint8_t const DIR_ATT_FILE_TYPE_MASK = (DIR_ATT_VOLUME_ID | DIR_ATT_DIRECTORY);
-/** Directory entry is for a file */
-static inline uint8_t DIR_IS_FILE(const dir_t* dir) {
- return (dir->attributes & DIR_ATT_FILE_TYPE_MASK) == 0;
-}
-/** Directory entry is for a subdirectory */
-static inline uint8_t DIR_IS_SUBDIR(const dir_t* dir) {
- return (dir->attributes & DIR_ATT_FILE_TYPE_MASK) == DIR_ATT_DIRECTORY;
-}
-/** Directory entry is for a file or subdirectory */
-static inline uint8_t DIR_IS_FILE_OR_SUBDIR(const dir_t* dir) {
- return (dir->attributes & DIR_ATT_VOLUME_ID) == 0;
-}
-#endif // FatStructs_h
+/* Arduino SdFat Library
+ * Copyright (C) 2009 by William Greiman
+ *
+ * This file is part of the Arduino SdFat Library
+ *
+ * This Library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Arduino SdFat Library. If not, see
+ * .
+ */
+#ifndef FatStructs_h
+#define FatStructs_h
+
+/**
+ * \file
+ * FAT file structures
+ */
+/*
+ * mostly from Microsoft document fatgen103.doc
+ * http://www.microsoft.com/whdc/system/platform/firmware/fatgen.mspx
+ */
+//------------------------------------------------------------------------------
+/** Value for byte 510 of boot block or MBR */
+uint8_t const BOOTSIG0 = 0X55;
+/** Value for byte 511 of boot block or MBR */
+uint8_t const BOOTSIG1 = 0XAA;
+//------------------------------------------------------------------------------
+/**
+ * \struct partitionTable
+ * \brief MBR partition table entry
+ *
+ * A partition table entry for a MBR formatted storage device.
+ * The MBR partition table has four entries.
+ */
+struct partitionTable {
+ /**
+ * Boot Indicator . Indicates whether the volume is the active
+ * partition. Legal values include: 0X00. Do not use for booting.
+ * 0X80 Active partition.
+ */
+ uint8_t boot;
+ /**
+ * Head part of Cylinder-head-sector address of the first block in
+ * the partition. Legal values are 0-255. Only used in old PC BIOS.
+ */
+ uint8_t beginHead;
+ /**
+ * Sector part of Cylinder-head-sector address of the first block in
+ * the partition. Legal values are 1-63. Only used in old PC BIOS.
+ */
+
+ uint8_t beginSector : 6;
+ /** High bits cylinder for first block in partition. */
+ uint8_t beginCylinderHigh : 2;
+ /**
+ * Combine beginCylinderLow with beginCylinderHigh. Legal values
+ * are 0-1023. Only used in old PC BIOS.
+ */
+ uint8_t beginCylinderLow;
+ /**
+ * Partition type. See defines that begin with PART_TYPE_ for
+ * some Microsoft partition types.
+ */
+ uint8_t type;
+ /**
+ * head part of cylinder-head-sector address of the last sector in the
+ * partition. Legal values are 0-255. Only used in old PC BIOS.
+ */
+ uint8_t endHead;
+ /**
+ * Sector part of cylinder-head-sector address of the last sector in
+ * the partition. Legal values are 1-63. Only used in old PC BIOS.
+ */
+ uint8_t endSector : 6;
+ /** High bits of end cylinder */
+ uint8_t endCylinderHigh : 2;
+ /**
+ * Combine endCylinderLow with endCylinderHigh. Legal values
+ * are 0-1023. Only used in old PC BIOS.
+ */
+ uint8_t endCylinderLow;
+ /** Logical block address of the first block in the partition. */
+ uint32_t firstSector;
+ /** Length of the partition, in blocks. */
+ uint32_t totalSectors;
+}__attribute__ ((packed));
+/** Type name for partitionTable */
+typedef struct partitionTable part_t;
+//------------------------------------------------------------------------------
+/**
+ * \struct masterBootRecord
+ *
+ * \brief Master Boot Record
+ *
+ * The first block of a storage device that is formatted with a MBR.
+ */
+struct masterBootRecord {
+ /** Code Area for master boot program. */
+ uint8_t codeArea[440];
+ /** Optional WindowsNT disk signature. May contain more boot code. */
+ uint32_t diskSignature;
+ /** Usually zero but may be more boot code. */
+ uint16_t usuallyZero;
+ /** Partition tables. */
+ part_t part[4];
+ /** First MBR signature byte. Must be 0X55 */
+ uint8_t mbrSig0;
+ /** Second MBR signature byte. Must be 0XAA */
+ uint8_t mbrSig1;
+}__attribute__ ((packed));
+/** Type name for masterBootRecord */
+typedef struct masterBootRecord mbr_t;
+//------------------------------------------------------------------------------
+/**
+ * \struct biosParmBlock
+ *
+ * \brief BIOS parameter block
+ *
+ * The BIOS parameter block describes the physical layout of a FAT volume.
+ */
+struct biosParmBlock {
+ /**
+ * Count of bytes per sector. This value may take on only the
+ * following values: 512, 1024, 2048 or 4096
+ */
+ uint16_t bytesPerSector;
+ /**
+ * Number of sectors per allocation unit. This value must be a
+ * power of 2 that is greater than 0. The legal values are
+ * 1, 2, 4, 8, 16, 32, 64, and 128.
+ */
+ uint8_t sectorsPerCluster;
+ /**
+ * Number of sectors before the first FAT.
+ * This value must not be zero.
+ */
+ uint16_t reservedSectorCount;
+ /** The count of FAT data structures on the volume. This field should
+ * always contain the value 2 for any FAT volume of any type.
+ */
+ uint8_t fatCount;
+ /**
+ * For FAT12 and FAT16 volumes, this field contains the count of
+ * 32-byte directory entries in the root directory. For FAT32 volumes,
+ * this field must be set to 0. For FAT12 and FAT16 volumes, this
+ * value should always specify a count that when multiplied by 32
+ * results in a multiple of bytesPerSector. FAT16 volumes should
+ * use the value 512.
+ */
+ uint16_t rootDirEntryCount;
+ /**
+ * This field is the old 16-bit total count of sectors on the volume.
+ * This count includes the count of all sectors in all four regions
+ * of the volume. This field can be 0; if it is 0, then totalSectors32
+ * must be non-zero. For FAT32 volumes, this field must be 0. For
+ * FAT12 and FAT16 volumes, this field contains the sector count, and
+ * totalSectors32 is 0 if the total sector count fits
+ * (is less than 0x10000).
+ */
+ uint16_t totalSectors16;
+ /**
+ * This dates back to the old MS-DOS 1.x media determination and is
+ * no longer usually used for anything. 0xF8 is the standard value
+ * for fixed (non-removable) media. For removable media, 0xF0 is
+ * frequently used. Legal values are 0xF0 or 0xF8-0xFF.
+ */
+ uint8_t mediaType;
+ /**
+ * Count of sectors occupied by one FAT on FAT12/FAT16 volumes.
+ * On FAT32 volumes this field must be 0, and sectorsPerFat32
+ * contains the FAT size count.
+ */
+ uint16_t sectorsPerFat16;
+ /** Sectors per track for interrupt 0x13. Not used otherwise. */
+ uint16_t sectorsPerTrtack;
+ /** Number of heads for interrupt 0x13. Not used otherwise. */
+ uint16_t headCount;
+ /**
+ * Count of hidden sectors preceding the partition that contains this
+ * FAT volume. This field is generally only relevant for media
+ * visible on interrupt 0x13.
+ */
+ uint32_t hidddenSectors;
+ /**
+ * This field is the new 32-bit total count of sectors on the volume.
+ * This count includes the count of all sectors in all four regions
+ * of the volume. This field can be 0; if it is 0, then
+ * totalSectors16 must be non-zero.
+ */
+ uint32_t totalSectors32;
+ /**
+ * Count of sectors occupied by one FAT on FAT32 volumes.
+ */
+ uint32_t sectorsPerFat32;
+ /**
+ * This field is only defined for FAT32 media and does not exist on
+ * FAT12 and FAT16 media.
+ * Bits 0-3 -- Zero-based number of active FAT.
+ * Only valid if mirroring is disabled.
+ * Bits 4-6 -- Reserved.
+ * Bit 7 -- 0 means the FAT is mirrored at runtime into all FATs.
+ * -- 1 means only one FAT is active; it is the one referenced in bits 0-3.
+ * Bits 8-15 -- Reserved.
+ */
+ uint16_t fat32Flags;
+ /**
+ * FAT32 version. High byte is major revision number.
+ * Low byte is minor revision number. Only 0.0 define.
+ */
+ uint16_t fat32Version;
+ /**
+ * Cluster number of the first cluster of the root directory for FAT32.
+ * This usually 2 but not required to be 2.
+ */
+ uint32_t fat32RootCluster;
+ /**
+ * Sector number of FSINFO structure in the reserved area of the
+ * FAT32 volume. Usually 1.
+ */
+ uint16_t fat32FSInfo;
+ /**
+ * If non-zero, indicates the sector number in the reserved area
+ * of the volume of a copy of the boot record. Usually 6.
+ * No value other than 6 is recommended.
+ */
+ uint16_t fat32BackBootBlock;
+ /**
+ * Reserved for future expansion. Code that formats FAT32 volumes
+ * should always set all of the bytes of this field to 0.
+ */
+ uint8_t fat32Reserved[12];
+}__attribute__ ((packed));
+/** Type name for biosParmBlock */
+typedef struct biosParmBlock bpb_t;
+//------------------------------------------------------------------------------
+/**
+ * \struct fat32BootSector
+ *
+ * \brief Boot sector for a FAT16 or FAT32 volume.
+ *
+ */
+struct fat32BootSector {
+ /** X86 jmp to boot program */
+ uint8_t jmpToBootCode[3];
+ /** informational only - don't depend on it */
+ uint8_t oemName[8];
+ /** BIOS Parameter Block */
+ bpb_t bpb;
+ /** for int0x13 use value 0X80 for hard drive */
+ uint8_t driveNumber;
+ /** used by Windows NT - should be zero for FAT */
+ uint8_t reserved1;
+ /** 0X29 if next three fields are valid */
+ uint8_t bootSignature;
+ /** usually generated by combining date and time */
+ uint32_t volumeSerialNumber;
+ /** should match volume label in root dir */
+ uint8_t volumeLabel[11];
+ /** informational only - don't depend on it */
+ uint8_t fileSystemType[8];
+ /** X86 boot code */
+ uint8_t bootCode[420];
+ /** must be 0X55 */
+ uint8_t bootSectorSig0;
+ /** must be 0XAA */
+ uint8_t bootSectorSig1;
+}__attribute__ ((packed));
+//------------------------------------------------------------------------------
+// End Of Chain values for FAT entries
+/** FAT16 end of chain value used by Microsoft. */
+uint16_t const FAT16EOC = 0XFFFF;
+/** Minimum value for FAT16 EOC. Use to test for EOC. */
+uint16_t const FAT16EOC_MIN = 0XFFF8;
+/** FAT32 end of chain value used by Microsoft. */
+uint32_t const FAT32EOC = 0X0FFFFFFF;
+/** Minimum value for FAT32 EOC. Use to test for EOC. */
+uint32_t const FAT32EOC_MIN = 0X0FFFFFF8;
+/** Mask a for FAT32 entry. Entries are 28 bits. */
+uint32_t const FAT32MASK = 0X0FFFFFFF;
+
+/** Type name for fat32BootSector */
+typedef struct fat32BootSector fbs_t;
+//------------------------------------------------------------------------------
+/**
+ * \struct directoryEntry
+ * \brief FAT short directory entry
+ *
+ * Short means short 8.3 name, not the entry size.
+ *
+ * Date Format. A FAT directory entry date stamp is a 16-bit field that is
+ * basically a date relative to the MS-DOS epoch of 01/01/1980. Here is the
+ * format (bit 0 is the LSB of the 16-bit word, bit 15 is the MSB of the
+ * 16-bit word):
+ *
+ * Bits 9-15: Count of years from 1980, valid value range 0-127
+ * inclusive (1980-2107).
+ *
+ * Bits 5-8: Month of year, 1 = January, valid value range 1-12 inclusive.
+ *
+ * Bits 0-4: Day of month, valid value range 1-31 inclusive.
+ *
+ * Time Format. A FAT directory entry time stamp is a 16-bit field that has
+ * a granularity of 2 seconds. Here is the format (bit 0 is the LSB of the
+ * 16-bit word, bit 15 is the MSB of the 16-bit word).
+ *
+ * Bits 11-15: Hours, valid value range 0-23 inclusive.
+ *
+ * Bits 5-10: Minutes, valid value range 0-59 inclusive.
+ *
+ * Bits 0-4: 2-second count, valid value range 0-29 inclusive (0 - 58 seconds).
+ *
+ * The valid time range is from Midnight 00:00:00 to 23:59:58.
+ */
+struct directoryEntry {
+ /**
+ * Short 8.3 name.
+ * The first eight bytes contain the file name with blank fill.
+ * The last three bytes contain the file extension with blank fill.
+ */
+ uint8_t name[11];
+ /** Entry attributes.
+ *
+ * The upper two bits of the attribute byte are reserved and should
+ * always be set to 0 when a file is created and never modified or
+ * looked at after that. See defines that begin with DIR_ATT_.
+ */
+ uint8_t attributes;
+ /**
+ * Reserved for use by Windows NT. Set value to 0 when a file is
+ * created and never modify or look at it after that.
+ */
+ uint8_t reservedNT;
+ /**
+ * The granularity of the seconds part of creationTime is 2 seconds
+ * so this field is a count of tenths of a second and its valid
+ * value range is 0-199 inclusive. (WHG note - seems to be hundredths)
+ */
+ uint8_t creationTimeTenths;
+ /** Time file was created. */
+ uint16_t creationTime;
+ /** Date file was created. */
+ uint16_t creationDate;
+ /**
+ * Last access date. Note that there is no last access time, only
+ * a date. This is the date of last read or write. In the case of
+ * a write, this should be set to the same date as lastWriteDate.
+ */
+ uint16_t lastAccessDate;
+ /**
+ * High word of this entry's first cluster number (always 0 for a
+ * FAT12 or FAT16 volume).
+ */
+ uint16_t firstClusterHigh;
+ /** Time of last write. File creation is considered a write. */
+ uint16_t lastWriteTime;
+ /** Date of last write. File creation is considered a write. */
+ uint16_t lastWriteDate;
+ /** Low word of this entry's first cluster number. */
+ uint16_t firstClusterLow;
+ /** 32-bit unsigned holding this file's size in bytes. */
+ uint32_t fileSize;
+}__attribute__ ((packed));
+//------------------------------------------------------------------------------
+// Definitions for directory entries
+//
+/** Type name for directoryEntry */
+typedef struct directoryEntry dir_t;
+/** escape for name[0] = 0XE5 */
+uint8_t const DIR_NAME_0XE5 = 0X05;
+/** name[0] value for entry that is free after being "deleted" */
+uint8_t const DIR_NAME_DELETED = 0XE5;
+/** name[0] value for entry that is free and no allocated entries follow */
+uint8_t const DIR_NAME_FREE = 0X00;
+/** file is read-only */
+uint8_t const DIR_ATT_READ_ONLY = 0X01;
+/** File should hidden in directory listings */
+uint8_t const DIR_ATT_HIDDEN = 0X02;
+/** Entry is for a system file */
+uint8_t const DIR_ATT_SYSTEM = 0X04;
+/** Directory entry contains the volume label */
+uint8_t const DIR_ATT_VOLUME_ID = 0X08;
+/** Entry is for a directory */
+uint8_t const DIR_ATT_DIRECTORY = 0X10;
+/** Old DOS archive bit for backup support */
+uint8_t const DIR_ATT_ARCHIVE = 0X20;
+/** Test value for long name entry. Test is
+ (d->attributes & DIR_ATT_LONG_NAME_MASK) == DIR_ATT_LONG_NAME. */
+uint8_t const DIR_ATT_LONG_NAME = 0X0F;
+/** Test mask for long name entry */
+uint8_t const DIR_ATT_LONG_NAME_MASK = 0X3F;
+/** defined attribute bits */
+uint8_t const DIR_ATT_DEFINED_BITS = 0X3F;
+/** Directory entry is part of a long name */
+static inline uint8_t DIR_IS_LONG_NAME(const dir_t* dir) {
+ return (dir->attributes & DIR_ATT_LONG_NAME_MASK) == DIR_ATT_LONG_NAME;
+}
+/** Mask for file/subdirectory tests */
+uint8_t const DIR_ATT_FILE_TYPE_MASK = (DIR_ATT_VOLUME_ID | DIR_ATT_DIRECTORY);
+/** Directory entry is for a file */
+static inline uint8_t DIR_IS_FILE(const dir_t* dir) {
+ return (dir->attributes & DIR_ATT_FILE_TYPE_MASK) == 0;
+}
+/** Directory entry is for a subdirectory */
+static inline uint8_t DIR_IS_SUBDIR(const dir_t* dir) {
+ return (dir->attributes & DIR_ATT_FILE_TYPE_MASK) == DIR_ATT_DIRECTORY;
+}
+/** Directory entry is for a file or subdirectory */
+static inline uint8_t DIR_IS_FILE_OR_SUBDIR(const dir_t* dir) {
+ return (dir->attributes & DIR_ATT_VOLUME_ID) == 0;
+}
+#endif // FatStructs_h
diff --git a/Libmaple/libmaple/libraries/mapleSDfat/Sd2Card.cpp b/Libmaple/libmaple/libraries/mapleSDfat/Sd2Card.cpp
index bf59af77..f7729aeb 100644
--- a/Libmaple/libmaple/libraries/mapleSDfat/Sd2Card.cpp
+++ b/Libmaple/libmaple/libraries/mapleSDfat/Sd2Card.cpp
@@ -1,715 +1,715 @@
-/* Arduino Sd2Card Library
- * Copyright (C) 2009 by William Greiman
- *
- * This file is part of the Arduino Sd2Card Library
- *
- * This Library is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This Library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with the Arduino Sd2Card Library. If not, see
- * .
- */
-#include
-#include
-#include "Sd2Card.h"
-#include "HardwareSPI.h"
-#include "spi.h"
-
-//pointer to spi object
-HardwareSPI *SPIn;
-
-//------------------------------------------------------------------------------
-// functions for hardware SPI
-/** Send a byte to the card */
-static void spiSend(uint8_t b)
-{
- SPIn->send(b);
- //while(SPIn->busy())
- //{
- //}
-}
-
-#if 0
-static void spiSend(const uint8_t *data, int len)
-{
- SPIn->send(data, len);
-}
-#endif
-
-/** Receive a byte from the card */
-static uint8_t spiRec(void)
-{
- return SPIn->send(0XFF);
-// return SPIn->read();
-}
-
-static void spiRec(uint8_t *data, int len)
-{
- SPIn->readMaster(data, len);
-}
-
-//------------------------------------------------------------------------------
-// send command and return error code. Return zero for OK
-uint8_t Sd2Card::cardCommand(uint8_t cmd, uint32_t arg) {
- // end read if in partialBlockRead mode
- readEnd();
-
- // select card
- chipSelectLow();
-
- // wait up to 300 ms if busy
- waitNotBusy(300);
-
- // send command
- spiSend(cmd | 0x40);
-
- // send argument
- for (int8_t s = 24; s >= 0; s -= 8)
- spiSend(arg >> s);
-
- // send CRC
- uint8_t crc = 0XFF;
- if (cmd == CMD0) crc = 0X95; // correct crc for CMD0 with arg 0
- if (cmd == CMD8) crc = 0X87; // correct crc for CMD8 with arg 0X1AA
- spiSend(crc);
-
- // wait for response
- for (uint8_t i = 0; ((status_ = spiRec()) & 0X80) && i != 0XFF; i++);
- return status_;
-}
-//------------------------------------------------------------------------------
-/**
- * Determine the size of an SD flash memory card.
- *
- * \return The number of 512 byte data blocks in the card
- * or zero if an error occurs.
- */
-uint32_t Sd2Card::cardSize(void) {
- csd_t csd;
- if (!readCSD(&csd)) return 0;
- if (csd.v1.csd_ver == 0) {
- uint8_t read_bl_len = csd.v1.read_bl_len;
- uint16_t c_size = (csd.v1.c_size_high << 10)
- | (csd.v1.c_size_mid << 2) | csd.v1.c_size_low;
- uint8_t c_size_mult = (csd.v1.c_size_mult_high << 1)
- | csd.v1.c_size_mult_low;
- return (uint32_t)(c_size + 1) << (c_size_mult + read_bl_len - 7);
- } else if (csd.v2.csd_ver == 1) {
- uint32_t c_size = ((uint32_t)csd.v2.c_size_high << 16)
- | (csd.v2.c_size_mid << 8) | csd.v2.c_size_low;
- return (c_size + 1) << 10;
- } else {
- error(SD_CARD_ERROR_BAD_CSD);
- return 0;
- }
-}
-//------------------------------------------------------------------------------
-void Sd2Card::chipSelectHigh(void)
-{
- digitalWrite(74, HIGH);
-}
-
-//------------------------------------------------------------------------------
-void Sd2Card::chipSelectLow(void)
-{
- digitalWrite(74, LOW);
-}
-
-//------------------------------------------------------------------------------
-/** Erase a range of blocks.
- *
- * \param[in] firstBlock The address of the first block in the range.
- * \param[in] lastBlock The address of the last block in the range.
- *
- * \note This function requests the SD card to do a flash erase for a
- * range of blocks. The data on the card after an erase operation is
- * either 0 or 1, depends on the card vendor. The card must support
- * single block erase.
- *
- * \return The value one, true, is returned for success and
- * the value zero, false, is returned for failure.
- */
-uint8_t Sd2Card::erase(uint32_t firstBlock, uint32_t lastBlock)
-{
- if (!eraseSingleBlockEnable())
- {
- error(SD_CARD_ERROR_ERASE_SINGLE_BLOCK);
- SerialDebug.println("Error: Erase Single Block");
- goto fail;
- }
- if (type_ != SD_CARD_TYPE_SDHC)
- {
- firstBlock <<= 9;
- lastBlock <<= 9;
- }
- if (cardCommand(CMD32, firstBlock)
- || cardCommand(CMD33, lastBlock)
- || cardCommand(CMD38, 0))
- {
- error(SD_CARD_ERROR_ERASE);
- SerialDebug.println("Error: Erase");
- goto fail;
- }
- if (!waitNotBusy(SD_ERASE_TIMEOUT))
- {
- error(SD_CARD_ERROR_ERASE_TIMEOUT);
- SerialDebug.println("Error: Erase timeout");
- goto fail;
- }
- chipSelectHigh();
- return true;
-
- fail:
- chipSelectHigh();
- SerialDebug.println("Error: Sd2Card::Erase()");
- return false;
-}
-//------------------------------------------------------------------------------
-/** Determine if card supports single block erase.
- *
- * \return The value one, true, is returned if single block erase is supported.
- * The value zero, false, is returned if single block erase is not supported.
- */
-uint8_t Sd2Card::eraseSingleBlockEnable(void)
-{
- csd_t csd;
- return readCSD(&csd) ? csd.v1.erase_blk_en : 0;
-}
-//------------------------------------------------------------------------------
-/**
- * Initialize an SD flash memory card.
- *
- * \param[in] sckRateID SPI clock rate selector. See setSckRate().
- * \param[in] chipSelectPin SD chip select pin number.
- *
- * \return The value one, true, is returned for success and
- * the value zero, false, is returned for failure. The reason for failure
- * can be determined by calling errorCode() and errorData().
- */
-uint8_t Sd2Card::init(HardwareSPI *s)
-{
- errorCode_ = inBlock_ = partialBlockRead_ = type_ = 0;
- // 16-bit init start time allows over a minute
-
- uint16_t t0 = (uint16_t)millis();
- uint32_t arg;
-
- pinMode(74,OUTPUT);
-
- SPIn = s;
- // set pin modes
-/* pinMode(chipSelectPin_, OUTPUT);
- chipSelectHigh();
- pinMode(SPI_MISO_PIN, INPUT);
- pinMode(SPI_MOSI_PIN, OUTPUT);
- pinMode(SPI_SCK_PIN, OUTPUT);
-*/
-
- // SS must be in output mode even it is not chip select
-// pinMode(SS_PIN, OUTPUT);
- // Enable SPI, Master, clock rate f_osc/128
-// SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0);
- // clear double speed
-// SPSR &= ~(1 << SPI2X);
-
- // must supply min of 74 clock cycles with CS high.
-
- chipSelectHigh();
- for (uint8_t i = 0; i < 10; i++) spiSend(0XFF);
- chipSelectLow();
-
- // command to go idle in SPI mode
- while ((status_ = cardCommand(CMD0, 0)) != R1_IDLE_STATE)
- {
- if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT)
- {
- SerialDebug.println("Error: CMD0");
- error(SD_CARD_ERROR_CMD0);
- goto fail;
- }
- }
- // check SD version
- if ((cardCommand(CMD8, 0x1AA) & R1_ILLEGAL_COMMAND))
- {
- type(SD_CARD_TYPE_SD1);
- }
- else
- {
- // only need last byte of r7 response
- for (uint8_t i = 0; i < 4; i++)
- status_ = spiRec();
- if (status_ != 0XAA)
- {
- error(SD_CARD_ERROR_CMD8);
- SerialDebug.println("Error: CMD8");
- goto fail;
- }
- type(SD_CARD_TYPE_SD2);
- }
- // initialize card and send host supports SDHC if SD2
- arg = (type() == SD_CARD_TYPE_SD2) ? 0X40000000 : 0;
-
- while ((status_ = cardAcmd(ACMD41, arg)) != R1_READY_STATE)
- {
- // check for timeout
- if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT)
- {
- SerialDebug.println("Error: ACMD41");
- error(SD_CARD_ERROR_ACMD41);
- goto fail;
- }
- }
- // if SD2 read OCR register to check for SDHC card
- if (type() == SD_CARD_TYPE_SD2)
- {
- if (cardCommand(CMD58, 0))
- {
- SerialDebug.println("Error: CMD58");
- error(SD_CARD_ERROR_CMD58);
- goto fail;
- }
- if ((spiRec() & 0XC0) == 0XC0)
- type(SD_CARD_TYPE_SDHC);
- // discard rest of ocr - contains allowed voltage range
- for (uint8_t i = 0; i < 3; i++)
- spiRec();
- }
- chipSelectHigh();
-
-// return setSckRate(sckRateID);
- return true;
-
- fail:
- chipSelectHigh();
- SerialDebug.println("Error: Sd2Card::init()");
- return false;
-}
-//------------------------------------------------------------------------------
-/**
- * Enable or disable partial block reads.
- *
- * Enabling partial block reads improves performance by allowing a block
- * to be read over the SPI bus as several sub-blocks. Errors may occur
- * if the time between reads is too long since the SD card may timeout.
- * The SPI SS line will be held low until the entire block is read or
- * readEnd() is called.
- *
- * Use this for applications like the Adafruit Wave Shield.
- *
- * \param[in] value The value TRUE (non-zero) or FALSE (zero).)
- */
-void Sd2Card::partialBlockRead(uint8_t value)
-{
- readEnd();
- partialBlockRead_ = value;
-}
-//------------------------------------------------------------------------------
-/**
- * Read a 512 byte block from an SD card device.
- *
- * \param[in] block Logical block to be read.
- * \param[out] dst Pointer to the location that will receive the data.
-
- * \return The value one, true, is returned for success and
- * the value zero, false, is returned for failure.
- */
-uint8_t Sd2Card::readBlock(uint32_t block, uint8_t* dst)
-{
- return readData(block, 0, 512, dst);
-}
-//------------------------------------------------------------------------------
-/**
- * Read part of a 512 byte block from an SD card.
- *
- * \param[in] block Logical block to be read.
- * \param[in] offset Number of bytes to skip at start of block
- * \param[out] dst Pointer to the location that will receive the data.
- * \param[in] count Number of bytes to read
- * \return The value one, true, is returned for success and
- * the value zero, false, is returned for failure.
- */
-uint8_t Sd2Card::readData(uint32_t block,
- uint16_t offset, uint16_t count, uint8_t* dst)
-{
- if (count == 0) return true;
- if ((count + offset) > 512)
- {
- goto fail;
- }
- if (!inBlock_ || block != block_ || offset < offset_)
- {
- block_ = block;
- // use address if not SDHC card
- if (type()!= SD_CARD_TYPE_SDHC)
- block <<= 9;
- if (cardCommand(CMD17, block))
- {
- error(SD_CARD_ERROR_CMD17);
- SerialDebug.println("Error: CMD17");
- goto fail;
- }
- if (!waitStartBlock())
- {
- goto fail;
- }
- offset_ = 0;
- inBlock_ = 1;
- }
-
-#ifdef OPTIMIZE_HARDWARE_SPI
-/* // start first spi transfer
- SPDR = 0XFF;
-
- // skip data before offset
- for (;offset_ < offset; offset_++) {
- while (!(SPSR & (1 << SPIF)));
- SPDR = 0XFF;
- }
- // transfer data
- uint16_t n;
- n = count - 1;
- for (uint16_t i = 0; i < n; i++) {
- while (!(SPSR & (1 << SPIF)));
- dst[i] = SPDR;
- SPDR = 0XFF;
- }
- // wait for last byte
- while (!(SPSR & (1 << SPIF)));
- dst[n] = SPDR;
-*/
-#else // OPTIMIZE_HARDWARE_SPI
-
- // skip data before offset
- for (;offset_ < offset; offset_++)
- {
- spiRec();
- }
- // transfer data
- //for (uint16_t i = 0; i < count; i++)
- //{
- // dst[i] = spiRec();
- //}
- spiRec(dst, count);
-
-#endif // OPTIMIZE_HARDWARE_SPI
-
- offset_ += count;
- if (!partialBlockRead_ || offset_ >= 512)
- {
- // read rest of data, checksum and set chip select high
- readEnd();
- }
- return true;
-
- fail:
- chipSelectHigh();
- SerialDebug.println("Error: Sd2Card::readData()");
- return false;
-}
-//------------------------------------------------------------------------------
-/** Skip remaining data in a block when in partial block read mode. */
-void Sd2Card::readEnd(void)
-{
- if (inBlock_)
- {
- // skip data and crc
-#ifdef OPTIMIZE_HARDWARE_SPI
- // optimize skip for hardware
-/* SPDR = 0XFF;
- while (offset_++ < 513) {
- while (!(SPSR & (1 << SPIF)));
- SPDR = 0XFF;
- }
- // wait for last crc byte
- while (!(SPSR & (1 << SPIF)));
-*/
-#else // OPTIMIZE_HARDWARE_SPI
- while (offset_++ < 514)
- spiRec();
-#endif // OPTIMIZE_HARDWARE_SPI
- chipSelectHigh();
- inBlock_ = 0;
- }
-}
-//------------------------------------------------------------------------------
-/** read CID or CSR register */
-uint8_t Sd2Card::readRegister(uint8_t cmd, void* buf)
-{
- uint8_t* dst = reinterpret_cast(buf);
- if (cardCommand(cmd, 0))
- {
- error(SD_CARD_ERROR_READ_REG);
- SerialDebug.println("Error: Read reg");
- goto fail;
- }
- if (!waitStartBlock())
- goto fail;
- // transfer data
- for (uint16_t i = 0; i < 16; i++)
- dst[i] = spiRec();
- spiRec(); // get first crc byte
- spiRec(); // get second crc byte
- chipSelectHigh();
- return true;
-
- fail:
- SerialDebug.println("Error: Sd2Card::readRegister()");
- chipSelectHigh();
- return false;
-}
-//------------------------------------------------------------------------------
-/**
- * Set the SPI clock rate.
- *
- * \param[in] sckRateID A value in the range [0, 6].
- *
- * The SPI clock will be set to F_CPU/pow(2, 1 + sckRateID). The maximum
- * SPI rate is F_CPU/2 for \a sckRateID = 0 and the minimum rate is F_CPU/128
- * for \a scsRateID = 6.
- *
- * \return The value one, true, is returned for success and the value zero,
- * false, is returned for an invalid value of \a sckRateID.
- */
-uint8_t Sd2Card::setSckRate(uint8_t sckRateID) {
-/* if (sckRateID > 6) {
- error(SD_CARD_ERROR_SCK_RATE);
- return false;
- }
- // see avr processor datasheet for SPI register bit definitions
- if ((sckRateID & 1) || sckRateID == 6) {
- SPSR &= ~(1 << SPI2X);
- } else {
- SPSR |= (1 << SPI2X);
- }
- SPCR &= ~((1 < SD_READ_TIMEOUT)
- {
- error(SD_CARD_ERROR_READ_TIMEOUT);
- SerialDebug.println("Error: Read timeout");
- goto fail;
- }
- }
- if (status_ != DATA_START_BLOCK)
- {
- error(SD_CARD_ERROR_READ);
- SerialDebug.println("Error: Read");
- goto fail;
- }
- return true;
-
- fail:
- chipSelectHigh();
- SerialDebug.println("Error: Sd2Card::waitStartBlock()");
- return false;
-}
-//------------------------------------------------------------------------------
-/**
- * Writes a 512 byte block to an SD card.
- *
- * \param[in] blockNumber Logical block to be written.
- * \param[in] src Pointer to the location of the data to be written.
- * \return The value one, true, is returned for success and
- * the value zero, false, is returned for failure.
- */
-uint8_t Sd2Card::writeBlock(uint32_t blockNumber, const uint8_t* src)
-{
-#if SD_PROTECT_BLOCK_ZERO
- // don't allow write to first block
- if (blockNumber == 0)
- {
- error(SD_CARD_ERROR_WRITE_BLOCK_ZERO);
- SerialDebug.println("Error: Write block zero");
- goto fail;
- }
-#endif // SD_PROTECT_BLOCK_ZERO
-
- // use address if not SDHC card
- if (type() != SD_CARD_TYPE_SDHC)
- blockNumber <<= 9;
- if (cardCommand(CMD24, blockNumber))
- {
- SerialDebug.println("Error: CMD24");
- error(SD_CARD_ERROR_CMD24);
- goto fail;
- }
- if (!writeData(DATA_START_BLOCK, src))
- goto fail;
-
- // wait for flash programming to complete
- if (!waitNotBusy(SD_WRITE_TIMEOUT))
- {
- error(SD_CARD_ERROR_WRITE_TIMEOUT);
- SerialDebug.println("Error: Write timeout");
- goto fail;
- }
- // response is r2 so get and check two bytes for nonzero
- if (cardCommand(CMD13, 0) || spiRec())
- {
- error(SD_CARD_ERROR_WRITE_PROGRAMMING);
- SerialDebug.println("Error: Write programming");
- goto fail;
- }
- chipSelectHigh();
- return true;
-
- fail:
- chipSelectHigh();
- SerialDebug.println("Error: Sd2Card::writeBlock");
- return false;
-}
-//------------------------------------------------------------------------------
-/** Write one data block in a multiple block write sequence */
-uint8_t Sd2Card::writeData(const uint8_t* src)
-{
- // wait for previous write to finish
- if (!waitNotBusy(SD_WRITE_TIMEOUT))
- {
- error(SD_CARD_ERROR_WRITE_MULTIPLE);
- SerialDebug.println("Error: writeData");
- chipSelectHigh();
- return false;
- }
- return writeData(WRITE_MULTIPLE_TOKEN, src);
-}
-//------------------------------------------------------------------------------
-// send one block of data for write block or write multiple blocks
-uint8_t Sd2Card::writeData(uint8_t token, const uint8_t* src) {
-#ifdef OPTIMIZE_HARDWARE_SPI
-/*
- // send data - optimized loop
- SPDR = token;
-
- // send two byte per iteration
- for (uint16_t i = 0; i < 512; i += 2) {
- while (!(SPSR & (1 << SPIF)));
- SPDR = src[i];
- while (!(SPSR & (1 << SPIF)));
- SPDR = src[i+1];
- }
-
- // wait for last data byte
- while (!(SPSR & (1 << SPIF)));
-*/
-#else // OPTIMIZE_HARDWARE_SPI
- spiSend(token);
- for (uint16_t i = 0; i < 512; i++)
- {
- spiSend(src[i]);
- }
- //spiSend(src, 512);
-#endif // OPTIMIZE_HARDWARE_SPI
- spiSend(0xff); // dummy crc
- spiSend(0xff); // dummy crc
-
- status_ = spiRec();
- if ((status_ & DATA_RES_MASK) != DATA_RES_ACCEPTED)
- {
- error(SD_CARD_ERROR_WRITE);
- chipSelectHigh();
- SerialDebug.println("Error: Write");
- SerialDebug.println("Error: Sd2Card::writeData()");
- return false;
- }
- return true;
-}
-//------------------------------------------------------------------------------
-/** Start a write multiple blocks sequence.
- *
- * \param[in] blockNumber Address of first block in sequence.
- * \param[in] eraseCount The number of blocks to be pre-erased.
- *
- * \note This function is used with writeData() and writeStop()
- * for optimized multiple block writes.
- *
- * \return The value one, true, is returned for success and
- * the value zero, false, is returned for failure.
- */
-uint8_t Sd2Card::writeStart(uint32_t blockNumber, uint32_t eraseCount)
-{
-#if SD_PROTECT_BLOCK_ZERO
- // don't allow write to first block
- if (blockNumber == 0)
- {
- error(SD_CARD_ERROR_WRITE_BLOCK_ZERO);
- SerialDebug.println("Error: Write block zero");
- goto fail;
- }
-#endif // SD_PROTECT_BLOCK_ZERO
- // send pre-erase count
- if (cardAcmd(ACMD23, eraseCount))
- {
- SerialDebug.println("Error: ACMD23");
- error(SD_CARD_ERROR_ACMD23);
- goto fail;
- }
- // use address if not SDHC card
- if (type() != SD_CARD_TYPE_SDHC)
- blockNumber <<= 9;
- if (cardCommand(CMD25, blockNumber))
- {
- error(SD_CARD_ERROR_CMD25);
- SerialDebug.println("Error: CMD25");
- goto fail;
- }
- return true;
-
- fail:
- chipSelectHigh();
- SerialDebug.println("Error: Sd2Card::writeStart()");
- return false;
-}
-//------------------------------------------------------------------------------
-/** End a write multiple blocks sequence.
- *
-* \return The value one, true, is returned for success and
- * the value zero, false, is returned for failure.
- */
-uint8_t Sd2Card::writeStop(void)
-{
- if (!waitNotBusy(SD_WRITE_TIMEOUT))
- goto fail;
- spiSend(STOP_TRAN_TOKEN);
- if (!waitNotBusy(SD_WRITE_TIMEOUT))
- goto fail;
- chipSelectHigh();
- return true;
-
- fail:
- error(SD_CARD_ERROR_STOP_TRAN);
- chipSelectHigh();
- SerialDebug.println("Error: Sd2Card::writeStop()");
- return false;
-}
+/* Arduino Sd2Card Library
+ * Copyright (C) 2009 by William Greiman
+ *
+ * This file is part of the Arduino Sd2Card Library
+ *
+ * This Library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Arduino Sd2Card Library. If not, see
+ * .
+ */
+#include
+#include
+#include "Sd2Card.h"
+#include "HardwareSPI.h"
+#include "spi.h"
+
+//pointer to spi object
+HardwareSPI *SPIn;
+
+//------------------------------------------------------------------------------
+// functions for hardware SPI
+/** Send a byte to the card */
+static void spiSend(uint8_t b)
+{
+ SPIn->send(b);
+ //while(SPIn->busy())
+ //{
+ //}
+}
+
+#if 0
+static void spiSend(const uint8_t *data, int len)
+{
+ SPIn->send(data, len);
+}
+#endif
+
+/** Receive a byte from the card */
+static uint8_t spiRec(void)
+{
+ return SPIn->send(0XFF);
+// return SPIn->read();
+}
+
+static void spiRec(uint8_t *data, int len)
+{
+ SPIn->readMaster(data, len);
+}
+
+//------------------------------------------------------------------------------
+// send command and return error code. Return zero for OK
+uint8_t Sd2Card::cardCommand(uint8_t cmd, uint32_t arg) {
+ // end read if in partialBlockRead mode
+ readEnd();
+
+ // select card
+ chipSelectLow();
+
+ // wait up to 300 ms if busy
+ waitNotBusy(300);
+
+ // send command
+ spiSend(cmd | 0x40);
+
+ // send argument
+ for (int8_t s = 24; s >= 0; s -= 8)
+ spiSend(arg >> s);
+
+ // send CRC
+ uint8_t crc = 0XFF;
+ if (cmd == CMD0) crc = 0X95; // correct crc for CMD0 with arg 0
+ if (cmd == CMD8) crc = 0X87; // correct crc for CMD8 with arg 0X1AA
+ spiSend(crc);
+
+ // wait for response
+ for (uint8_t i = 0; ((status_ = spiRec()) & 0X80) && i != 0XFF; i++);
+ return status_;
+}
+//------------------------------------------------------------------------------
+/**
+ * Determine the size of an SD flash memory card.
+ *
+ * \return The number of 512 byte data blocks in the card
+ * or zero if an error occurs.
+ */
+uint32_t Sd2Card::cardSize(void) {
+ csd_t csd;
+ if (!readCSD(&csd)) return 0;
+ if (csd.v1.csd_ver == 0) {
+ uint8_t read_bl_len = csd.v1.read_bl_len;
+ uint16_t c_size = (csd.v1.c_size_high << 10)
+ | (csd.v1.c_size_mid << 2) | csd.v1.c_size_low;
+ uint8_t c_size_mult = (csd.v1.c_size_mult_high << 1)
+ | csd.v1.c_size_mult_low;
+ return (uint32_t)(c_size + 1) << (c_size_mult + read_bl_len - 7);
+ } else if (csd.v2.csd_ver == 1) {
+ uint32_t c_size = ((uint32_t)csd.v2.c_size_high << 16)
+ | (csd.v2.c_size_mid << 8) | csd.v2.c_size_low;
+ return (c_size + 1) << 10;
+ } else {
+ error(SD_CARD_ERROR_BAD_CSD);
+ return 0;
+ }
+}
+//------------------------------------------------------------------------------
+void Sd2Card::chipSelectHigh(void)
+{
+ digitalWrite(74, HIGH);
+}
+
+//------------------------------------------------------------------------------
+void Sd2Card::chipSelectLow(void)
+{
+ digitalWrite(74, LOW);
+}
+
+//------------------------------------------------------------------------------
+/** Erase a range of blocks.
+ *
+ * \param[in] firstBlock The address of the first block in the range.
+ * \param[in] lastBlock The address of the last block in the range.
+ *
+ * \note This function requests the SD card to do a flash erase for a
+ * range of blocks. The data on the card after an erase operation is
+ * either 0 or 1, depends on the card vendor. The card must support
+ * single block erase.
+ *
+ * \return The value one, true, is returned for success and
+ * the value zero, false, is returned for failure.
+ */
+uint8_t Sd2Card::erase(uint32_t firstBlock, uint32_t lastBlock)
+{
+ if (!eraseSingleBlockEnable())
+ {
+ error(SD_CARD_ERROR_ERASE_SINGLE_BLOCK);
+ SerialDebug.println("Error: Erase Single Block");
+ goto fail;
+ }
+ if (type_ != SD_CARD_TYPE_SDHC)
+ {
+ firstBlock <<= 9;
+ lastBlock <<= 9;
+ }
+ if (cardCommand(CMD32, firstBlock)
+ || cardCommand(CMD33, lastBlock)
+ || cardCommand(CMD38, 0))
+ {
+ error(SD_CARD_ERROR_ERASE);
+ SerialDebug.println("Error: Erase");
+ goto fail;
+ }
+ if (!waitNotBusy(SD_ERASE_TIMEOUT))
+ {
+ error(SD_CARD_ERROR_ERASE_TIMEOUT);
+ SerialDebug.println("Error: Erase timeout");
+ goto fail;
+ }
+ chipSelectHigh();
+ return true;
+
+ fail:
+ chipSelectHigh();
+ SerialDebug.println("Error: Sd2Card::Erase()");
+ return false;
+}
+//------------------------------------------------------------------------------
+/** Determine if card supports single block erase.
+ *
+ * \return The value one, true, is returned if single block erase is supported.
+ * The value zero, false, is returned if single block erase is not supported.
+ */
+uint8_t Sd2Card::eraseSingleBlockEnable(void)
+{
+ csd_t csd;
+ return readCSD(&csd) ? csd.v1.erase_blk_en : 0;
+}
+//------------------------------------------------------------------------------
+/**
+ * Initialize an SD flash memory card.
+ *
+ * \param[in] sckRateID SPI clock rate selector. See setSckRate().
+ * \param[in] chipSelectPin SD chip select pin number.
+ *
+ * \return The value one, true, is returned for success and
+ * the value zero, false, is returned for failure. The reason for failure
+ * can be determined by calling errorCode() and errorData().
+ */
+uint8_t Sd2Card::init(HardwareSPI *s)
+{
+ errorCode_ = inBlock_ = partialBlockRead_ = type_ = 0;
+ // 16-bit init start time allows over a minute
+
+ uint16_t t0 = (uint16_t)millis();
+ uint32_t arg;
+
+ pinMode(74,OUTPUT);
+
+ SPIn = s;
+ // set pin modes
+/* pinMode(chipSelectPin_, OUTPUT);
+ chipSelectHigh();
+ pinMode(SPI_MISO_PIN, INPUT);
+ pinMode(SPI_MOSI_PIN, OUTPUT);
+ pinMode(SPI_SCK_PIN, OUTPUT);
+*/
+
+ // SS must be in output mode even it is not chip select
+// pinMode(SS_PIN, OUTPUT);
+ // Enable SPI, Master, clock rate f_osc/128
+// SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0);
+ // clear double speed
+// SPSR &= ~(1 << SPI2X);
+
+ // must supply min of 74 clock cycles with CS high.
+
+ chipSelectHigh();
+ for (uint8_t i = 0; i < 10; i++) spiSend(0XFF);
+ chipSelectLow();
+
+ // command to go idle in SPI mode
+ while ((status_ = cardCommand(CMD0, 0)) != R1_IDLE_STATE)
+ {
+ if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT)
+ {
+ SerialDebug.println("Error: CMD0");
+ error(SD_CARD_ERROR_CMD0);
+ goto fail;
+ }
+ }
+ // check SD version
+ if ((cardCommand(CMD8, 0x1AA) & R1_ILLEGAL_COMMAND))
+ {
+ type(SD_CARD_TYPE_SD1);
+ }
+ else
+ {
+ // only need last byte of r7 response
+ for (uint8_t i = 0; i < 4; i++)
+ status_ = spiRec();
+ if (status_ != 0XAA)
+ {
+ error(SD_CARD_ERROR_CMD8);
+ SerialDebug.println("Error: CMD8");
+ goto fail;
+ }
+ type(SD_CARD_TYPE_SD2);
+ }
+ // initialize card and send host supports SDHC if SD2
+ arg = (type() == SD_CARD_TYPE_SD2) ? 0X40000000 : 0;
+
+ while ((status_ = cardAcmd(ACMD41, arg)) != R1_READY_STATE)
+ {
+ // check for timeout
+ if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT)
+ {
+ SerialDebug.println("Error: ACMD41");
+ error(SD_CARD_ERROR_ACMD41);
+ goto fail;
+ }
+ }
+ // if SD2 read OCR register to check for SDHC card
+ if (type() == SD_CARD_TYPE_SD2)
+ {
+ if (cardCommand(CMD58, 0))
+ {
+ SerialDebug.println("Error: CMD58");
+ error(SD_CARD_ERROR_CMD58);
+ goto fail;
+ }
+ if ((spiRec() & 0XC0) == 0XC0)
+ type(SD_CARD_TYPE_SDHC);
+ // discard rest of ocr - contains allowed voltage range
+ for (uint8_t i = 0; i < 3; i++)
+ spiRec();
+ }
+ chipSelectHigh();
+
+// return setSckRate(sckRateID);
+ return true;
+
+ fail:
+ chipSelectHigh();
+ SerialDebug.println("Error: Sd2Card::init()");
+ return false;
+}
+//------------------------------------------------------------------------------
+/**
+ * Enable or disable partial block reads.
+ *
+ * Enabling partial block reads improves performance by allowing a block
+ * to be read over the SPI bus as several sub-blocks. Errors may occur
+ * if the time between reads is too long since the SD card may timeout.
+ * The SPI SS line will be held low until the entire block is read or
+ * readEnd() is called.
+ *
+ * Use this for applications like the Adafruit Wave Shield.
+ *
+ * \param[in] value The value TRUE (non-zero) or FALSE (zero).)
+ */
+void Sd2Card::partialBlockRead(uint8_t value)
+{
+ readEnd();
+ partialBlockRead_ = value;
+}
+//------------------------------------------------------------------------------
+/**
+ * Read a 512 byte block from an SD card device.
+ *
+ * \param[in] block Logical block to be read.
+ * \param[out] dst Pointer to the location that will receive the data.
+
+ * \return The value one, true, is returned for success and
+ * the value zero, false, is returned for failure.
+ */
+uint8_t Sd2Card::readBlock(uint32_t block, uint8_t* dst)
+{
+ return readData(block, 0, 512, dst);
+}
+//------------------------------------------------------------------------------
+/**
+ * Read part of a 512 byte block from an SD card.
+ *
+ * \param[in] block Logical block to be read.
+ * \param[in] offset Number of bytes to skip at start of block
+ * \param[out] dst Pointer to the location that will receive the data.
+ * \param[in] count Number of bytes to read
+ * \return The value one, true, is returned for success and
+ * the value zero, false, is returned for failure.
+ */
+uint8_t Sd2Card::readData(uint32_t block,
+ uint16_t offset, uint16_t count, uint8_t* dst)
+{
+ if (count == 0) return true;
+ if ((count + offset) > 512)
+ {
+ goto fail;
+ }
+ if (!inBlock_ || block != block_ || offset < offset_)
+ {
+ block_ = block;
+ // use address if not SDHC card
+ if (type()!= SD_CARD_TYPE_SDHC)
+ block <<= 9;
+ if (cardCommand(CMD17, block))
+ {
+ error(SD_CARD_ERROR_CMD17);
+ SerialDebug.println("Error: CMD17");
+ goto fail;
+ }
+ if (!waitStartBlock())
+ {
+ goto fail;
+ }
+ offset_ = 0;
+ inBlock_ = 1;
+ }
+
+#ifdef OPTIMIZE_HARDWARE_SPI
+/* // start first spi transfer
+ SPDR = 0XFF;
+
+ // skip data before offset
+ for (;offset_ < offset; offset_++) {
+ while (!(SPSR & (1 << SPIF)));
+ SPDR = 0XFF;
+ }
+ // transfer data
+ uint16_t n;
+ n = count - 1;
+ for (uint16_t i = 0; i < n; i++) {
+ while (!(SPSR & (1 << SPIF)));
+ dst[i] = SPDR;
+ SPDR = 0XFF;
+ }
+ // wait for last byte
+ while (!(SPSR & (1 << SPIF)));
+ dst[n] = SPDR;
+*/
+#else // OPTIMIZE_HARDWARE_SPI
+
+ // skip data before offset
+ for (;offset_ < offset; offset_++)
+ {
+ spiRec();
+ }
+ // transfer data
+ //for (uint16_t i = 0; i < count; i++)
+ //{
+ // dst[i] = spiRec();
+ //}
+ spiRec(dst, count);
+
+#endif // OPTIMIZE_HARDWARE_SPI
+
+ offset_ += count;
+ if (!partialBlockRead_ || offset_ >= 512)
+ {
+ // read rest of data, checksum and set chip select high
+ readEnd();
+ }
+ return true;
+
+ fail:
+ chipSelectHigh();
+ SerialDebug.println("Error: Sd2Card::readData()");
+ return false;
+}
+//------------------------------------------------------------------------------
+/** Skip remaining data in a block when in partial block read mode. */
+void Sd2Card::readEnd(void)
+{
+ if (inBlock_)
+ {
+ // skip data and crc
+#ifdef OPTIMIZE_HARDWARE_SPI
+ // optimize skip for hardware
+/* SPDR = 0XFF;
+ while (offset_++ < 513) {
+ while (!(SPSR & (1 << SPIF)));
+ SPDR = 0XFF;
+ }
+ // wait for last crc byte
+ while (!(SPSR & (1 << SPIF)));
+*/
+#else // OPTIMIZE_HARDWARE_SPI
+ while (offset_++ < 514)
+ spiRec();
+#endif // OPTIMIZE_HARDWARE_SPI
+ chipSelectHigh();
+ inBlock_ = 0;
+ }
+}
+//------------------------------------------------------------------------------
+/** read CID or CSR register */
+uint8_t Sd2Card::readRegister(uint8_t cmd, void* buf)
+{
+ uint8_t* dst = reinterpret_cast(buf);
+ if (cardCommand(cmd, 0))
+ {
+ error(SD_CARD_ERROR_READ_REG);
+ SerialDebug.println("Error: Read reg");
+ goto fail;
+ }
+ if (!waitStartBlock())
+ goto fail;
+ // transfer data
+ for (uint16_t i = 0; i < 16; i++)
+ dst[i] = spiRec();
+ spiRec(); // get first crc byte
+ spiRec(); // get second crc byte
+ chipSelectHigh();
+ return true;
+
+ fail:
+ SerialDebug.println("Error: Sd2Card::readRegister()");
+ chipSelectHigh();
+ return false;
+}
+//------------------------------------------------------------------------------
+/**
+ * Set the SPI clock rate.
+ *
+ * \param[in] sckRateID A value in the range [0, 6].
+ *
+ * The SPI clock will be set to F_CPU/pow(2, 1 + sckRateID). The maximum
+ * SPI rate is F_CPU/2 for \a sckRateID = 0 and the minimum rate is F_CPU/128
+ * for \a scsRateID = 6.
+ *
+ * \return The value one, true, is returned for success and the value zero,
+ * false, is returned for an invalid value of \a sckRateID.
+ */
+uint8_t Sd2Card::setSckRate(uint8_t sckRateID) {
+/* if (sckRateID > 6) {
+ error(SD_CARD_ERROR_SCK_RATE);
+ return false;
+ }
+ // see avr processor datasheet for SPI register bit definitions
+ if ((sckRateID & 1) || sckRateID == 6) {
+ SPSR &= ~(1 << SPI2X);
+ } else {
+ SPSR |= (1 << SPI2X);
+ }
+ SPCR &= ~((1 < SD_READ_TIMEOUT)
+ {
+ error(SD_CARD_ERROR_READ_TIMEOUT);
+ SerialDebug.println("Error: Read timeout");
+ goto fail;
+ }
+ }
+ if (status_ != DATA_START_BLOCK)
+ {
+ error(SD_CARD_ERROR_READ);
+ SerialDebug.println("Error: Read");
+ goto fail;
+ }
+ return true;
+
+ fail:
+ chipSelectHigh();
+ SerialDebug.println("Error: Sd2Card::waitStartBlock()");
+ return false;
+}
+//------------------------------------------------------------------------------
+/**
+ * Writes a 512 byte block to an SD card.
+ *
+ * \param[in] blockNumber Logical block to be written.
+ * \param[in] src Pointer to the location of the data to be written.
+ * \return The value one, true, is returned for success and
+ * the value zero, false, is returned for failure.
+ */
+uint8_t Sd2Card::writeBlock(uint32_t blockNumber, const uint8_t* src)
+{
+#if SD_PROTECT_BLOCK_ZERO
+ // don't allow write to first block
+ if (blockNumber == 0)
+ {
+ error(SD_CARD_ERROR_WRITE_BLOCK_ZERO);
+ SerialDebug.println("Error: Write block zero");
+ goto fail;
+ }
+#endif // SD_PROTECT_BLOCK_ZERO
+
+ // use address if not SDHC card
+ if (type() != SD_CARD_TYPE_SDHC)
+ blockNumber <<= 9;
+ if (cardCommand(CMD24, blockNumber))
+ {
+ SerialDebug.println("Error: CMD24");
+ error(SD_CARD_ERROR_CMD24);
+ goto fail;
+ }
+ if (!writeData(DATA_START_BLOCK, src))
+ goto fail;
+
+ // wait for flash programming to complete
+ if (!waitNotBusy(SD_WRITE_TIMEOUT))
+ {
+ error(SD_CARD_ERROR_WRITE_TIMEOUT);
+ SerialDebug.println("Error: Write timeout");
+ goto fail;
+ }
+ // response is r2 so get and check two bytes for nonzero
+ if (cardCommand(CMD13, 0) || spiRec())
+ {
+ error(SD_CARD_ERROR_WRITE_PROGRAMMING);
+ SerialDebug.println("Error: Write programming");
+ goto fail;
+ }
+ chipSelectHigh();
+ return true;
+
+ fail:
+ chipSelectHigh();
+ SerialDebug.println("Error: Sd2Card::writeBlock");
+ return false;
+}
+//------------------------------------------------------------------------------
+/** Write one data block in a multiple block write sequence */
+uint8_t Sd2Card::writeData(const uint8_t* src)
+{
+ // wait for previous write to finish
+ if (!waitNotBusy(SD_WRITE_TIMEOUT))
+ {
+ error(SD_CARD_ERROR_WRITE_MULTIPLE);
+ SerialDebug.println("Error: writeData");
+ chipSelectHigh();
+ return false;
+ }
+ return writeData(WRITE_MULTIPLE_TOKEN, src);
+}
+//------------------------------------------------------------------------------
+// send one block of data for write block or write multiple blocks
+uint8_t Sd2Card::writeData(uint8_t token, const uint8_t* src) {
+#ifdef OPTIMIZE_HARDWARE_SPI
+/*
+ // send data - optimized loop
+ SPDR = token;
+
+ // send two byte per iteration
+ for (uint16_t i = 0; i < 512; i += 2) {
+ while (!(SPSR & (1 << SPIF)));
+ SPDR = src[i];
+ while (!(SPSR & (1 << SPIF)));
+ SPDR = src[i+1];
+ }
+
+ // wait for last data byte
+ while (!(SPSR & (1 << SPIF)));
+*/
+#else // OPTIMIZE_HARDWARE_SPI
+ spiSend(token);
+ for (uint16_t i = 0; i < 512; i++)
+ {
+ spiSend(src[i]);
+ }
+ //spiSend(src, 512);
+#endif // OPTIMIZE_HARDWARE_SPI
+ spiSend(0xff); // dummy crc
+ spiSend(0xff); // dummy crc
+
+ status_ = spiRec();
+ if ((status_ & DATA_RES_MASK) != DATA_RES_ACCEPTED)
+ {
+ error(SD_CARD_ERROR_WRITE);
+ chipSelectHigh();
+ SerialDebug.println("Error: Write");
+ SerialDebug.println("Error: Sd2Card::writeData()");
+ return false;
+ }
+ return true;
+}
+//------------------------------------------------------------------------------
+/** Start a write multiple blocks sequence.
+ *
+ * \param[in] blockNumber Address of first block in sequence.
+ * \param[in] eraseCount The number of blocks to be pre-erased.
+ *
+ * \note This function is used with writeData() and writeStop()
+ * for optimized multiple block writes.
+ *
+ * \return The value one, true, is returned for success and
+ * the value zero, false, is returned for failure.
+ */
+uint8_t Sd2Card::writeStart(uint32_t blockNumber, uint32_t eraseCount)
+{
+#if SD_PROTECT_BLOCK_ZERO
+ // don't allow write to first block
+ if (blockNumber == 0)
+ {
+ error(SD_CARD_ERROR_WRITE_BLOCK_ZERO);
+ SerialDebug.println("Error: Write block zero");
+ goto fail;
+ }
+#endif // SD_PROTECT_BLOCK_ZERO
+ // send pre-erase count
+ if (cardAcmd(ACMD23, eraseCount))
+ {
+ SerialDebug.println("Error: ACMD23");
+ error(SD_CARD_ERROR_ACMD23);
+ goto fail;
+ }
+ // use address if not SDHC card
+ if (type() != SD_CARD_TYPE_SDHC)
+ blockNumber <<= 9;
+ if (cardCommand(CMD25, blockNumber))
+ {
+ error(SD_CARD_ERROR_CMD25);
+ SerialDebug.println("Error: CMD25");
+ goto fail;
+ }
+ return true;
+
+ fail:
+ chipSelectHigh();
+ SerialDebug.println("Error: Sd2Card::writeStart()");
+ return false;
+}
+//------------------------------------------------------------------------------
+/** End a write multiple blocks sequence.
+ *
+* \return The value one, true, is returned for success and
+ * the value zero, false, is returned for failure.
+ */
+uint8_t Sd2Card::writeStop(void)
+{
+ if (!waitNotBusy(SD_WRITE_TIMEOUT))
+ goto fail;
+ spiSend(STOP_TRAN_TOKEN);
+ if (!waitNotBusy(SD_WRITE_TIMEOUT))
+ goto fail;
+ chipSelectHigh();
+ return true;
+
+ fail:
+ error(SD_CARD_ERROR_STOP_TRAN);
+ chipSelectHigh();
+ SerialDebug.println("Error: Sd2Card::writeStop()");
+ return false;
+}
diff --git a/Libmaple/libmaple/libraries/mapleSDfat/Sd2Card.h b/Libmaple/libmaple/libraries/mapleSDfat/Sd2Card.h
index 40adb689..ba142959 100644
--- a/Libmaple/libmaple/libraries/mapleSDfat/Sd2Card.h
+++ b/Libmaple/libmaple/libraries/mapleSDfat/Sd2Card.h
@@ -1,191 +1,191 @@
-/* Arduino Sd2Card Library
- * Copyright (C) 2009 by William Greiman
- *
- * This file is part of the Arduino Sd2Card Library
- *
- * This Library is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This Library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with the Arduino Sd2Card Library. If not, see
- * .
- */
-#ifndef Sd2Card_h
-#define Sd2Card_h
-/**
- * \file
- * Sd2Card class
- */
-#include "Sd2PinMap.h"
-#include "SdInfo.h"
-#include "HardwareSPI.h"
-
-/** Set SCK to max rate of F_CPU/2. See Sd2Card::setSckRate(). */
-uint8_t const SPI_FULL_SPEED = 0;
-/** Set SCK rate to F_CPU/4. See Sd2Card::setSckRate(). */
-uint8_t const SPI_HALF_SPEED = 1;
-/** Set SCK rate to F_CPU/8. Sd2Card::setSckRate(). */
-uint8_t const SPI_QUARTER_SPEED = 2;
-//------------------------------------------------------------------------------
-/** Protect block zero from write if nonzero */
-#define SD_PROTECT_BLOCK_ZERO 1
-/** init timeout ms */
-uint16_t const SD_INIT_TIMEOUT = 2000;
-/** erase timeout ms */
-uint16_t const SD_ERASE_TIMEOUT = 10000;
-/** read timeout ms */
-uint16_t const SD_READ_TIMEOUT = 300;
-/** write time out ms */
-uint16_t const SD_WRITE_TIMEOUT = 600;
-//------------------------------------------------------------------------------
-// SD card errors
-/** timeout error for command CMD0 */
-uint8_t const SD_CARD_ERROR_CMD0 = 0X1;
-/** CMD8 was not accepted - not a valid SD card*/
-uint8_t const SD_CARD_ERROR_CMD8 = 0X2;
-/** card returned an error response for CMD17 (read block) */
-uint8_t const SD_CARD_ERROR_CMD17 = 0X3;
-/** card returned an error response for CMD24 (write block) */
-uint8_t const SD_CARD_ERROR_CMD24 = 0X4;
-/** WRITE_MULTIPLE_BLOCKS command failed */
-uint8_t const SD_CARD_ERROR_CMD25 = 0X05;
-/** card returned an error response for CMD58 (read OCR) */
-uint8_t const SD_CARD_ERROR_CMD58 = 0X06;
-/** SET_WR_BLK_ERASE_COUNT failed */
-uint8_t const SD_CARD_ERROR_ACMD23 = 0X07;
-/** card's ACMD41 initialization process timeout */
-uint8_t const SD_CARD_ERROR_ACMD41 = 0X08;
-/** card returned a bad CSR version field */
-uint8_t const SD_CARD_ERROR_BAD_CSD = 0X09;
-/** erase block group command failed */
-uint8_t const SD_CARD_ERROR_ERASE = 0X0A;
-/** card not capable of single block erase */
-uint8_t const SD_CARD_ERROR_ERASE_SINGLE_BLOCK = 0X0B;
-/** Erase sequence timed out */
-uint8_t const SD_CARD_ERROR_ERASE_TIMEOUT = 0X0C;
-/** card returned an error token instead of read data */
-uint8_t const SD_CARD_ERROR_READ = 0X0D;
-/** read CID or CSD failed */
-uint8_t const SD_CARD_ERROR_READ_REG = 0X0E;
-/** timeout while waiting for start of read data */
-uint8_t const SD_CARD_ERROR_READ_TIMEOUT = 0X0F;
-/** card did not accept STOP_TRAN_TOKEN */
-uint8_t const SD_CARD_ERROR_STOP_TRAN = 0X10;
-/** card returned an error token as a response to a write operation */
-uint8_t const SD_CARD_ERROR_WRITE = 0X11;
-/** attempt to write protected block zero */
-uint8_t const SD_CARD_ERROR_WRITE_BLOCK_ZERO = 0X12;
-/** card did not go ready for a multiple block write */
-uint8_t const SD_CARD_ERROR_WRITE_MULTIPLE = 0X13;
-/** card returned an error to a CMD13 status check after a write */
-uint8_t const SD_CARD_ERROR_WRITE_PROGRAMMING = 0X14;
-/** timeout occurred during write programming */
-uint8_t const SD_CARD_ERROR_WRITE_TIMEOUT = 0X15;
-/** incorrect rate selected */
-uint8_t const SD_CARD_ERROR_SCK_RATE = 0X16;
-//------------------------------------------------------------------------------
-// card types
-/** Standard capacity V1 SD card */
-uint8_t const SD_CARD_TYPE_SD1 = 1;
-/** Standard capacity V2 SD card */
-uint8_t const SD_CARD_TYPE_SD2 = 2;
-/** High Capacity SD card */
-uint8_t const SD_CARD_TYPE_SDHC = 3;
-//------------------------------------------------------------------------------
-/**
- * \class Sd2Card
- * \brief Raw access to SD and SDHC flash memory cards.
- */
-class Sd2Card {
- public:
- /** Construct an instance of Sd2Card. */
- Sd2Card(void) : errorCode_(0), inBlock_(0), partialBlockRead_(0), type_(0) {}
- uint32_t cardSize(void);
- uint8_t erase(uint32_t firstBlock, uint32_t lastBlock);
- uint8_t eraseSingleBlockEnable(void);
- /**
- * \return error code for last error. See Sd2Card.h for a list of error codes.
- */
- uint8_t errorCode(void) const {return errorCode_;}
- /** \return error data for last error. */
- uint8_t errorData(void) const {return status_;}
- /**
- * Initialize an SD flash memory card with default clock rate and chip
- * select pin. See sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin).
- */
- uint8_t init(void) {
-// return init(SPI_FULL_SPEED, SD_CHIP_SELECT_PIN);
- return false;
- }
-
- /**
- * Initialize an SD flash memory card with the selected SPI clock rate
- * and the default SD chip select pin.
- * See sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin).
- */
- uint8_t init(uint8_t sckRateID) {
-// return init(sckRateID, SD_CHIP_SELECT_PIN);
- return false;
- }
-
- uint8_t init(HardwareSPI *);
- void partialBlockRead(uint8_t value);
- /** Returns the current value, true or false, for partial block read. */
- uint8_t partialBlockRead(void) const {return partialBlockRead_;}
- uint8_t readBlock(uint32_t block, uint8_t* dst);
- uint8_t readData(uint32_t block,
- uint16_t offset, uint16_t count, uint8_t* dst);
- /**
- * Read a cards CID register. The CID contains card identification
- * information such as Manufacturer ID, Product name, Product serial
- * number and Manufacturing date. */
- uint8_t readCID(cid_t* cid) {
- return readRegister(CMD10, cid);
- }
- /**
- * Read a cards CSD register. The CSD contains Card-Specific Data that
- * provides information regarding access to the card's contents. */
- uint8_t readCSD(csd_t* csd) {
- return readRegister(CMD9, csd);
- }
- void readEnd(void);
- uint8_t setSckRate(uint8_t sckRateID);
- /** Return the card type: SD V1, SD V2 or SDHC */
- uint8_t type(void) const {return type_;}
- uint8_t writeBlock(uint32_t blockNumber, const uint8_t* src);
- uint8_t writeData(const uint8_t* src);
- uint8_t writeStart(uint32_t blockNumber, uint32_t eraseCount);
- uint8_t writeStop(void);
- private:
- uint32_t block_;
- uint8_t chipSelectPin_;
- uint8_t errorCode_;
- uint8_t inBlock_;
- uint16_t offset_;
- uint8_t partialBlockRead_;
- uint8_t status_;
- uint8_t type_;
- // private functions
- uint8_t cardAcmd(uint8_t cmd, uint32_t arg) {
- cardCommand(CMD55, 0);
- return cardCommand(cmd, arg);
- }
- uint8_t cardCommand(uint8_t cmd, uint32_t arg);
- void error(uint8_t code) {errorCode_ = code;}
- uint8_t readRegister(uint8_t cmd, void* buf);
- uint8_t sendWriteCommand(uint32_t blockNumber, uint32_t eraseCount);
- void chipSelectHigh(void);
- void chipSelectLow(void);
- void type(uint8_t value) {type_ = value;}
- uint8_t waitNotBusy(uint16_t timeoutMillis);
- uint8_t writeData(uint8_t token, const uint8_t* src);
- uint8_t waitStartBlock(void);
-};
-#endif // Sd2Card_h
+/* Arduino Sd2Card Library
+ * Copyright (C) 2009 by William Greiman
+ *
+ * This file is part of the Arduino Sd2Card Library
+ *
+ * This Library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Arduino Sd2Card Library. If not, see
+ * .
+ */
+#ifndef Sd2Card_h
+#define Sd2Card_h
+/**
+ * \file
+ * Sd2Card class
+ */
+#include "Sd2PinMap.h"
+#include "SdInfo.h"
+#include "HardwareSPI.h"
+
+/** Set SCK to max rate of F_CPU/2. See Sd2Card::setSckRate(). */
+uint8_t const SPI_FULL_SPEED = 0;
+/** Set SCK rate to F_CPU/4. See Sd2Card::setSckRate(). */
+uint8_t const SPI_HALF_SPEED = 1;
+/** Set SCK rate to F_CPU/8. Sd2Card::setSckRate(). */
+uint8_t const SPI_QUARTER_SPEED = 2;
+//------------------------------------------------------------------------------
+/** Protect block zero from write if nonzero */
+#define SD_PROTECT_BLOCK_ZERO 1
+/** init timeout ms */
+uint16_t const SD_INIT_TIMEOUT = 2000;
+/** erase timeout ms */
+uint16_t const SD_ERASE_TIMEOUT = 10000;
+/** read timeout ms */
+uint16_t const SD_READ_TIMEOUT = 300;
+/** write time out ms */
+uint16_t const SD_WRITE_TIMEOUT = 600;
+//------------------------------------------------------------------------------
+// SD card errors
+/** timeout error for command CMD0 */
+uint8_t const SD_CARD_ERROR_CMD0 = 0X1;
+/** CMD8 was not accepted - not a valid SD card*/
+uint8_t const SD_CARD_ERROR_CMD8 = 0X2;
+/** card returned an error response for CMD17 (read block) */
+uint8_t const SD_CARD_ERROR_CMD17 = 0X3;
+/** card returned an error response for CMD24 (write block) */
+uint8_t const SD_CARD_ERROR_CMD24 = 0X4;
+/** WRITE_MULTIPLE_BLOCKS command failed */
+uint8_t const SD_CARD_ERROR_CMD25 = 0X05;
+/** card returned an error response for CMD58 (read OCR) */
+uint8_t const SD_CARD_ERROR_CMD58 = 0X06;
+/** SET_WR_BLK_ERASE_COUNT failed */
+uint8_t const SD_CARD_ERROR_ACMD23 = 0X07;
+/** card's ACMD41 initialization process timeout */
+uint8_t const SD_CARD_ERROR_ACMD41 = 0X08;
+/** card returned a bad CSR version field */
+uint8_t const SD_CARD_ERROR_BAD_CSD = 0X09;
+/** erase block group command failed */
+uint8_t const SD_CARD_ERROR_ERASE = 0X0A;
+/** card not capable of single block erase */
+uint8_t const SD_CARD_ERROR_ERASE_SINGLE_BLOCK = 0X0B;
+/** Erase sequence timed out */
+uint8_t const SD_CARD_ERROR_ERASE_TIMEOUT = 0X0C;
+/** card returned an error token instead of read data */
+uint8_t const SD_CARD_ERROR_READ = 0X0D;
+/** read CID or CSD failed */
+uint8_t const SD_CARD_ERROR_READ_REG = 0X0E;
+/** timeout while waiting for start of read data */
+uint8_t const SD_CARD_ERROR_READ_TIMEOUT = 0X0F;
+/** card did not accept STOP_TRAN_TOKEN */
+uint8_t const SD_CARD_ERROR_STOP_TRAN = 0X10;
+/** card returned an error token as a response to a write operation */
+uint8_t const SD_CARD_ERROR_WRITE = 0X11;
+/** attempt to write protected block zero */
+uint8_t const SD_CARD_ERROR_WRITE_BLOCK_ZERO = 0X12;
+/** card did not go ready for a multiple block write */
+uint8_t const SD_CARD_ERROR_WRITE_MULTIPLE = 0X13;
+/** card returned an error to a CMD13 status check after a write */
+uint8_t const SD_CARD_ERROR_WRITE_PROGRAMMING = 0X14;
+/** timeout occurred during write programming */
+uint8_t const SD_CARD_ERROR_WRITE_TIMEOUT = 0X15;
+/** incorrect rate selected */
+uint8_t const SD_CARD_ERROR_SCK_RATE = 0X16;
+//------------------------------------------------------------------------------
+// card types
+/** Standard capacity V1 SD card */
+uint8_t const SD_CARD_TYPE_SD1 = 1;
+/** Standard capacity V2 SD card */
+uint8_t const SD_CARD_TYPE_SD2 = 2;
+/** High Capacity SD card */
+uint8_t const SD_CARD_TYPE_SDHC = 3;
+//------------------------------------------------------------------------------
+/**
+ * \class Sd2Card
+ * \brief Raw access to SD and SDHC flash memory cards.
+ */
+class Sd2Card {
+ public:
+ /** Construct an instance of Sd2Card. */
+ Sd2Card(void) : errorCode_(0), inBlock_(0), partialBlockRead_(0), type_(0) {}
+ uint32_t cardSize(void);
+ uint8_t erase(uint32_t firstBlock, uint32_t lastBlock);
+ uint8_t eraseSingleBlockEnable(void);
+ /**
+ * \return error code for last error. See Sd2Card.h for a list of error codes.
+ */
+ uint8_t errorCode(void) const {return errorCode_;}
+ /** \return error data for last error. */
+ uint8_t errorData(void) const {return status_;}
+ /**
+ * Initialize an SD flash memory card with default clock rate and chip
+ * select pin. See sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin).
+ */
+ uint8_t init(void) {
+// return init(SPI_FULL_SPEED, SD_CHIP_SELECT_PIN);
+ return false;
+ }
+
+ /**
+ * Initialize an SD flash memory card with the selected SPI clock rate
+ * and the default SD chip select pin.
+ * See sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin).
+ */
+ uint8_t init(uint8_t sckRateID) {
+// return init(sckRateID, SD_CHIP_SELECT_PIN);
+ return false;
+ }
+
+ uint8_t init(HardwareSPI *);
+ void partialBlockRead(uint8_t value);
+ /** Returns the current value, true or false, for partial block read. */
+ uint8_t partialBlockRead(void) const {return partialBlockRead_;}
+ uint8_t readBlock(uint32_t block, uint8_t* dst);
+ uint8_t readData(uint32_t block,
+ uint16_t offset, uint16_t count, uint8_t* dst);
+ /**
+ * Read a cards CID register. The CID contains card identification
+ * information such as Manufacturer ID, Product name, Product serial
+ * number and Manufacturing date. */
+ uint8_t readCID(cid_t* cid) {
+ return readRegister(CMD10, cid);
+ }
+ /**
+ * Read a cards CSD register. The CSD contains Card-Specific Data that
+ * provides information regarding access to the card's contents. */
+ uint8_t readCSD(csd_t* csd) {
+ return readRegister(CMD9, csd);
+ }
+ void readEnd(void);
+ uint8_t setSckRate(uint8_t sckRateID);
+ /** Return the card type: SD V1, SD V2 or SDHC */
+ uint8_t type(void) const {return type_;}
+ uint8_t writeBlock(uint32_t blockNumber, const uint8_t* src);
+ uint8_t writeData(const uint8_t* src);
+ uint8_t writeStart(uint32_t blockNumber, uint32_t eraseCount);
+ uint8_t writeStop(void);
+ private:
+ uint32_t block_;
+ uint8_t chipSelectPin_;
+ uint8_t errorCode_;
+ uint8_t inBlock_;
+ uint16_t offset_;
+ uint8_t partialBlockRead_;
+ uint8_t status_;
+ uint8_t type_;
+ // private functions
+ uint8_t cardAcmd(uint8_t cmd, uint32_t arg) {
+ cardCommand(CMD55, 0);
+ return cardCommand(cmd, arg);
+ }
+ uint8_t cardCommand(uint8_t cmd, uint32_t arg);
+ void error(uint8_t code) {errorCode_ = code;}
+ uint8_t readRegister(uint8_t cmd, void* buf);
+ uint8_t sendWriteCommand(uint32_t blockNumber, uint32_t eraseCount);
+ void chipSelectHigh(void);
+ void chipSelectLow(void);
+ void type(uint8_t value) {type_ = value;}
+ uint8_t waitNotBusy(uint16_t timeoutMillis);
+ uint8_t writeData(uint8_t token, const uint8_t* src);
+ uint8_t waitStartBlock(void);
+};
+#endif // Sd2Card_h
diff --git a/Libmaple/libmaple/libraries/mapleSDfat/Sd2PinMap.h b/Libmaple/libmaple/libraries/mapleSDfat/Sd2PinMap.h
index f23e9691..09c5329a 100644
--- a/Libmaple/libmaple/libraries/mapleSDfat/Sd2PinMap.h
+++ b/Libmaple/libmaple/libraries/mapleSDfat/Sd2PinMap.h
@@ -1,357 +1,357 @@
-/* Arduino SdFat Library
- * Copyright (C) 2010 by William Greiman
- *
- * This file is part of the Arduino SdFat Library
- *
- * This Library is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This Library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with the Arduino SdFat Library. If not, see
- * .
- */
-// Warning this file was generated by a program.
-#ifndef Sd2PinMap_h
-#define Sd2PinMap_h
-
-#include
-
-//------------------------------------------------------------------------------
-/** struct for mapping digital pins */
-struct pin_map_t
-{
- volatile uint8_t* ddr;
- volatile uint8_t* pin;
- volatile uint8_t* port;
- uint8_t bit;
-};
-/*
-//------------------------------------------------------------------------------
-#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
-// Mega
-
-// Two Wire (aka I2C) ports
-uint8_t const SDA_PIN = 20;
-uint8_t const SCL_PIN = 21;
-
-// SPI port
-uint8_t const SS_PIN = 53;
-uint8_t const MOSI_PIN = 51;
-uint8_t const MISO_PIN = 50;
-uint8_t const SCK_PIN = 52;
-
-static const pin_map_t digitalPinMap[] = {
- {&DDRE, &PINE, &PORTE, 0}, // E0 0
- {&DDRE, &PINE, &PORTE, 1}, // E1 1
- {&DDRE, &PINE, &PORTE, 4}, // E4 2
- {&DDRE, &PINE, &PORTE, 5}, // E5 3
- {&DDRG, &PING, &PORTG, 5}, // G5 4
- {&DDRE, &PINE, &PORTE, 3}, // E3 5
- {&DDRH, &PINH, &PORTH, 3}, // H3 6
- {&DDRH, &PINH, &PORTH, 4}, // H4 7
- {&DDRH, &PINH, &PORTH, 5}, // H5 8
- {&DDRH, &PINH, &PORTH, 6}, // H6 9
- {&DDRB, &PINB, &PORTB, 4}, // B4 10
- {&DDRB, &PINB, &PORTB, 5}, // B5 11
- {&DDRB, &PINB, &PORTB, 6}, // B6 12
- {&DDRB, &PINB, &PORTB, 7}, // B7 13
- {&DDRJ, &PINJ, &PORTJ, 1}, // J1 14
- {&DDRJ, &PINJ, &PORTJ, 0}, // J0 15
- {&DDRH, &PINH, &PORTH, 1}, // H1 16
- {&DDRH, &PINH, &PORTH, 0}, // H0 17
- {&DDRD, &PIND, &PORTD, 3}, // D3 18
- {&DDRD, &PIND, &PORTD, 2}, // D2 19
- {&DDRD, &PIND, &PORTD, 1}, // D1 20
- {&DDRD, &PIND, &PORTD, 0}, // D0 21
- {&DDRA, &PINA, &PORTA, 0}, // A0 22
- {&DDRA, &PINA, &PORTA, 1}, // A1 23
- {&DDRA, &PINA, &PORTA, 2}, // A2 24
- {&DDRA, &PINA, &PORTA, 3}, // A3 25
- {&DDRA, &PINA, &PORTA, 4}, // A4 26
- {&DDRA, &PINA, &PORTA, 5}, // A5 27
- {&DDRA, &PINA, &PORTA, 6}, // A6 28
- {&DDRA, &PINA, &PORTA, 7}, // A7 29
- {&DDRC, &PINC, &PORTC, 7}, // C7 30
- {&DDRC, &PINC, &PORTC, 6}, // C6 31
- {&DDRC, &PINC, &PORTC, 5}, // C5 32
- {&DDRC, &PINC, &PORTC, 4}, // C4 33
- {&DDRC, &PINC, &PORTC, 3}, // C3 34
- {&DDRC, &PINC, &PORTC, 2}, // C2 35
- {&DDRC, &PINC, &PORTC, 1}, // C1 36
- {&DDRC, &PINC, &PORTC, 0}, // C0 37
- {&DDRD, &PIND, &PORTD, 7}, // D7 38
- {&DDRG, &PING, &PORTG, 2}, // G2 39
- {&DDRG, &PING, &PORTG, 1}, // G1 40
- {&DDRG, &PING, &PORTG, 0}, // G0 41
- {&DDRL, &PINL, &PORTL, 7}, // L7 42
- {&DDRL, &PINL, &PORTL, 6}, // L6 43
- {&DDRL, &PINL, &PORTL, 5}, // L5 44
- {&DDRL, &PINL, &PORTL, 4}, // L4 45
- {&DDRL, &PINL, &PORTL, 3}, // L3 46
- {&DDRL, &PINL, &PORTL, 2}, // L2 47
- {&DDRL, &PINL, &PORTL, 1}, // L1 48
- {&DDRL, &PINL, &PORTL, 0}, // L0 49
- {&DDRB, &PINB, &PORTB, 3}, // B3 50
- {&DDRB, &PINB, &PORTB, 2}, // B2 51
- {&DDRB, &PINB, &PORTB, 1}, // B1 52
- {&DDRB, &PINB, &PORTB, 0}, // B0 53
- {&DDRF, &PINF, &PORTF, 0}, // F0 54
- {&DDRF, &PINF, &PORTF, 1}, // F1 55
- {&DDRF, &PINF, &PORTF, 2}, // F2 56
- {&DDRF, &PINF, &PORTF, 3}, // F3 57
- {&DDRF, &PINF, &PORTF, 4}, // F4 58
- {&DDRF, &PINF, &PORTF, 5}, // F5 59
- {&DDRF, &PINF, &PORTF, 6}, // F6 60
- {&DDRF, &PINF, &PORTF, 7}, // F7 61
- {&DDRK, &PINK, &PORTK, 0}, // K0 62
- {&DDRK, &PINK, &PORTK, 1}, // K1 63
- {&DDRK, &PINK, &PORTK, 2}, // K2 64
- {&DDRK, &PINK, &PORTK, 3}, // K3 65
- {&DDRK, &PINK, &PORTK, 4}, // K4 66
- {&DDRK, &PINK, &PORTK, 5}, // K5 67
- {&DDRK, &PINK, &PORTK, 6}, // K6 68
- {&DDRK, &PINK, &PORTK, 7} // K7 69
-};
-//------------------------------------------------------------------------------
-#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__)
-// Sanguino
-
-// Two Wire (aka I2C) ports
-uint8_t const SDA_PIN = 17;
-uint8_t const SCL_PIN = 18;
-
-// SPI port
-uint8_t const SS_PIN = 4;
-uint8_t const MOSI_PIN = 5;
-uint8_t const MISO_PIN = 6;
-uint8_t const SCK_PIN = 7;
-
-static const pin_map_t digitalPinMap[] = {
- {&DDRB, &PINB, &PORTB, 0}, // B0 0
- {&DDRB, &PINB, &PORTB, 1}, // B1 1
- {&DDRB, &PINB, &PORTB, 2}, // B2 2
- {&DDRB, &PINB, &PORTB, 3}, // B3 3
- {&DDRB, &PINB, &PORTB, 4}, // B4 4
- {&DDRB, &PINB, &PORTB, 5}, // B5 5
- {&DDRB, &PINB, &PORTB, 6}, // B6 6
- {&DDRB, &PINB, &PORTB, 7}, // B7 7
- {&DDRD, &PIND, &PORTD, 0}, // D0 8
- {&DDRD, &PIND, &PORTD, 1}, // D1 9
- {&DDRD, &PIND, &PORTD, 2}, // D2 10
- {&DDRD, &PIND, &PORTD, 3}, // D3 11
- {&DDRD, &PIND, &PORTD, 4}, // D4 12
- {&DDRD, &PIND, &PORTD, 5}, // D5 13
- {&DDRD, &PIND, &PORTD, 6}, // D6 14
- {&DDRD, &PIND, &PORTD, 7}, // D7 15
- {&DDRC, &PINC, &PORTC, 0}, // C0 16
- {&DDRC, &PINC, &PORTC, 1}, // C1 17
- {&DDRC, &PINC, &PORTC, 2}, // C2 18
- {&DDRC, &PINC, &PORTC, 3}, // C3 19
- {&DDRC, &PINC, &PORTC, 4}, // C4 20
- {&DDRC, &PINC, &PORTC, 5}, // C5 21
- {&DDRC, &PINC, &PORTC, 6}, // C6 22
- {&DDRC, &PINC, &PORTC, 7}, // C7 23
- {&DDRA, &PINA, &PORTA, 7}, // A7 24
- {&DDRA, &PINA, &PORTA, 6}, // A6 25
- {&DDRA, &PINA, &PORTA, 5}, // A5 26
- {&DDRA, &PINA, &PORTA, 4}, // A4 27
- {&DDRA, &PINA, &PORTA, 3}, // A3 28
- {&DDRA, &PINA, &PORTA, 2}, // A2 29
- {&DDRA, &PINA, &PORTA, 1}, // A1 30
- {&DDRA, &PINA, &PORTA, 0} // A0 31
-};
-//------------------------------------------------------------------------------
-#elif defined(__AVR_ATmega32U4__)
-// Teensy 2.0
-
-// Two Wire (aka I2C) ports
-uint8_t const SDA_PIN = 6;
-uint8_t const SCL_PIN = 5;
-
-// SPI port
-uint8_t const SS_PIN = 0;
-uint8_t const MOSI_PIN = 2;
-uint8_t const MISO_PIN = 3;
-uint8_t const SCK_PIN = 1;
-
-static const pin_map_t digitalPinMap[] = {
- {&DDRB, &PINB, &PORTB, 0}, // B0 0
- {&DDRB, &PINB, &PORTB, 1}, // B1 1
- {&DDRB, &PINB, &PORTB, 2}, // B2 2
- {&DDRB, &PINB, &PORTB, 3}, // B3 3
- {&DDRB, &PINB, &PORTB, 7}, // B7 4
- {&DDRD, &PIND, &PORTD, 0}, // D0 5
- {&DDRD, &PIND, &PORTD, 1}, // D1 6
- {&DDRD, &PIND, &PORTD, 2}, // D2 7
- {&DDRD, &PIND, &PORTD, 3}, // D3 8
- {&DDRC, &PINC, &PORTC, 6}, // C6 9
- {&DDRC, &PINC, &PORTC, 7}, // C7 10
- {&DDRD, &PIND, &PORTD, 6}, // D6 11
- {&DDRD, &PIND, &PORTD, 7}, // D7 12
- {&DDRB, &PINB, &PORTB, 4}, // B4 13
- {&DDRB, &PINB, &PORTB, 5}, // B5 14
- {&DDRB, &PINB, &PORTB, 6}, // B6 15
- {&DDRF, &PINF, &PORTF, 7}, // F7 16
- {&DDRF, &PINF, &PORTF, 6}, // F6 17
- {&DDRF, &PINF, &PORTF, 5}, // F5 18
- {&DDRF, &PINF, &PORTF, 4}, // F4 19
- {&DDRF, &PINF, &PORTF, 1}, // F1 20
- {&DDRF, &PINF, &PORTF, 0}, // F0 21
- {&DDRD, &PIND, &PORTD, 4}, // D4 22
- {&DDRD, &PIND, &PORTD, 5}, // D5 23
- {&DDRE, &PINE, &PORTE, 6} // E6 24
-};
-//------------------------------------------------------------------------------
-#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
-// Teensy++ 1.0 & 2.0
-
-// Two Wire (aka I2C) ports
-uint8_t const SDA_PIN = 1;
-uint8_t const SCL_PIN = 0;
-
-// SPI port
-uint8_t const SS_PIN = 20;
-uint8_t const MOSI_PIN = 22;
-uint8_t const MISO_PIN = 23;
-uint8_t const SCK_PIN = 21;
-
-static const pin_map_t digitalPinMap[] = {
- {&DDRD, &PIND, &PORTD, 0}, // D0 0
- {&DDRD, &PIND, &PORTD, 1}, // D1 1
- {&DDRD, &PIND, &PORTD, 2}, // D2 2
- {&DDRD, &PIND, &PORTD, 3}, // D3 3
- {&DDRD, &PIND, &PORTD, 4}, // D4 4
- {&DDRD, &PIND, &PORTD, 5}, // D5 5
- {&DDRD, &PIND, &PORTD, 6}, // D6 6
- {&DDRD, &PIND, &PORTD, 7}, // D7 7
- {&DDRE, &PINE, &PORTE, 0}, // E0 8
- {&DDRE, &PINE, &PORTE, 1}, // E1 9
- {&DDRC, &PINC, &PORTC, 0}, // C0 10
- {&DDRC, &PINC, &PORTC, 1}, // C1 11
- {&DDRC, &PINC, &PORTC, 2}, // C2 12
- {&DDRC, &PINC, &PORTC, 3}, // C3 13
- {&DDRC, &PINC, &PORTC, 4}, // C4 14
- {&DDRC, &PINC, &PORTC, 5}, // C5 15
- {&DDRC, &PINC, &PORTC, 6}, // C6 16
- {&DDRC, &PINC, &PORTC, 7}, // C7 17
- {&DDRE, &PINE, &PORTE, 6}, // E6 18
- {&DDRE, &PINE, &PORTE, 7}, // E7 19
- {&DDRB, &PINB, &PORTB, 0}, // B0 20
- {&DDRB, &PINB, &PORTB, 1}, // B1 21
- {&DDRB, &PINB, &PORTB, 2}, // B2 22
- {&DDRB, &PINB, &PORTB, 3}, // B3 23
- {&DDRB, &PINB, &PORTB, 4}, // B4 24
- {&DDRB, &PINB, &PORTB, 5}, // B5 25
- {&DDRB, &PINB, &PORTB, 6}, // B6 26
- {&DDRB, &PINB, &PORTB, 7}, // B7 27
- {&DDRA, &PINA, &PORTA, 0}, // A0 28
- {&DDRA, &PINA, &PORTA, 1}, // A1 29
- {&DDRA, &PINA, &PORTA, 2}, // A2 30
- {&DDRA, &PINA, &PORTA, 3}, // A3 31
- {&DDRA, &PINA, &PORTA, 4}, // A4 32
- {&DDRA, &PINA, &PORTA, 5}, // A5 33
- {&DDRA, &PINA, &PORTA, 6}, // A6 34
- {&DDRA, &PINA, &PORTA, 7}, // A7 35
- {&DDRE, &PINE, &PORTE, 4}, // E4 36
- {&DDRE, &PINE, &PORTE, 5}, // E5 37
- {&DDRF, &PINF, &PORTF, 0}, // F0 38
- {&DDRF, &PINF, &PORTF, 1}, // F1 39
- {&DDRF, &PINF, &PORTF, 2}, // F2 40
- {&DDRF, &PINF, &PORTF, 3}, // F3 41
- {&DDRF, &PINF, &PORTF, 4}, // F4 42
- {&DDRF, &PINF, &PORTF, 5}, // F5 43
- {&DDRF, &PINF, &PORTF, 6}, // F6 44
- {&DDRF, &PINF, &PORTF, 7} // F7 45
-};
-//------------------------------------------------------------------------------
-#else // defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
-// 168 and 328 Arduinos
-
-// Two Wire (aka I2C) ports
-uint8_t const SDA_PIN = 18;
-uint8_t const SCL_PIN = 19;
-
-// SPI port
-uint8_t const SS_PIN = 10;
-uint8_t const MOSI_PIN = 11;
-uint8_t const MISO_PIN = 12;
-uint8_t const SCK_PIN = 13;
-
-static const pin_map_t digitalPinMap[] = {
- {&DDRD, &PIND, &PORTD, 0}, // D0 0
- {&DDRD, &PIND, &PORTD, 1}, // D1 1
- {&DDRD, &PIND, &PORTD, 2}, // D2 2
- {&DDRD, &PIND, &PORTD, 3}, // D3 3
- {&DDRD, &PIND, &PORTD, 4}, // D4 4
- {&DDRD, &PIND, &PORTD, 5}, // D5 5
- {&DDRD, &PIND, &PORTD, 6}, // D6 6
- {&DDRD, &PIND, &PORTD, 7}, // D7 7
- {&DDRB, &PINB, &PORTB, 0}, // B0 8
- {&DDRB, &PINB, &PORTB, 1}, // B1 9
- {&DDRB, &PINB, &PORTB, 2}, // B2 10
- {&DDRB, &PINB, &PORTB, 3}, // B3 11
- {&DDRB, &PINB, &PORTB, 4}, // B4 12
- {&DDRB, &PINB, &PORTB, 5}, // B5 13
- {&DDRC, &PINC, &PORTC, 0}, // C0 14
- {&DDRC, &PINC, &PORTC, 1}, // C1 15
- {&DDRC, &PINC, &PORTC, 2}, // C2 16
- {&DDRC, &PINC, &PORTC, 3}, // C3 17
- {&DDRC, &PINC, &PORTC, 4}, // C4 18
- {&DDRC, &PINC, &PORTC, 5} // C5 19
-};
-#endif // defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
-//------------------------------------------------------------------------------
-static const uint8_t digitalPinCount = sizeof(digitalPinMap)/sizeof(pin_map_t);
-
-uint8_t badPinNumber(void)
- __attribute__((error("Pin number is too large or not a constant")));
-
-static inline __attribute__((always_inline))
- uint8_t getPinMode(uint8_t pin) {
- if (__builtin_constant_p(pin) && pin < digitalPinCount) {
- return (*digitalPinMap[pin].ddr >> digitalPinMap[pin].bit) & 1;
- } else {
- return badPinNumber();
- }
-}
-static inline __attribute__((always_inline))
- void setPinMode(uint8_t pin, uint8_t mode) {
- if (__builtin_constant_p(pin) && pin < digitalPinCount) {
- if (mode) {
- *digitalPinMap[pin].ddr |= 1 << digitalPinMap[pin].bit;
- } else {
- *digitalPinMap[pin].ddr &= ~(1 << digitalPinMap[pin].bit);
- }
- } else {
- badPinNumber();
- }
-}
-static inline __attribute__((always_inline))
- uint8_t fastDigitalRead(uint8_t pin) {
- if (__builtin_constant_p(pin) && pin < digitalPinCount) {
- return (*digitalPinMap[pin].pin >> digitalPinMap[pin].bit) & 1;
- } else {
- return badPinNumber();
- }
-}
-static inline __attribute__((always_inline))
- void fastDigitalWrite(uint8_t pin, uint8_t value) {
- if (__builtin_constant_p(pin) && pin < digitalPinCount) {
- if (value) {
- *digitalPinMap[pin].port |= 1 << digitalPinMap[pin].bit;
- } else {
- *digitalPinMap[pin].port &= ~(1 << digitalPinMap[pin].bit);
- }
- } else {
- badPinNumber();
- }
-}
-*/
-#endif // Sd2PinMap_h
+/* Arduino SdFat Library
+ * Copyright (C) 2010 by William Greiman
+ *
+ * This file is part of the Arduino SdFat Library
+ *
+ * This Library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Arduino SdFat Library. If not, see
+ * .
+ */
+// Warning this file was generated by a program.
+#ifndef Sd2PinMap_h
+#define Sd2PinMap_h
+
+#include
+
+//------------------------------------------------------------------------------
+/** struct for mapping digital pins */
+struct pin_map_t
+{
+ volatile uint8_t* ddr;
+ volatile uint8_t* pin;
+ volatile uint8_t* port;
+ uint8_t bit;
+};
+/*
+//------------------------------------------------------------------------------
+#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
+// Mega
+
+// Two Wire (aka I2C) ports
+uint8_t const SDA_PIN = 20;
+uint8_t const SCL_PIN = 21;
+
+// SPI port
+uint8_t const SS_PIN = 53;
+uint8_t const MOSI_PIN = 51;
+uint8_t const MISO_PIN = 50;
+uint8_t const SCK_PIN = 52;
+
+static const pin_map_t digitalPinMap[] = {
+ {&DDRE, &PINE, &PORTE, 0}, // E0 0
+ {&DDRE, &PINE, &PORTE, 1}, // E1 1
+ {&DDRE, &PINE, &PORTE, 4}, // E4 2
+ {&DDRE, &PINE, &PORTE, 5}, // E5 3
+ {&DDRG, &PING, &PORTG, 5}, // G5 4
+ {&DDRE, &PINE, &PORTE, 3}, // E3 5
+ {&DDRH, &PINH, &PORTH, 3}, // H3 6
+ {&DDRH, &PINH, &PORTH, 4}, // H4 7
+ {&DDRH, &PINH, &PORTH, 5}, // H5 8
+ {&DDRH, &PINH, &PORTH, 6}, // H6 9
+ {&DDRB, &PINB, &PORTB, 4}, // B4 10
+ {&DDRB, &PINB, &PORTB, 5}, // B5 11
+ {&DDRB, &PINB, &PORTB, 6}, // B6 12
+ {&DDRB, &PINB, &PORTB, 7}, // B7 13
+ {&DDRJ, &PINJ, &PORTJ, 1}, // J1 14
+ {&DDRJ, &PINJ, &PORTJ, 0}, // J0 15
+ {&DDRH, &PINH, &PORTH, 1}, // H1 16
+ {&DDRH, &PINH, &PORTH, 0}, // H0 17
+ {&DDRD, &PIND, &PORTD, 3}, // D3 18
+ {&DDRD, &PIND, &PORTD, 2}, // D2 19
+ {&DDRD, &PIND, &PORTD, 1}, // D1 20
+ {&DDRD, &PIND, &PORTD, 0}, // D0 21
+ {&DDRA, &PINA, &PORTA, 0}, // A0 22
+ {&DDRA, &PINA, &PORTA, 1}, // A1 23
+ {&DDRA, &PINA, &PORTA, 2}, // A2 24
+ {&DDRA, &PINA, &PORTA, 3}, // A3 25
+ {&DDRA, &PINA, &PORTA, 4}, // A4 26
+ {&DDRA, &PINA, &PORTA, 5}, // A5 27
+ {&DDRA, &PINA, &PORTA, 6}, // A6 28
+ {&DDRA, &PINA, &PORTA, 7}, // A7 29
+ {&DDRC, &PINC, &PORTC, 7}, // C7 30
+ {&DDRC, &PINC, &PORTC, 6}, // C6 31
+ {&DDRC, &PINC, &PORTC, 5}, // C5 32
+ {&DDRC, &PINC, &PORTC, 4}, // C4 33
+ {&DDRC, &PINC, &PORTC, 3}, // C3 34
+ {&DDRC, &PINC, &PORTC, 2}, // C2 35
+ {&DDRC, &PINC, &PORTC, 1}, // C1 36
+ {&DDRC, &PINC, &PORTC, 0}, // C0 37
+ {&DDRD, &PIND, &PORTD, 7}, // D7 38
+ {&DDRG, &PING, &PORTG, 2}, // G2 39
+ {&DDRG, &PING, &PORTG, 1}, // G1 40
+ {&DDRG, &PING, &PORTG, 0}, // G0 41
+ {&DDRL, &PINL, &PORTL, 7}, // L7 42
+ {&DDRL, &PINL, &PORTL, 6}, // L6 43
+ {&DDRL, &PINL, &PORTL, 5}, // L5 44
+ {&DDRL, &PINL, &PORTL, 4}, // L4 45
+ {&DDRL, &PINL, &PORTL, 3}, // L3 46
+ {&DDRL, &PINL, &PORTL, 2}, // L2 47
+ {&DDRL, &PINL, &PORTL, 1}, // L1 48
+ {&DDRL, &PINL, &PORTL, 0}, // L0 49
+ {&DDRB, &PINB, &PORTB, 3}, // B3 50
+ {&DDRB, &PINB, &PORTB, 2}, // B2 51
+ {&DDRB, &PINB, &PORTB, 1}, // B1 52
+ {&DDRB, &PINB, &PORTB, 0}, // B0 53
+ {&DDRF, &PINF, &PORTF, 0}, // F0 54
+ {&DDRF, &PINF, &PORTF, 1}, // F1 55
+ {&DDRF, &PINF, &PORTF, 2}, // F2 56
+ {&DDRF, &PINF, &PORTF, 3}, // F3 57
+ {&DDRF, &PINF, &PORTF, 4}, // F4 58
+ {&DDRF, &PINF, &PORTF, 5}, // F5 59
+ {&DDRF, &PINF, &PORTF, 6}, // F6 60
+ {&DDRF, &PINF, &PORTF, 7}, // F7 61
+ {&DDRK, &PINK, &PORTK, 0}, // K0 62
+ {&DDRK, &PINK, &PORTK, 1}, // K1 63
+ {&DDRK, &PINK, &PORTK, 2}, // K2 64
+ {&DDRK, &PINK, &PORTK, 3}, // K3 65
+ {&DDRK, &PINK, &PORTK, 4}, // K4 66
+ {&DDRK, &PINK, &PORTK, 5}, // K5 67
+ {&DDRK, &PINK, &PORTK, 6}, // K6 68
+ {&DDRK, &PINK, &PORTK, 7} // K7 69
+};
+//------------------------------------------------------------------------------
+#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__)
+// Sanguino
+
+// Two Wire (aka I2C) ports
+uint8_t const SDA_PIN = 17;
+uint8_t const SCL_PIN = 18;
+
+// SPI port
+uint8_t const SS_PIN = 4;
+uint8_t const MOSI_PIN = 5;
+uint8_t const MISO_PIN = 6;
+uint8_t const SCK_PIN = 7;
+
+static const pin_map_t digitalPinMap[] = {
+ {&DDRB, &PINB, &PORTB, 0}, // B0 0
+ {&DDRB, &PINB, &PORTB, 1}, // B1 1
+ {&DDRB, &PINB, &PORTB, 2}, // B2 2
+ {&DDRB, &PINB, &PORTB, 3}, // B3 3
+ {&DDRB, &PINB, &PORTB, 4}, // B4 4
+ {&DDRB, &PINB, &PORTB, 5}, // B5 5
+ {&DDRB, &PINB, &PORTB, 6}, // B6 6
+ {&DDRB, &PINB, &PORTB, 7}, // B7 7
+ {&DDRD, &PIND, &PORTD, 0}, // D0 8
+ {&DDRD, &PIND, &PORTD, 1}, // D1 9
+ {&DDRD, &PIND, &PORTD, 2}, // D2 10
+ {&DDRD, &PIND, &PORTD, 3}, // D3 11
+ {&DDRD, &PIND, &PORTD, 4}, // D4 12
+ {&DDRD, &PIND, &PORTD, 5}, // D5 13
+ {&DDRD, &PIND, &PORTD, 6}, // D6 14
+ {&DDRD, &PIND, &PORTD, 7}, // D7 15
+ {&DDRC, &PINC, &PORTC, 0}, // C0 16
+ {&DDRC, &PINC, &PORTC, 1}, // C1 17
+ {&DDRC, &PINC, &PORTC, 2}, // C2 18
+ {&DDRC, &PINC, &PORTC, 3}, // C3 19
+ {&DDRC, &PINC, &PORTC, 4}, // C4 20
+ {&DDRC, &PINC, &PORTC, 5}, // C5 21
+ {&DDRC, &PINC, &PORTC, 6}, // C6 22
+ {&DDRC, &PINC, &PORTC, 7}, // C7 23
+ {&DDRA, &PINA, &PORTA, 7}, // A7 24
+ {&DDRA, &PINA, &PORTA, 6}, // A6 25
+ {&DDRA, &PINA, &PORTA, 5}, // A5 26
+ {&DDRA, &PINA, &PORTA, 4}, // A4 27
+ {&DDRA, &PINA, &PORTA, 3}, // A3 28
+ {&DDRA, &PINA, &PORTA, 2}, // A2 29
+ {&DDRA, &PINA, &PORTA, 1}, // A1 30
+ {&DDRA, &PINA, &PORTA, 0} // A0 31
+};
+//------------------------------------------------------------------------------
+#elif defined(__AVR_ATmega32U4__)
+// Teensy 2.0
+
+// Two Wire (aka I2C) ports
+uint8_t const SDA_PIN = 6;
+uint8_t const SCL_PIN = 5;
+
+// SPI port
+uint8_t const SS_PIN = 0;
+uint8_t const MOSI_PIN = 2;
+uint8_t const MISO_PIN = 3;
+uint8_t const SCK_PIN = 1;
+
+static const pin_map_t digitalPinMap[] = {
+ {&DDRB, &PINB, &PORTB, 0}, // B0 0
+ {&DDRB, &PINB, &PORTB, 1}, // B1 1
+ {&DDRB, &PINB, &PORTB, 2}, // B2 2
+ {&DDRB, &PINB, &PORTB, 3}, // B3 3
+ {&DDRB, &PINB, &PORTB, 7}, // B7 4
+ {&DDRD, &PIND, &PORTD, 0}, // D0 5
+ {&DDRD, &PIND, &PORTD, 1}, // D1 6
+ {&DDRD, &PIND, &PORTD, 2}, // D2 7
+ {&DDRD, &PIND, &PORTD, 3}, // D3 8
+ {&DDRC, &PINC, &PORTC, 6}, // C6 9
+ {&DDRC, &PINC, &PORTC, 7}, // C7 10
+ {&DDRD, &PIND, &PORTD, 6}, // D6 11
+ {&DDRD, &PIND, &PORTD, 7}, // D7 12
+ {&DDRB, &PINB, &PORTB, 4}, // B4 13
+ {&DDRB, &PINB, &PORTB, 5}, // B5 14
+ {&DDRB, &PINB, &PORTB, 6}, // B6 15
+ {&DDRF, &PINF, &PORTF, 7}, // F7 16
+ {&DDRF, &PINF, &PORTF, 6}, // F6 17
+ {&DDRF, &PINF, &PORTF, 5}, // F5 18
+ {&DDRF, &PINF, &PORTF, 4}, // F4 19
+ {&DDRF, &PINF, &PORTF, 1}, // F1 20
+ {&DDRF, &PINF, &PORTF, 0}, // F0 21
+ {&DDRD, &PIND, &PORTD, 4}, // D4 22
+ {&DDRD, &PIND, &PORTD, 5}, // D5 23
+ {&DDRE, &PINE, &PORTE, 6} // E6 24
+};
+//------------------------------------------------------------------------------
+#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
+// Teensy++ 1.0 & 2.0
+
+// Two Wire (aka I2C) ports
+uint8_t const SDA_PIN = 1;
+uint8_t const SCL_PIN = 0;
+
+// SPI port
+uint8_t const SS_PIN = 20;
+uint8_t const MOSI_PIN = 22;
+uint8_t const MISO_PIN = 23;
+uint8_t const SCK_PIN = 21;
+
+static const pin_map_t digitalPinMap[] = {
+ {&DDRD, &PIND, &PORTD, 0}, // D0 0
+ {&DDRD, &PIND, &PORTD, 1}, // D1 1
+ {&DDRD, &PIND, &PORTD, 2}, // D2 2
+ {&DDRD, &PIND, &PORTD, 3}, // D3 3
+ {&DDRD, &PIND, &PORTD, 4}, // D4 4
+ {&DDRD, &PIND, &PORTD, 5}, // D5 5
+ {&DDRD, &PIND, &PORTD, 6}, // D6 6
+ {&DDRD, &PIND, &PORTD, 7}, // D7 7
+ {&DDRE, &PINE, &PORTE, 0}, // E0 8
+ {&DDRE, &PINE, &PORTE, 1}, // E1 9
+ {&DDRC, &PINC, &PORTC, 0}, // C0 10
+ {&DDRC, &PINC, &PORTC, 1}, // C1 11
+ {&DDRC, &PINC, &PORTC, 2}, // C2 12
+ {&DDRC, &PINC, &PORTC, 3}, // C3 13
+ {&DDRC, &PINC, &PORTC, 4}, // C4 14
+ {&DDRC, &PINC, &PORTC, 5}, // C5 15
+ {&DDRC, &PINC, &PORTC, 6}, // C6 16
+ {&DDRC, &PINC, &PORTC, 7}, // C7 17
+ {&DDRE, &PINE, &PORTE, 6}, // E6 18
+ {&DDRE, &PINE, &PORTE, 7}, // E7 19
+ {&DDRB, &PINB, &PORTB, 0}, // B0 20
+ {&DDRB, &PINB, &PORTB, 1}, // B1 21
+ {&DDRB, &PINB, &PORTB, 2}, // B2 22
+ {&DDRB, &PINB, &PORTB, 3}, // B3 23
+ {&DDRB, &PINB, &PORTB, 4}, // B4 24
+ {&DDRB, &PINB, &PORTB, 5}, // B5 25
+ {&DDRB, &PINB, &PORTB, 6}, // B6 26
+ {&DDRB, &PINB, &PORTB, 7}, // B7 27
+ {&DDRA, &PINA, &PORTA, 0}, // A0 28
+ {&DDRA, &PINA, &PORTA, 1}, // A1 29
+ {&DDRA, &PINA, &PORTA, 2}, // A2 30
+ {&DDRA, &PINA, &PORTA, 3}, // A3 31
+ {&DDRA, &PINA, &PORTA, 4}, // A4 32
+ {&DDRA, &PINA, &PORTA, 5}, // A5 33
+ {&DDRA, &PINA, &PORTA, 6}, // A6 34
+ {&DDRA, &PINA, &PORTA, 7}, // A7 35
+ {&DDRE, &PINE, &PORTE, 4}, // E4 36
+ {&DDRE, &PINE, &PORTE, 5}, // E5 37
+ {&DDRF, &PINF, &PORTF, 0}, // F0 38
+ {&DDRF, &PINF, &PORTF, 1}, // F1 39
+ {&DDRF, &PINF, &PORTF, 2}, // F2 40
+ {&DDRF, &PINF, &PORTF, 3}, // F3 41
+ {&DDRF, &PINF, &PORTF, 4}, // F4 42
+ {&DDRF, &PINF, &PORTF, 5}, // F5 43
+ {&DDRF, &PINF, &PORTF, 6}, // F6 44
+ {&DDRF, &PINF, &PORTF, 7} // F7 45
+};
+//------------------------------------------------------------------------------
+#else // defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
+// 168 and 328 Arduinos
+
+// Two Wire (aka I2C) ports
+uint8_t const SDA_PIN = 18;
+uint8_t const SCL_PIN = 19;
+
+// SPI port
+uint8_t const SS_PIN = 10;
+uint8_t const MOSI_PIN = 11;
+uint8_t const MISO_PIN = 12;
+uint8_t const SCK_PIN = 13;
+
+static const pin_map_t digitalPinMap[] = {
+ {&DDRD, &PIND, &PORTD, 0}, // D0 0
+ {&DDRD, &PIND, &PORTD, 1}, // D1 1
+ {&DDRD, &PIND, &PORTD, 2}, // D2 2
+ {&DDRD, &PIND, &PORTD, 3}, // D3 3
+ {&DDRD, &PIND, &PORTD, 4}, // D4 4
+ {&DDRD, &PIND, &PORTD, 5}, // D5 5
+ {&DDRD, &PIND, &PORTD, 6}, // D6 6
+ {&DDRD, &PIND, &PORTD, 7}, // D7 7
+ {&DDRB, &PINB, &PORTB, 0}, // B0 8
+ {&DDRB, &PINB, &PORTB, 1}, // B1 9
+ {&DDRB, &PINB, &PORTB, 2}, // B2 10
+ {&DDRB, &PINB, &PORTB, 3}, // B3 11
+ {&DDRB, &PINB, &PORTB, 4}, // B4 12
+ {&DDRB, &PINB, &PORTB, 5}, // B5 13
+ {&DDRC, &PINC, &PORTC, 0}, // C0 14
+ {&DDRC, &PINC, &PORTC, 1}, // C1 15
+ {&DDRC, &PINC, &PORTC, 2}, // C2 16
+ {&DDRC, &PINC, &PORTC, 3}, // C3 17
+ {&DDRC, &PINC, &PORTC, 4}, // C4 18
+ {&DDRC, &PINC, &PORTC, 5} // C5 19
+};
+#endif // defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
+//------------------------------------------------------------------------------
+static const uint8_t digitalPinCount = sizeof(digitalPinMap)/sizeof(pin_map_t);
+
+uint8_t badPinNumber(void)
+ __attribute__((error("Pin number is too large or not a constant")));
+
+static inline __attribute__((always_inline))
+ uint8_t getPinMode(uint8_t pin) {
+ if (__builtin_constant_p(pin) && pin < digitalPinCount) {
+ return (*digitalPinMap[pin].ddr >> digitalPinMap[pin].bit) & 1;
+ } else {
+ return badPinNumber();
+ }
+}
+static inline __attribute__((always_inline))
+ void setPinMode(uint8_t pin, uint8_t mode) {
+ if (__builtin_constant_p(pin) && pin < digitalPinCount) {
+ if (mode) {
+ *digitalPinMap[pin].ddr |= 1 << digitalPinMap[pin].bit;
+ } else {
+ *digitalPinMap[pin].ddr &= ~(1 << digitalPinMap[pin].bit);
+ }
+ } else {
+ badPinNumber();
+ }
+}
+static inline __attribute__((always_inline))
+ uint8_t fastDigitalRead(uint8_t pin) {
+ if (__builtin_constant_p(pin) && pin < digitalPinCount) {
+ return (*digitalPinMap[pin].pin >> digitalPinMap[pin].bit) & 1;
+ } else {
+ return badPinNumber();
+ }
+}
+static inline __attribute__((always_inline))
+ void fastDigitalWrite(uint8_t pin, uint8_t value) {
+ if (__builtin_constant_p(pin) && pin < digitalPinCount) {
+ if (value) {
+ *digitalPinMap[pin].port |= 1 << digitalPinMap[pin].bit;
+ } else {
+ *digitalPinMap[pin].port &= ~(1 << digitalPinMap[pin].bit);
+ }
+ } else {
+ badPinNumber();
+ }
+}
+*/
+#endif // Sd2PinMap_h
diff --git a/Libmaple/libmaple/libraries/mapleSDfat/SdFat.h b/Libmaple/libmaple/libraries/mapleSDfat/SdFat.h
index 6dcf98ea..e1b40118 100644
--- a/Libmaple/libmaple/libraries/mapleSDfat/SdFat.h
+++ b/Libmaple/libmaple/libraries/mapleSDfat/SdFat.h
@@ -1,548 +1,548 @@
-/* Arduino SdFat Library
- * Copyright (C) 2009 by William Greiman
- *
- * This file is part of the Arduino SdFat Library
- *
- * This Library is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This Library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with the Arduino SdFat Library. If not, see
- * .
- */
-#ifndef SdFat_h
-#define SdFat_h
-/**
- * \file
- * SdFile and SdVolume classes
- */
-//#include
-#include
-#include "Sd2Card.h"
-#include "FatStructs.h"
-#include "Print.h"
-//------------------------------------------------------------------------------
-/**
- * Allow use of deprecated functions if non-zero
- */
-#define ALLOW_DEPRECATED_FUNCTIONS 1
-//------------------------------------------------------------------------------
-// forward declaration since SdVolume is used in SdFile
-class SdVolume;
-//==============================================================================
-// SdFile class
-
-// flags for ls()
-/** ls() flag to print modify date */
-uint8_t const LS_DATE = 1;
-/** ls() flag to print file size */
-uint8_t const LS_SIZE = 2;
-/** ls() flag for recursive list of subdirectories */
-uint8_t const LS_R = 4;
-
-// use the gnu style oflag in open()
-/** open() oflag for reading */
-uint8_t const O_READ = 0X01;
-/** open() oflag - same as O_READ */
-uint8_t const O_RDONLY = O_READ;
-/** open() oflag for write */
-uint8_t const O_WRITE = 0X02;
-/** open() oflag - same as O_WRITE */
-uint8_t const O_WRONLY = O_WRITE;
-/** open() oflag for reading and writing */
-uint8_t const O_RDWR = (O_READ | O_WRITE);
-/** open() oflag mask for access modes */
-uint8_t const O_ACCMODE = (O_READ | O_WRITE);
-/** The file offset shall be set to the end of the file prior to each write. */
-uint8_t const O_APPEND = 0X04;
-/** synchronous writes - call sync() after each write */
-uint8_t const O_SYNC = 0X08;
-/** create the file if nonexistent */
-uint8_t const O_CREAT = 0X10;
-/** If O_CREAT and O_EXCL are set, open() shall fail if the file exists */
-uint8_t const O_EXCL = 0X20;
-/** truncate the file to zero length */
-uint8_t const O_TRUNC = 0X40;
-
-// flags for timestamp
-/** set the file's last access date */
-uint8_t const T_ACCESS = 1;
-/** set the file's creation date and time */
-uint8_t const T_CREATE = 2;
-/** Set the file's write date and time */
-uint8_t const T_WRITE = 4;
-// values for type_
-/** This SdFile has not been opened. */
-uint8_t const FAT_FILE_TYPE_CLOSED = 0;
-/** SdFile for a file */
-uint8_t const FAT_FILE_TYPE_NORMAL = 1;
-/** SdFile for a FAT16 root directory */
-uint8_t const FAT_FILE_TYPE_ROOT16 = 2;
-/** SdFile for a FAT32 root directory */
-uint8_t const FAT_FILE_TYPE_ROOT32 = 3;
-/** SdFile for a subdirectory */
-uint8_t const FAT_FILE_TYPE_SUBDIR = 4;
-/** Test value for directory type */
-uint8_t const FAT_FILE_TYPE_MIN_DIR = FAT_FILE_TYPE_ROOT16;
-
-/** date field for FAT directory entry */
-static inline uint16_t FAT_DATE(uint16_t year, uint8_t month, uint8_t day) {
- return (year - 1980) << 9 | month << 5 | day;
-}
-/** year part of FAT directory date field */
-static inline uint16_t FAT_YEAR(uint16_t fatDate) {
- return 1980 + (fatDate >> 9);
-}
-/** month part of FAT directory date field */
-static inline uint8_t FAT_MONTH(uint16_t fatDate) {
- return (fatDate >> 5) & 0XF;
-}
-/** day part of FAT directory date field */
-static inline uint8_t FAT_DAY(uint16_t fatDate) {
- return fatDate & 0X1F;
-}
-/** time field for FAT directory entry */
-static inline uint16_t FAT_TIME(uint8_t hour, uint8_t minute, uint8_t second) {
- return hour << 11 | minute << 5 | second >> 1;
-}
-/** hour part of FAT directory time field */
-static inline uint8_t FAT_HOUR(uint16_t fatTime) {
- return fatTime >> 11;
-}
-/** minute part of FAT directory time field */
-static inline uint8_t FAT_MINUTE(uint16_t fatTime) {
- return(fatTime >> 5) & 0X3F;
-}
-/** second part of FAT directory time field */
-static inline uint8_t FAT_SECOND(uint16_t fatTime) {
- return 2*(fatTime & 0X1F);
-}
-/** Default date for file timestamps is 1 Jan 2000 */
-uint16_t const FAT_DEFAULT_DATE = ((2000 - 1980) << 9) | (1 << 5) | 1;
-/** Default time for file timestamp is 1 am */
-uint16_t const FAT_DEFAULT_TIME = (1 << 11);
-//------------------------------------------------------------------------------
-/**
- * \class SdFile
- * \brief Access FAT16 and FAT32 files on SD and SDHC cards.
- */
-class SdFile : public Print {
- public:
- /** Create an instance of SdFile. */
- SdFile(void) : type_(FAT_FILE_TYPE_CLOSED) {}
- /**
- * writeError is set to true if an error occurs during a write().
- * Set writeError to false before calling print() and/or write() and check
- * for true after calls to print() and/or write().
- */
- bool writeError;
- /**
- * Cancel unbuffered reads for this file.
- * See setUnbufferedRead()
- */
- void clearUnbufferedRead(void) {
- flags_ &= ~F_FILE_UNBUFFERED_READ;
- }
- uint8_t close(void);
- uint8_t contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock);
- uint8_t createContiguous(SdFile* dirFile,
- const char* fileName, uint32_t size);
- /** \return The current cluster number for a file or directory. */
- uint32_t curCluster(void) const {return curCluster_;}
- /** \return The current position for a file or directory. */
- uint32_t curPosition(void) const {return curPosition_;}
- /**
- * Set the date/time callback function
- *
- * \param[in] dateTime The user's call back function. The callback
- * function is of the form:
- *
- * \code
- * void dateTime(uint16_t* date, uint16_t* time) {
- * uint16_t year;
- * uint8_t month, day, hour, minute, second;
- *
- * // User gets date and time from GPS or real-time clock here
- *
- * // return date using FAT_DATE macro to format fields
- * *date = FAT_DATE(year, month, day);
- *
- * // return time using FAT_TIME macro to format fields
- * *time = FAT_TIME(hour, minute, second);
- * }
- * \endcode
- *
- * Sets the function that is called when a file is created or when
- * a file's directory entry is modified by sync(). All timestamps,
- * access, creation, and modify, are set when a file is created.
- * sync() maintains the last access date and last modify date/time.
- *
- * See the timestamp() function.
- */
- static void dateTimeCallback(
- void (*dateTime)(uint16_t* date, uint16_t* time)) {
- dateTime_ = dateTime;
- }
- /**
- * Cancel the date/time callback function.
- */
- static void dateTimeCallbackCancel(void) {
- // use explicit zero since NULL is not defined for Sanguino
- dateTime_ = 0;
- }
- /** \return Address of the block that contains this file's directory. */
- uint32_t dirBlock(void) const {return dirBlock_;}
- uint8_t dirEntry(dir_t* dir);
- /** \return Index of this file's directory in the block dirBlock. */
- uint8_t dirIndex(void) const {return dirIndex_;}
- static void dirName(const dir_t& dir, char* name);
- /** \return The total number of bytes in a file or directory. */
- uint32_t fileSize(void) const {return fileSize_;}
- /** \return The first cluster number for a file or directory. */
- uint32_t firstCluster(void) const {return firstCluster_;}
- /** \return True if this is a SdFile for a directory else false. */
- uint8_t isDir(void) const {return type_ >= FAT_FILE_TYPE_MIN_DIR;}
- /** \return True if this is a SdFile for a file else false. */
- uint8_t isFile(void) const {return type_ == FAT_FILE_TYPE_NORMAL;}
- /** \return True if this is a SdFile for an open file/directory else false. */
- uint8_t isOpen(void) const {return type_ != FAT_FILE_TYPE_CLOSED;}
- /** \return True if this is a SdFile for a subdirectory else false. */
- uint8_t isSubDir(void) const {return type_ == FAT_FILE_TYPE_SUBDIR;}
- /** \return True if this is a SdFile for the root directory. */
- uint8_t isRoot(void) const {
- return type_ == FAT_FILE_TYPE_ROOT16 || type_ == FAT_FILE_TYPE_ROOT32;
- }
- void ls(uint8_t flags = 0, uint8_t indent = 0);
- uint8_t makeDir(SdFile* dir, const char* dirName);
- uint8_t open(SdFile* dirFile, uint16_t index, uint8_t oflag);
- uint8_t open(SdFile* dirFile, const char* fileName, uint8_t oflag);
-
- uint8_t openRoot(SdVolume* vol);
- static void printDirName(const dir_t& dir, uint8_t width);
- static void printFatDate(uint16_t fatDate);
- static void printFatTime(uint16_t fatTime);
- static void printTwoDigits(uint8_t v);
- /**
- * Read the next byte from a file.
- *
- * \return For success read returns the next byte in the file as an int.
- * If an error occurs or end of file is reached -1 is returned.
- */
- int16_t read(void) {
- uint8_t b;
- return read(&b, 1) == 1 ? b : -1;
- }
- int16_t read(void* buf, uint16_t nbyte);
- int8_t readDir(dir_t* dir);
- static uint8_t remove(SdFile* dirFile, const char* fileName);
- uint8_t remove(void);
- /** Set the file's current position to zero. */
- void rewind(void) {
- curPosition_ = curCluster_ = 0;
- }
- uint8_t rmDir(void);
- uint8_t rmRfStar(void);
- /** Set the files position to current position + \a pos. See seekSet(). */
- uint8_t seekCur(uint32_t pos) {
- return seekSet(curPosition_ + pos);
- }
- /**
- * Set the files current position to end of file. Useful to position
- * a file for append. See seekSet().
- */
- uint8_t seekEnd(void) {return seekSet(fileSize_);}
- uint8_t seekSet(uint32_t pos);
- /**
- * Use unbuffered reads to access this file. Used with Wave
- * Shield ISR. Used with Sd2Card::partialBlockRead() in WaveRP.
- *
- * Not recommended for normal applications.
- */
- void setUnbufferedRead(void) {
- if (isFile()) flags_ |= F_FILE_UNBUFFERED_READ;
- }
- uint8_t timestamp(uint8_t flag, uint16_t year, uint8_t month, uint8_t day,
- uint8_t hour, uint8_t minute, uint8_t second);
- uint8_t sync(void);
- /** Type of this SdFile. You should use isFile() or isDir() instead of type()
- * if possible.
- *
- * \return The file or directory type.
- */
- uint8_t type(void) const {return type_;}
- uint8_t truncate(uint32_t size);
- /** \return Unbuffered read flag. */
- uint8_t unbufferedRead(void) const {
- return flags_ & F_FILE_UNBUFFERED_READ;
- }
- /** \return SdVolume that contains this file. */
- SdVolume* volume(void) const {return vol_;}
- void write(uint8_t b);
- int16_t write(const void* buf, uint16_t nbyte);
- void write(const char* str);
-// void write_P(PGM_P str);
-// void writeln_P(PGM_P str);
-//------------------------------------------------------------------------------
-#if ALLOW_DEPRECATED_FUNCTIONS
-// Deprecated functions - suppress cpplint warnings with NOLINT comment
- /** \deprecated Use:
- * uint8_t SdFile::contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock);
- */
- uint8_t contiguousRange(uint32_t& bgnBlock, uint32_t& endBlock) { // NOLINT
- return contiguousRange(&bgnBlock, &endBlock);
- }
- /** \deprecated Use:
- * uint8_t SdFile::createContiguous(SdFile* dirFile,
- * const char* fileName, uint32_t size)
- */
- uint8_t createContiguous(SdFile& dirFile, // NOLINT
- const char* fileName, uint32_t size) {
- return createContiguous(&dirFile, fileName, size);
- }
-
- /**
- * \deprecated Use:
- * static void SdFile::dateTimeCallback(
- * void (*dateTime)(uint16_t* date, uint16_t* time));
- */
- static void dateTimeCallback(
- void (*dateTime)(uint16_t& date, uint16_t& time)) { // NOLINT
- oldDateTime_ = dateTime;
- dateTime_ = dateTime ? oldToNew : 0;
- }
- /** \deprecated Use: uint8_t SdFile::dirEntry(dir_t* dir); */
- uint8_t dirEntry(dir_t& dir) {return dirEntry(&dir);} // NOLINT
- /** \deprecated Use:
- * uint8_t SdFile::makeDir(SdFile* dir, const char* dirName);
- */
- uint8_t makeDir(SdFile& dir, const char* dirName) { // NOLINT
- return makeDir(&dir, dirName);
- }
- /** \deprecated Use:
- * uint8_t SdFile::open(SdFile* dirFile, const char* fileName, uint8_t oflag);
- */
- uint8_t open(SdFile& dirFile, // NOLINT
- const char* fileName, uint8_t oflag) {
- return open(&dirFile, fileName, oflag);
- }
- /** \deprecated Do not use in new apps */
- uint8_t open(SdFile& dirFile, const char* fileName) { // NOLINT
- return open(dirFile, fileName, O_RDWR);
- }
- /** \deprecated Use:
- * uint8_t SdFile::open(SdFile* dirFile, uint16_t index, uint8_t oflag);
- */
- uint8_t open(SdFile& dirFile, uint16_t index, uint8_t oflag) { // NOLINT
- return open(&dirFile, index, oflag);
- }
- /** \deprecated Use: uint8_t SdFile::openRoot(SdVolume* vol); */
- uint8_t openRoot(SdVolume& vol) {return openRoot(&vol);} // NOLINT
-
- /** \deprecated Use: int8_t SdFile::readDir(dir_t* dir); */
- int8_t readDir(dir_t& dir) {return readDir(&dir);} // NOLINT
- /** \deprecated Use:
- * static uint8_t SdFile::remove(SdFile* dirFile, const char* fileName);
- */
- static uint8_t remove(SdFile& dirFile, const char* fileName) { // NOLINT
- return remove(&dirFile, fileName);
- }
-//------------------------------------------------------------------------------
-// rest are private
- private:
- static void (*oldDateTime_)(uint16_t& date, uint16_t& time); // NOLINT
- static void oldToNew(uint16_t* date, uint16_t* time) {
- uint16_t d;
- uint16_t t;
- oldDateTime_(d, t);
- *date = d;
- *time = t;
- }
-#endif // ALLOW_DEPRECATED_FUNCTIONS
- private:
- // bits defined in flags_
- // should be 0XF
- static uint8_t const F_OFLAG = (O_ACCMODE | O_APPEND | O_SYNC);
- // available bits
- static uint8_t const F_UNUSED = 0X30;
- // use unbuffered SD read
- static uint8_t const F_FILE_UNBUFFERED_READ = 0X40;
- // sync of directory entry required
- static uint8_t const F_FILE_DIR_DIRTY = 0X80;
-
-// make sure F_OFLAG is ok
-//#if ((F_UNUSED | F_FILE_UNBUFFERED_READ | F_FILE_DIR_DIRTY) & F_OFLAG)
-//#error flags_ bits conflict
-//#endif // flags_ bits
-
- // private data
- uint8_t flags_; // See above for definition of flags_ bits
- uint8_t type_; // type of file see above for values
- uint32_t curCluster_; // cluster for current file position
- uint32_t curPosition_; // current file position in bytes from beginning
- uint32_t dirBlock_; // SD block that contains directory entry for file
- uint8_t dirIndex_; // index of entry in dirBlock 0 <= dirIndex_ <= 0XF
- uint32_t fileSize_; // file size in bytes
- uint32_t firstCluster_; // first cluster of file
- SdVolume* vol_; // volume where file is located
-
- // private functions
- uint8_t addCluster(void);
- uint8_t addDirCluster(void);
- dir_t* cacheDirEntry(uint8_t action);
- static void (*dateTime_)(uint16_t* date, uint16_t* time);
- static uint8_t make83Name(const char* str, uint8_t* name);
- uint8_t openCachedEntry(uint8_t cacheIndex, uint8_t oflags);
- dir_t* readDirCache(void);
-};
-//==============================================================================
-// SdVolume class
-/**
- * \brief Cache for an SD data block
- */
-union cache_t {
- /** Used to access cached file data blocks. */
- uint8_t data[512];
- /** Used to access cached FAT16 entries. */
- uint16_t fat16[256];
- /** Used to access cached FAT32 entries. */
- uint32_t fat32[128];
- /** Used to access cached directory entries. */
- dir_t dir[16];
- /** Used to access a cached MasterBoot Record. */
- mbr_t mbr;
- /** Used to access to a cached FAT boot sector. */
- fbs_t fbs;
-};
-//------------------------------------------------------------------------------
-/**
- * \class SdVolume
- * \brief Access FAT16 and FAT32 volumes on SD and SDHC cards.
- */
-class SdVolume {
- public:
- /** Create an instance of SdVolume */
- SdVolume(void) :allocSearchStart_(2), fatType_(0) {}
- /** Clear the cache and returns a pointer to the cache. Used by the WaveRP
- * recorder to do raw write to the SD card. Not for normal apps.
- */
- static uint8_t* cacheClear(void) {
- cacheFlush();
- cacheBlockNumber_ = 0XFFFFFFFF;
- return cacheBuffer_.data;
- }
- /**
- * Initialize a FAT volume. Try partition one first then try super
- * floppy format.
- *
- * \param[in] dev The Sd2Card where the volume is located.
- *
- * \return The value one, true, is returned for success and
- * the value zero, false, is returned for failure. Reasons for
- * failure include not finding a valid partition, not finding a valid
- * FAT file system or an I/O error.
- */
- uint8_t init(Sd2Card* dev) { return init(dev, 1) ? true : init(dev, 0);}
- uint8_t init(Sd2Card* dev, uint8_t part);
-
- // inline functions that return volume info
- /** \return The volume's cluster size in blocks. */
- uint8_t blocksPerCluster(void) const {return blocksPerCluster_;}
- /** \return The number of blocks in one FAT. */
- uint32_t blocksPerFat(void) const {return blocksPerFat_;}
- /** \return The total number of clusters in the volume. */
- uint32_t clusterCount(void) const {return clusterCount_;}
- /** \return The shift count required to multiply by blocksPerCluster. */
- uint8_t clusterSizeShift(void) const {return clusterSizeShift_;}
- /** \return The logical block number for the start of file data. */
- uint32_t dataStartBlock(void) const {return dataStartBlock_;}
- /** \return The number of FAT structures on the volume. */
- uint8_t fatCount(void) const { return fatCount_;}
- /** \return The logical block number for the start of the first FAT. */
- uint32_t fatStartBlock(void) const {return fatStartBlock_;}
- /** \return The FAT type of the volume. Values are 12, 16 or 32. */
- uint8_t fatType(void) const {return fatType_;}
- /** \return The number of entries in the root directory for FAT16 volumes. */
- uint32_t rootDirEntryCount(void) const {return rootDirEntryCount_;}
- /** \return The logical block number for the start of the root directory
- on FAT16 volumes or the first cluster number on FAT32 volumes. */
- uint32_t rootDirStart(void) const {return rootDirStart_;}
- /** return a pointer to the Sd2Card object for this volume */
- static Sd2Card* sdCard(void) {return sdCard_;}
-//------------------------------------------------------------------------------
-#if ALLOW_DEPRECATED_FUNCTIONS
- // Deprecated functions - suppress cpplint warnings with NOLINT comment
- /** \deprecated Use: uint8_t SdVolume::init(Sd2Card* dev); */
- uint8_t init(Sd2Card& dev) {return init(&dev);} // NOLINT
-
- /** \deprecated Use: uint8_t SdVolume::init(Sd2Card* dev, uint8_t vol); */
- uint8_t init(Sd2Card& dev, uint8_t part) { // NOLINT
- return init(&dev, part);
- }
-#endif // ALLOW_DEPRECATED_FUNCTIONS
-//------------------------------------------------------------------------------
- private:
- // Allow SdFile access to SdVolume private data.
- friend class SdFile;
-
- // value for action argument in cacheRawBlock to indicate read from cache
- static uint8_t const CACHE_FOR_READ = 0;
- // value for action argument in cacheRawBlock to indicate cache dirty
- static uint8_t const CACHE_FOR_WRITE = 1;
-
- static cache_t cacheBuffer_; // 512 byte cache for device blocks
- static uint32_t cacheBlockNumber_; // Logical number of block in the cache
- static Sd2Card* sdCard_; // Sd2Card object for cache
- static uint8_t cacheDirty_; // cacheFlush() will write block if true
- static uint32_t cacheMirrorBlock_; // block number for mirror FAT
-//
- uint32_t allocSearchStart_; // start cluster for alloc search
- uint8_t blocksPerCluster_; // cluster size in blocks
- uint32_t blocksPerFat_; // FAT size in blocks
- uint32_t clusterCount_; // clusters in one FAT
- uint8_t clusterSizeShift_; // shift to convert cluster count to block count
- uint32_t dataStartBlock_; // first data block number
- uint8_t fatCount_; // number of FATs on volume
- uint32_t fatStartBlock_; // start block for first FAT
- uint8_t fatType_; // volume type (12, 16, OR 32)
- uint16_t rootDirEntryCount_; // number of entries in FAT16 root dir
- uint32_t rootDirStart_; // root start block for FAT16, cluster for FAT32
- //----------------------------------------------------------------------------
- uint8_t allocContiguous(uint32_t count, uint32_t* curCluster);
- uint8_t blockOfCluster(uint32_t position) const {
- return (position >> 9) & (blocksPerCluster_ - 1);}
- uint32_t clusterStartBlock(uint32_t cluster) const {
- return dataStartBlock_ + ((cluster - 2) << clusterSizeShift_);}
- uint32_t blockNumber(uint32_t cluster, uint32_t position) const {
- return clusterStartBlock(cluster) + blockOfCluster(position);}
- static uint8_t cacheFlush(void);
- static uint8_t cacheRawBlock(uint32_t blockNumber, uint8_t action);
- static void cacheSetDirty(void) {cacheDirty_ |= CACHE_FOR_WRITE;}
- static uint8_t cacheZeroBlock(uint32_t blockNumber);
- uint8_t chainSize(uint32_t beginCluster, uint32_t* size) const;
- uint8_t fatGet(uint32_t cluster, uint32_t* value) const;
- uint8_t fatPut(uint32_t cluster, uint32_t value);
- uint8_t fatPutEOC(uint32_t cluster) {
- return fatPut(cluster, 0x0FFFFFFF);
- }
- uint8_t freeChain(uint32_t cluster);
- uint8_t isEOC(uint32_t cluster) const {
- return cluster >= (fatType_ == 16 ? FAT16EOC_MIN : FAT32EOC_MIN);
- }
- uint8_t readBlock(uint32_t block, uint8_t* dst) {
- return sdCard_->readBlock(block, dst);}
- uint8_t readData(uint32_t block, uint16_t offset,
- uint16_t count, uint8_t* dst) {
- return sdCard_->readData(block, offset, count, dst);
- }
- uint8_t writeBlock(uint32_t block, const uint8_t* dst) {
- return sdCard_->writeBlock(block, dst);
- }
-};
-#endif // SdFat_h
+/* Arduino SdFat Library
+ * Copyright (C) 2009 by William Greiman
+ *
+ * This file is part of the Arduino SdFat Library
+ *
+ * This Library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Arduino SdFat Library. If not, see
+ * .
+ */
+#ifndef SdFat_h
+#define SdFat_h
+/**
+ * \file
+ * SdFile and SdVolume classes
+ */
+//#include
+#include
+#include "Sd2Card.h"
+#include "FatStructs.h"
+#include "Print.h"
+//------------------------------------------------------------------------------
+/**
+ * Allow use of deprecated functions if non-zero
+ */
+#define ALLOW_DEPRECATED_FUNCTIONS 1
+//------------------------------------------------------------------------------
+// forward declaration since SdVolume is used in SdFile
+class SdVolume;
+//==============================================================================
+// SdFile class
+
+// flags for ls()
+/** ls() flag to print modify date */
+uint8_t const LS_DATE = 1;
+/** ls() flag to print file size */
+uint8_t const LS_SIZE = 2;
+/** ls() flag for recursive list of subdirectories */
+uint8_t const LS_R = 4;
+
+// use the gnu style oflag in open()
+/** open() oflag for reading */
+uint8_t const O_READ = 0X01;
+/** open() oflag - same as O_READ */
+uint8_t const O_RDONLY = O_READ;
+/** open() oflag for write */
+uint8_t const O_WRITE = 0X02;
+/** open() oflag - same as O_WRITE */
+uint8_t const O_WRONLY = O_WRITE;
+/** open() oflag for reading and writing */
+uint8_t const O_RDWR = (O_READ | O_WRITE);
+/** open() oflag mask for access modes */
+uint8_t const O_ACCMODE = (O_READ | O_WRITE);
+/** The file offset shall be set to the end of the file prior to each write. */
+uint8_t const O_APPEND = 0X04;
+/** synchronous writes - call sync() after each write */
+uint8_t const O_SYNC = 0X08;
+/** create the file if nonexistent */
+uint8_t const O_CREAT = 0X10;
+/** If O_CREAT and O_EXCL are set, open() shall fail if the file exists */
+uint8_t const O_EXCL = 0X20;
+/** truncate the file to zero length */
+uint8_t const O_TRUNC = 0X40;
+
+// flags for timestamp
+/** set the file's last access date */
+uint8_t const T_ACCESS = 1;
+/** set the file's creation date and time */
+uint8_t const T_CREATE = 2;
+/** Set the file's write date and time */
+uint8_t const T_WRITE = 4;
+// values for type_
+/** This SdFile has not been opened. */
+uint8_t const FAT_FILE_TYPE_CLOSED = 0;
+/** SdFile for a file */
+uint8_t const FAT_FILE_TYPE_NORMAL = 1;
+/** SdFile for a FAT16 root directory */
+uint8_t const FAT_FILE_TYPE_ROOT16 = 2;
+/** SdFile for a FAT32 root directory */
+uint8_t const FAT_FILE_TYPE_ROOT32 = 3;
+/** SdFile for a subdirectory */
+uint8_t const FAT_FILE_TYPE_SUBDIR = 4;
+/** Test value for directory type */
+uint8_t const FAT_FILE_TYPE_MIN_DIR = FAT_FILE_TYPE_ROOT16;
+
+/** date field for FAT directory entry */
+static inline uint16_t FAT_DATE(uint16_t year, uint8_t month, uint8_t day) {
+ return (year - 1980) << 9 | month << 5 | day;
+}
+/** year part of FAT directory date field */
+static inline uint16_t FAT_YEAR(uint16_t fatDate) {
+ return 1980 + (fatDate >> 9);
+}
+/** month part of FAT directory date field */
+static inline uint8_t FAT_MONTH(uint16_t fatDate) {
+ return (fatDate >> 5) & 0XF;
+}
+/** day part of FAT directory date field */
+static inline uint8_t FAT_DAY(uint16_t fatDate) {
+ return fatDate & 0X1F;
+}
+/** time field for FAT directory entry */
+static inline uint16_t FAT_TIME(uint8_t hour, uint8_t minute, uint8_t second) {
+ return hour << 11 | minute << 5 | second >> 1;
+}
+/** hour part of FAT directory time field */
+static inline uint8_t FAT_HOUR(uint16_t fatTime) {
+ return fatTime >> 11;
+}
+/** minute part of FAT directory time field */
+static inline uint8_t FAT_MINUTE(uint16_t fatTime) {
+ return(fatTime >> 5) & 0X3F;
+}
+/** second part of FAT directory time field */
+static inline uint8_t FAT_SECOND(uint16_t fatTime) {
+ return 2*(fatTime & 0X1F);
+}
+/** Default date for file timestamps is 1 Jan 2000 */
+uint16_t const FAT_DEFAULT_DATE = ((2000 - 1980) << 9) | (1 << 5) | 1;
+/** Default time for file timestamp is 1 am */
+uint16_t const FAT_DEFAULT_TIME = (1 << 11);
+//------------------------------------------------------------------------------
+/**
+ * \class SdFile
+ * \brief Access FAT16 and FAT32 files on SD and SDHC cards.
+ */
+class SdFile : public Print {
+ public:
+ /** Create an instance of SdFile. */
+ SdFile(void) : type_(FAT_FILE_TYPE_CLOSED) {}
+ /**
+ * writeError is set to true if an error occurs during a write().
+ * Set writeError to false before calling print() and/or write() and check
+ * for true after calls to print() and/or write().
+ */
+ bool writeError;
+ /**
+ * Cancel unbuffered reads for this file.
+ * See setUnbufferedRead()
+ */
+ void clearUnbufferedRead(void) {
+ flags_ &= ~F_FILE_UNBUFFERED_READ;
+ }
+ uint8_t close(void);
+ uint8_t contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock);
+ uint8_t createContiguous(SdFile* dirFile,
+ const char* fileName, uint32_t size);
+ /** \return The current cluster number for a file or directory. */
+ uint32_t curCluster(void) const {return curCluster_;}
+ /** \return The current position for a file or directory. */
+ uint32_t curPosition(void) const {return curPosition_;}
+ /**
+ * Set the date/time callback function
+ *
+ * \param[in] dateTime The user's call back function. The callback
+ * function is of the form:
+ *
+ * \code
+ * void dateTime(uint16_t* date, uint16_t* time) {
+ * uint16_t year;
+ * uint8_t month, day, hour, minute, second;
+ *
+ * // User gets date and time from GPS or real-time clock here
+ *
+ * // return date using FAT_DATE macro to format fields
+ * *date = FAT_DATE(year, month, day);
+ *
+ * // return time using FAT_TIME macro to format fields
+ * *time = FAT_TIME(hour, minute, second);
+ * }
+ * \endcode
+ *
+ * Sets the function that is called when a file is created or when
+ * a file's directory entry is modified by sync(). All timestamps,
+ * access, creation, and modify, are set when a file is created.
+ * sync() maintains the last access date and last modify date/time.
+ *
+ * See the timestamp() function.
+ */
+ static void dateTimeCallback(
+ void (*dateTime)(uint16_t* date, uint16_t* time)) {
+ dateTime_ = dateTime;
+ }
+ /**
+ * Cancel the date/time callback function.
+ */
+ static void dateTimeCallbackCancel(void) {
+ // use explicit zero since NULL is not defined for Sanguino
+ dateTime_ = 0;
+ }
+ /** \return Address of the block that contains this file's directory. */
+ uint32_t dirBlock(void) const {return dirBlock_;}
+ uint8_t dirEntry(dir_t* dir);
+ /** \return Index of this file's directory in the block dirBlock. */
+ uint8_t dirIndex(void) const {return dirIndex_;}
+ static void dirName(const dir_t& dir, char* name);
+ /** \return The total number of bytes in a file or directory. */
+ uint32_t fileSize(void) const {return fileSize_;}
+ /** \return The first cluster number for a file or directory. */
+ uint32_t firstCluster(void) const {return firstCluster_;}
+ /** \return True if this is a SdFile for a directory else false. */
+ uint8_t isDir(void) const {return type_ >= FAT_FILE_TYPE_MIN_DIR;}
+ /** \return True if this is a SdFile for a file else false. */
+ uint8_t isFile(void) const {return type_ == FAT_FILE_TYPE_NORMAL;}
+ /** \return True if this is a SdFile for an open file/directory else false. */
+ uint8_t isOpen(void) const {return type_ != FAT_FILE_TYPE_CLOSED;}
+ /** \return True if this is a SdFile for a subdirectory else false. */
+ uint8_t isSubDir(void) const {return type_ == FAT_FILE_TYPE_SUBDIR;}
+ /** \return True if this is a SdFile for the root directory. */
+ uint8_t isRoot(void) const {
+ return type_ == FAT_FILE_TYPE_ROOT16 || type_ == FAT_FILE_TYPE_ROOT32;
+ }
+ void ls(uint8_t flags = 0, uint8_t indent = 0);
+ uint8_t makeDir(SdFile* dir, const char* dirName);
+ uint8_t open(SdFile* dirFile, uint16_t index, uint8_t oflag);
+ uint8_t open(SdFile* dirFile, const char* fileName, uint8_t oflag);
+
+ uint8_t openRoot(SdVolume* vol);
+ static void printDirName(const dir_t& dir, uint8_t width);
+ static void printFatDate(uint16_t fatDate);
+ static void printFatTime(uint16_t fatTime);
+ static void printTwoDigits(uint8_t v);
+ /**
+ * Read the next byte from a file.
+ *
+ * \return For success read returns the next byte in the file as an int.
+ * If an error occurs or end of file is reached -1 is returned.
+ */
+ int16_t read(void) {
+ uint8_t b;
+ return read(&b, 1) == 1 ? b : -1;
+ }
+ int16_t read(void* buf, uint16_t nbyte);
+ int8_t readDir(dir_t* dir);
+ static uint8_t remove(SdFile* dirFile, const char* fileName);
+ uint8_t remove(void);
+ /** Set the file's current position to zero. */
+ void rewind(void) {
+ curPosition_ = curCluster_ = 0;
+ }
+ uint8_t rmDir(void);
+ uint8_t rmRfStar(void);
+ /** Set the files position to current position + \a pos. See seekSet(). */
+ uint8_t seekCur(uint32_t pos) {
+ return seekSet(curPosition_ + pos);
+ }
+ /**
+ * Set the files current position to end of file. Useful to position
+ * a file for append. See seekSet().
+ */
+ uint8_t seekEnd(void) {return seekSet(fileSize_);}
+ uint8_t seekSet(uint32_t pos);
+ /**
+ * Use unbuffered reads to access this file. Used with Wave
+ * Shield ISR. Used with Sd2Card::partialBlockRead() in WaveRP.
+ *
+ * Not recommended for normal applications.
+ */
+ void setUnbufferedRead(void) {
+ if (isFile()) flags_ |= F_FILE_UNBUFFERED_READ;
+ }
+ uint8_t timestamp(uint8_t flag, uint16_t year, uint8_t month, uint8_t day,
+ uint8_t hour, uint8_t minute, uint8_t second);
+ uint8_t sync(void);
+ /** Type of this SdFile. You should use isFile() or isDir() instead of type()
+ * if possible.
+ *
+ * \return The file or directory type.
+ */
+ uint8_t type(void) const {return type_;}
+ uint8_t truncate(uint32_t size);
+ /** \return Unbuffered read flag. */
+ uint8_t unbufferedRead(void) const {
+ return flags_ & F_FILE_UNBUFFERED_READ;
+ }
+ /** \return SdVolume that contains this file. */
+ SdVolume* volume(void) const {return vol_;}
+ void write(uint8_t b);
+ int16_t write(const void* buf, uint16_t nbyte);
+ void write(const char* str);
+// void write_P(PGM_P str);
+// void writeln_P(PGM_P str);
+//------------------------------------------------------------------------------
+#if ALLOW_DEPRECATED_FUNCTIONS
+// Deprecated functions - suppress cpplint warnings with NOLINT comment
+ /** \deprecated Use:
+ * uint8_t SdFile::contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock);
+ */
+ uint8_t contiguousRange(uint32_t& bgnBlock, uint32_t& endBlock) { // NOLINT
+ return contiguousRange(&bgnBlock, &endBlock);
+ }
+ /** \deprecated Use:
+ * uint8_t SdFile::createContiguous(SdFile* dirFile,
+ * const char* fileName, uint32_t size)
+ */
+ uint8_t createContiguous(SdFile& dirFile, // NOLINT
+ const char* fileName, uint32_t size) {
+ return createContiguous(&dirFile, fileName, size);
+ }
+
+ /**
+ * \deprecated Use:
+ * static void SdFile::dateTimeCallback(
+ * void (*dateTime)(uint16_t* date, uint16_t* time));
+ */
+ static void dateTimeCallback(
+ void (*dateTime)(uint16_t& date, uint16_t& time)) { // NOLINT
+ oldDateTime_ = dateTime;
+ dateTime_ = dateTime ? oldToNew : 0;
+ }
+ /** \deprecated Use: uint8_t SdFile::dirEntry(dir_t* dir); */
+ uint8_t dirEntry(dir_t& dir) {return dirEntry(&dir);} // NOLINT
+ /** \deprecated Use:
+ * uint8_t SdFile::makeDir(SdFile* dir, const char* dirName);
+ */
+ uint8_t makeDir(SdFile& dir, const char* dirName) { // NOLINT
+ return makeDir(&dir, dirName);
+ }
+ /** \deprecated Use:
+ * uint8_t SdFile::open(SdFile* dirFile, const char* fileName, uint8_t oflag);
+ */
+ uint8_t open(SdFile& dirFile, // NOLINT
+ const char* fileName, uint8_t oflag) {
+ return open(&dirFile, fileName, oflag);
+ }
+ /** \deprecated Do not use in new apps */
+ uint8_t open(SdFile& dirFile, const char* fileName) { // NOLINT
+ return open(dirFile, fileName, O_RDWR);
+ }
+ /** \deprecated Use:
+ * uint8_t SdFile::open(SdFile* dirFile, uint16_t index, uint8_t oflag);
+ */
+ uint8_t open(SdFile& dirFile, uint16_t index, uint8_t oflag) { // NOLINT
+ return open(&dirFile, index, oflag);
+ }
+ /** \deprecated Use: uint8_t SdFile::openRoot(SdVolume* vol); */
+ uint8_t openRoot(SdVolume& vol) {return openRoot(&vol);} // NOLINT
+
+ /** \deprecated Use: int8_t SdFile::readDir(dir_t* dir); */
+ int8_t readDir(dir_t& dir) {return readDir(&dir);} // NOLINT
+ /** \deprecated Use:
+ * static uint8_t SdFile::remove(SdFile* dirFile, const char* fileName);
+ */
+ static uint8_t remove(SdFile& dirFile, const char* fileName) { // NOLINT
+ return remove(&dirFile, fileName);
+ }
+//------------------------------------------------------------------------------
+// rest are private
+ private:
+ static void (*oldDateTime_)(uint16_t& date, uint16_t& time); // NOLINT
+ static void oldToNew(uint16_t* date, uint16_t* time) {
+ uint16_t d;
+ uint16_t t;
+ oldDateTime_(d, t);
+ *date = d;
+ *time = t;
+ }
+#endif // ALLOW_DEPRECATED_FUNCTIONS
+ private:
+ // bits defined in flags_
+ // should be 0XF
+ static uint8_t const F_OFLAG = (O_ACCMODE | O_APPEND | O_SYNC);
+ // available bits
+ static uint8_t const F_UNUSED = 0X30;
+ // use unbuffered SD read
+ static uint8_t const F_FILE_UNBUFFERED_READ = 0X40;
+ // sync of directory entry required
+ static uint8_t const F_FILE_DIR_DIRTY = 0X80;
+
+// make sure F_OFLAG is ok
+//#if ((F_UNUSED | F_FILE_UNBUFFERED_READ | F_FILE_DIR_DIRTY) & F_OFLAG)
+//#error flags_ bits conflict
+//#endif // flags_ bits
+
+ // private data
+ uint8_t flags_; // See above for definition of flags_ bits
+ uint8_t type_; // type of file see above for values
+ uint32_t curCluster_; // cluster for current file position
+ uint32_t curPosition_; // current file position in bytes from beginning
+ uint32_t dirBlock_; // SD block that contains directory entry for file
+ uint8_t dirIndex_; // index of entry in dirBlock 0 <= dirIndex_ <= 0XF
+ uint32_t fileSize_; // file size in bytes
+ uint32_t firstCluster_; // first cluster of file
+ SdVolume* vol_; // volume where file is located
+
+ // private functions
+ uint8_t addCluster(void);
+ uint8_t addDirCluster(void);
+ dir_t* cacheDirEntry(uint8_t action);
+ static void (*dateTime_)(uint16_t* date, uint16_t* time);
+ static uint8_t make83Name(const char* str, uint8_t* name);
+ uint8_t openCachedEntry(uint8_t cacheIndex, uint8_t oflags);
+ dir_t* readDirCache(void);
+};
+//==============================================================================
+// SdVolume class
+/**
+ * \brief Cache for an SD data block
+ */
+union cache_t {
+ /** Used to access cached file data blocks. */
+ uint8_t data[512];
+ /** Used to access cached FAT16 entries. */
+ uint16_t fat16[256];
+ /** Used to access cached FAT32 entries. */
+ uint32_t fat32[128];
+ /** Used to access cached directory entries. */
+ dir_t dir[16];
+ /** Used to access a cached MasterBoot Record. */
+ mbr_t mbr;
+ /** Used to access to a cached FAT boot sector. */
+ fbs_t fbs;
+};
+//------------------------------------------------------------------------------
+/**
+ * \class SdVolume
+ * \brief Access FAT16 and FAT32 volumes on SD and SDHC cards.
+ */
+class SdVolume {
+ public:
+ /** Create an instance of SdVolume */
+ SdVolume(void) :allocSearchStart_(2), fatType_(0) {}
+ /** Clear the cache and returns a pointer to the cache. Used by the WaveRP
+ * recorder to do raw write to the SD card. Not for normal apps.
+ */
+ static uint8_t* cacheClear(void) {
+ cacheFlush();
+ cacheBlockNumber_ = 0XFFFFFFFF;
+ return cacheBuffer_.data;
+ }
+ /**
+ * Initialize a FAT volume. Try partition one first then try super
+ * floppy format.
+ *
+ * \param[in] dev The Sd2Card where the volume is located.
+ *
+ * \return The value one, true, is returned for success and
+ * the value zero, false, is returned for failure. Reasons for
+ * failure include not finding a valid partition, not finding a valid
+ * FAT file system or an I/O error.
+ */
+ uint8_t init(Sd2Card* dev) { return init(dev, 1) ? true : init(dev, 0);}
+ uint8_t init(Sd2Card* dev, uint8_t part);
+
+ // inline functions that return volume info
+ /** \return The volume's cluster size in blocks. */
+ uint8_t blocksPerCluster(void) const {return blocksPerCluster_;}
+ /** \return The number of blocks in one FAT. */
+ uint32_t blocksPerFat(void) const {return blocksPerFat_;}
+ /** \return The total number of clusters in the volume. */
+ uint32_t clusterCount(void) const {return clusterCount_;}
+ /** \return The shift count required to multiply by blocksPerCluster. */
+ uint8_t clusterSizeShift(void) const {return clusterSizeShift_;}
+ /** \return The logical block number for the start of file data. */
+ uint32_t dataStartBlock(void) const {return dataStartBlock_;}
+ /** \return The number of FAT structures on the volume. */
+ uint8_t fatCount(void) const { return fatCount_;}
+ /** \return The logical block number for the start of the first FAT. */
+ uint32_t fatStartBlock(void) const {return fatStartBlock_;}
+ /** \return The FAT type of the volume. Values are 12, 16 or 32. */
+ uint8_t fatType(void) const {return fatType_;}
+ /** \return The number of entries in the root directory for FAT16 volumes. */
+ uint32_t rootDirEntryCount(void) const {return rootDirEntryCount_;}
+ /** \return The logical block number for the start of the root directory
+ on FAT16 volumes or the first cluster number on FAT32 volumes. */
+ uint32_t rootDirStart(void) const {return rootDirStart_;}
+ /** return a pointer to the Sd2Card object for this volume */
+ static Sd2Card* sdCard(void) {return sdCard_;}
+//------------------------------------------------------------------------------
+#if ALLOW_DEPRECATED_FUNCTIONS
+ // Deprecated functions - suppress cpplint warnings with NOLINT comment
+ /** \deprecated Use: uint8_t SdVolume::init(Sd2Card* dev); */
+ uint8_t init(Sd2Card& dev) {return init(&dev);} // NOLINT
+
+ /** \deprecated Use: uint8_t SdVolume::init(Sd2Card* dev, uint8_t vol); */
+ uint8_t init(Sd2Card& dev, uint8_t part) { // NOLINT
+ return init(&dev, part);
+ }
+#endif // ALLOW_DEPRECATED_FUNCTIONS
+//------------------------------------------------------------------------------
+ private:
+ // Allow SdFile access to SdVolume private data.
+ friend class SdFile;
+
+ // value for action argument in cacheRawBlock to indicate read from cache
+ static uint8_t const CACHE_FOR_READ = 0;
+ // value for action argument in cacheRawBlock to indicate cache dirty
+ static uint8_t const CACHE_FOR_WRITE = 1;
+
+ static cache_t cacheBuffer_; // 512 byte cache for device blocks
+ static uint32_t cacheBlockNumber_; // Logical number of block in the cache
+ static Sd2Card* sdCard_; // Sd2Card object for cache
+ static uint8_t cacheDirty_; // cacheFlush() will write block if true
+ static uint32_t cacheMirrorBlock_; // block number for mirror FAT
+//
+ uint32_t allocSearchStart_; // start cluster for alloc search
+ uint8_t blocksPerCluster_; // cluster size in blocks
+ uint32_t blocksPerFat_; // FAT size in blocks
+ uint32_t clusterCount_; // clusters in one FAT
+ uint8_t clusterSizeShift_; // shift to convert cluster count to block count
+ uint32_t dataStartBlock_; // first data block number
+ uint8_t fatCount_; // number of FATs on volume
+ uint32_t fatStartBlock_; // start block for first FAT
+ uint8_t fatType_; // volume type (12, 16, OR 32)
+ uint16_t rootDirEntryCount_; // number of entries in FAT16 root dir
+ uint32_t rootDirStart_; // root start block for FAT16, cluster for FAT32
+ //----------------------------------------------------------------------------
+ uint8_t allocContiguous(uint32_t count, uint32_t* curCluster);
+ uint8_t blockOfCluster(uint32_t position) const {
+ return (position >> 9) & (blocksPerCluster_ - 1);}
+ uint32_t clusterStartBlock(uint32_t cluster) const {
+ return dataStartBlock_ + ((cluster - 2) << clusterSizeShift_);}
+ uint32_t blockNumber(uint32_t cluster, uint32_t position) const {
+ return clusterStartBlock(cluster) + blockOfCluster(position);}
+ static uint8_t cacheFlush(void);
+ static uint8_t cacheRawBlock(uint32_t blockNumber, uint8_t action);
+ static void cacheSetDirty(void) {cacheDirty_ |= CACHE_FOR_WRITE;}
+ static uint8_t cacheZeroBlock(uint32_t blockNumber);
+ uint8_t chainSize(uint32_t beginCluster, uint32_t* size) const;
+ uint8_t fatGet(uint32_t cluster, uint32_t* value) const;
+ uint8_t fatPut(uint32_t cluster, uint32_t value);
+ uint8_t fatPutEOC(uint32_t cluster) {
+ return fatPut(cluster, 0x0FFFFFFF);
+ }
+ uint8_t freeChain(uint32_t cluster);
+ uint8_t isEOC(uint32_t cluster) const {
+ return cluster >= (fatType_ == 16 ? FAT16EOC_MIN : FAT32EOC_MIN);
+ }
+ uint8_t readBlock(uint32_t block, uint8_t* dst) {
+ return sdCard_->readBlock(block, dst);}
+ uint8_t readData(uint32_t block, uint16_t offset,
+ uint16_t count, uint8_t* dst) {
+ return sdCard_->readData(block, offset, count, dst);
+ }
+ uint8_t writeBlock(uint32_t block, const uint8_t* dst) {
+ return sdCard_->writeBlock(block, dst);
+ }
+};
+#endif // SdFat_h
diff --git a/Libmaple/libmaple/libraries/mapleSDfat/SdFatUtil.h b/Libmaple/libmaple/libraries/mapleSDfat/SdFatUtil.h
index cb2e7a0a..a4af739f 100644
--- a/Libmaple/libmaple/libraries/mapleSDfat/SdFatUtil.h
+++ b/Libmaple/libmaple/libraries/mapleSDfat/SdFatUtil.h
@@ -1,55 +1,55 @@
-/* Arduino SdFat Library
- * Copyright (C) 2008 by William Greiman
- *
- * This file is part of the Arduino SdFat Library
- *
- * This Library is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This Library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with the Arduino SdFat Library. If not, see
- * .
- */
-#ifndef SdFatUtil_h
-#define SdFatUtil_h
-/**
- * \file
- * Useful utility functions.
- */
-#include
-//#include
-/** Store and print a string in flash memory.*/
-#define PgmPrint(x) SerialPrint_P(PSTR(x))
-/** Store and print a string in flash memory followed by a CR/LF.*/
-#define PgmPrintln(x) SerialPrintln_P(PSTR(x))
-/** Defined so doxygen works for function definitions. */
-#define NOINLINE __attribute__((noinline))
-//------------------------------------------------------------------------------
-
-#if 0
-/** Return the number of bytes currently free in RAM. */
-static int FreeRam(void) {
- extern int __bss_end;
- extern int* __brkval;
- int free_memory;
- if (reinterpret_cast(__brkval) == 0) {
- // if no heap use from end of bss section
- free_memory = reinterpret_cast(&free_memory)
- - reinterpret_cast(&__bss_end);
- } else {
- // use from top of stack to heap
- free_memory = reinterpret_cast(&free_memory)
- - reinterpret_cast(__brkval);
- }
- return free_memory;
-}
-#endif
-
-#endif // #define SdFatUtil_h
+/* Arduino SdFat Library
+ * Copyright (C) 2008 by William Greiman
+ *
+ * This file is part of the Arduino SdFat Library
+ *
+ * This Library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with the Arduino SdFat Library. If not, see
+ * .
+ */
+#ifndef SdFatUtil_h
+#define SdFatUtil_h
+/**
+ * \file
+ * Useful utility functions.
+ */
+#include
+//#include
+/** Store and print a string in flash memory.*/
+#define PgmPrint(x) SerialPrint_P(PSTR(x))
+/** Store and print a string in flash memory followed by a CR/LF.*/
+#define PgmPrintln(x) SerialPrintln_P(PSTR(x))
+/** Defined so doxygen works for function definitions. */
+#define NOINLINE __attribute__((noinline))
+//------------------------------------------------------------------------------
+
+#if 0
+/** Return the number of bytes currently free in RAM. */
+static int FreeRam(void) {
+ extern int __bss_end;
+ extern int* __brkval;
+ int free_memory;
+ if (reinterpret_cast(__brkval) == 0) {
+ // if no heap use from end of bss section
+ free_memory = reinterpret_cast(&free_memory)
+ - reinterpret_cast(&__bss_end);
+ } else {
+ // use from top of stack to heap
+ free_memory = reinterpret_cast(&free_memory)
+ - reinterpret_cast(__brkval);
+ }
+ return free_memory;
+}
+#endif
+
+#endif // #define SdFatUtil_h
diff --git a/Libmaple/libmaple/libraries/mapleSDfat/SdFatWorks.h b/Libmaple/libmaple/libraries/mapleSDfat/SdFatWorks.h
index b865b0dc..b5424bb9 100644
--- a/Libmaple/libmaple/libraries/mapleSDfat/SdFatWorks.h
+++ b/Libmaple/libmaple/libraries/mapleSDfat/SdFatWorks.h
@@ -1,555 +1,555 @@
-/* Arduino SdFat Library
- * Copyright (C) 2009 by William Greiman
- *
- * This file is part of the Arduino SdFat Library
- *
- * This Library is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This Library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with the Arduino SdFat Library. If not, see
- * .
- */
-#ifndef SdFat_h
-#define SdFat_h
-/**
- * \file
- * SdFile and SdVolume classes
- */
-//#include
-#include
-#include "Sd2Card.h"
-#include "FatStructs.h"
-#include "Print.h"
-//------------------------------------------------------------------------------
-/**
- * Allow use of deprecated functions if non-zero
- */
-#define ALLOW_DEPRECATED_FUNCTIONS 1
-//------------------------------------------------------------------------------
-// forward declaration since SdVolume is used in SdFile
-class SdVolume;
-//==============================================================================
-// SdFile class
-
-// flags for ls()
-/** ls() flag to print modify date */
-uint8_t const LS_DATE = 1;
-/** ls() flag to print file size */
-uint8_t const LS_SIZE = 2;
-/** ls() flag for recursive list of subdirectories */
-uint8_t const LS_R = 4;
-
-// use the gnu style oflag in open()
-/** open() oflag for reading */
-uint8_t const O_READ = 0X01;
-/** open() oflag - same as O_READ */
-uint8_t const O_RDONLY = O_READ;
-/** open() oflag for write */
-uint8_t const O_WRITE = 0X02;
-/** open() oflag - same as O_WRITE */
-uint8_t const O_WRONLY = O_WRITE;
-/** open() oflag for reading and writing */
-uint8_t const O_RDWR = (O_READ | O_WRITE);
-/** open() oflag mask for access modes */
-uint8_t const O_ACCMODE = (O_READ | O_WRITE);
-/** The file offset shall be set to the end of the file prior to each write. */
-uint8_t const O_APPEND = 0X04;
-/** synchronous writes - call sync() after each write */
-uint8_t const O_SYNC = 0X08;
-/** create the file if nonexistent */
-uint8_t const O_CREAT = 0X10;
-/** If O_CREAT and O_EXCL are set, open() shall fail if the file exists */
-uint8_t const O_EXCL = 0X20;
-/** truncate the file to zero length */
-uint8_t const O_TRUNC = 0X40;
-
-// flags for timestamp
-/** set the file's last access date */
-uint8_t const T_ACCESS = 1;
-/** set the file's creation date and time */
-uint8_t const T_CREATE = 2;
-/** Set the file's write date and time */
-uint8_t const T_WRITE = 4;
-// values for type_
-/** This SdFile has not been opened. */
-uint8_t const FAT_FILE_TYPE_CLOSED = 0;
-/** SdFile for a file */
-uint8_t const FAT_FILE_TYPE_NORMAL = 1;
-/** SdFile for a FAT16 root directory */
-uint8_t const FAT_FILE_TYPE_ROOT16 = 2;
-/** SdFile for a FAT32 root directory */
-uint8_t const FAT_FILE_TYPE_ROOT32 = 3;
-/** SdFile for a subdirectory */
-uint8_t const FAT_FILE_TYPE_SUBDIR = 4;
-/** Test value for directory type */
-uint8_t const FAT_FILE_TYPE_MIN_DIR = FAT_FILE_TYPE_ROOT16;
-
-/** date field for FAT directory entry */
-static inline uint16_t FAT_DATE(uint16_t year, uint8_t month, uint8_t day) {
- return (year - 1980) << 9 | month << 5 | day;
-}
-/** year part of FAT directory date field */
-static inline uint16_t FAT_YEAR(uint16_t fatDate) {
- return 1980 + (fatDate >> 9);
-}
-/** month part of FAT directory date field */
-static inline uint8_t FAT_MONTH(uint16_t fatDate) {
- return (fatDate >> 5) & 0XF;
-}
-/** day part of FAT directory date field */
-static inline uint8_t FAT_DAY(uint16_t fatDate) {
- return fatDate & 0X1F;
-}
-/** time field for FAT directory entry */
-static inline uint16_t FAT_TIME(uint8_t hour, uint8_t minute, uint8_t second) {
- return hour << 11 | minute << 5 | second >> 1;
-}
-/** hour part of FAT directory time field */
-static inline uint8_t FAT_HOUR(uint16_t fatTime) {
- return fatTime >> 11;
-}
-/** minute part of FAT directory time field */
-static inline uint8_t FAT_MINUTE(uint16_t fatTime) {
- return(fatTime >> 5) & 0X3F;
-}
-/** second part of FAT directory time field */
-static inline uint8_t FAT_SECOND(uint16_t fatTime) {
- return 2*(fatTime & 0X1F);
-}
-/** Default date for file timestamps is 1 Jan 2000 */
-uint16_t const FAT_DEFAULT_DATE = ((2000 - 1980) << 9) | (1 << 5) | 1;
-/** Default time for file timestamp is 1 am */
-uint16_t const FAT_DEFAULT_TIME = (1 << 11);
-//------------------------------------------------------------------------------
-/**
- * \class SdFile
- * \brief Access FAT16 and FAT32 files on SD and SDHC cards.
- */
-class SdFile : public Print {
- public:
- /** Create an instance of SdFile. */
- SdFile(void) : type_(FAT_FILE_TYPE_CLOSED) {}
- /**
- * writeError is set to true if an error occurs during a write().
- * Set writeError to false before calling print() and/or write() and check
- * for true after calls to print() and/or write().
- */
- bool writeError;
- /**
- * Cancel unbuffered reads for this file.
- * See setUnbufferedRead()
- */
- void clearUnbufferedRead(void) {
- flags_ &= ~F_FILE_UNBUFFERED_READ;
- }
- uint8_t close(void);
- uint8_t contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock);
- uint8_t createContiguous(SdFile* dirFile,
- const char* fileName, uint32_t size);
- /** \return The current cluster number for a file or directory. */
- uint32_t curCluster(void) const {return curCluster_;}
- /** \return The current position for a file or directory. */
- uint32_t curPosition(void) const {return curPosition_;}
- /**
- * Set the date/time callback function
- *
- * \param[in] dateTime The user's call back function. The callback
- * function is of the form:
- *
- * \code
- * void dateTime(uint16_t* date, uint16_t* time) {
- * uint16_t year;
- * uint8_t month, day, hour, minute, second;
- *
- * // User gets date and time from GPS or real-time clock here
- *
- * // return date using FAT_DATE macro to format fields
- * *date = FAT_DATE(year, month, day);
- *
- * // return time using FAT_TIME macro to format fields
- * *time = FAT_TIME(hour, minute, second);
- * }
- * \endcode
- *
- * Sets the function that is called when a file is created or when
- * a file's directory entry is modified by sync(). All timestamps,
- * access, creation, and modify, are set when a file is created.
- * sync() maintains the last access date and last modify date/time.
- *
- * See the timestamp() function.
- */
- static void dateTimeCallback(
- void (*dateTime)(uint16_t* date, uint16_t* time)) {
- dateTime_ = dateTime;
- }
- /**
- * Cancel the date/time callback function.
- */
- static void dateTimeCallbackCancel(void) {
- // use explicit zero since NULL is not defined for Sanguino
- dateTime_ = 0;
- }
- /** \return Address of the block that contains this file's directory. */
- uint32_t dirBlock(void) const {return dirBlock_;}
- uint8_t dirEntry(dir_t* dir);
- /** \return Index of this file's directory in the block dirBlock. */
- uint8_t dirIndex(void) const {return dirIndex_;}
- static void dirName(const dir_t& dir, char* name);
- /** \return The total number of bytes in a file or directory. */
- uint32_t fileSize(void) const {return fileSize_;}
- /** \return The first cluster number for a file or directory. */
- uint32_t firstCluster(void) const {return firstCluster_;}
- /** \return True if this is a SdFile for a directory else false. */
- uint8_t isDir(void) const {return type_ >= FAT_FILE_TYPE_MIN_DIR;}
- /** \return True if this is a SdFile for a file else false. */
- uint8_t isFile(void) const {return type_ == FAT_FILE_TYPE_NORMAL;}
- /** \return True if this is a SdFile for an open file/directory else false. */
- uint8_t isOpen(void) const {return type_ != FAT_FILE_TYPE_CLOSED;}
- /** \return True if this is a SdFile for a subdirectory else false. */
- uint8_t isSubDir(void) const {return type_ == FAT_FILE_TYPE_SUBDIR;}
- /** \return True if this is a SdFile for the root directory. */
- uint8_t isRoot(void) const {
- return type_ == FAT_FILE_TYPE_ROOT16 || type_ == FAT_FILE_TYPE_ROOT32;
- }
- void ls(uint8_t flags = 0, uint8_t indent = 0);
- uint8_t makeDir(SdFile* dir, const char* dirName);
- uint8_t open(SdFile* dirFile, uint16_t index, uint8_t oflag);
- uint8_t open(SdFile* dirFile, const char* fileName, uint8_t oflag);
-
- uint8_t openRoot(SdVolume* vol);
- static void printDirName(const dir_t& dir, uint8_t width);
- static void printFatDate(uint16_t fatDate);
- static void printFatTime(uint16_t fatTime);
- static void printTwoDigits(uint8_t v);
- /**
- * Read the next byte from a file.
- *
- * \return For success read returns the next byte in the file as an int.
- * If an error occurs or end of file is reached -1 is returned.
- */
- int16_t read(void) {
- uint8_t b;
- return read(&b, 1) == 1 ? b : -1;
- }
- int16_t read(void* buf, uint16_t nbyte);
- int8_t readDir(dir_t* dir);
- static uint8_t remove(SdFile* dirFile, const char* fileName);
- uint8_t remove(void);
- /** Set the file's current position to zero. */
- void rewind(void) {
- curPosition_ = curCluster_ = 0;
- }
- uint8_t rmDir(void);
- uint8_t rmRfStar(void);
- /** Set the files position to current position + \a pos. See seekSet(). */
- uint8_t seekCur(uint32_t pos) {
- return seekSet(curPosition_ + pos);
- }
- /**
- * Set the files current position to end of file. Useful to position
- * a file for append. See seekSet().
- */
- uint8_t seekEnd(void) {return seekSet(fileSize_);}
- uint8_t seekSet(uint32_t pos);
- /**
- * Use unbuffered reads to access this file. Used with Wave
- * Shield ISR. Used with Sd2Card::partialBlockRead() in WaveRP.
- *
- * Not recommended for normal applications.
- */
- void setUnbufferedRead(void) {
- if (isFile()) flags_ |= F_FILE_UNBUFFERED_READ;
- }
- uint8_t timestamp(uint8_t flag, uint16_t year, uint8_t month, uint8_t day,
- uint8_t hour, uint8_t minute, uint8_t second);
- uint8_t sync(void);
- /** Type of this SdFile. You should use isFile() or isDir() instead of type()
- * if possible.
- *
- * \return The file or directory type.
- */
- uint8_t type(void) const {return type_;}
- uint8_t truncate(uint32_t size);
- /** \return Unbuffered read flag. */
- uint8_t unbufferedRead(void) const {
- return flags_ & F_FILE_UNBUFFERED_READ;
- }
- /** \return SdVolume that contains this file. */
- SdVolume* volume(void) const {return vol_;}
- void write(uint8_t b);
- int16_t write(const void* buf, uint16_t nbyte);
- void write(const char* str);
-// void write_P(PGM_P str);
-// void writeln_P(PGM_P str);
-//------------------------------------------------------------------------------
-#if ALLOW_DEPRECATED_FUNCTIONS
-// Deprecated functions - suppress cpplint warnings with NOLINT comment
- /** \deprecated Use:
- * uint8_t SdFile::contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock);
- */
- uint8_t contiguousRange(uint32_t& bgnBlock, uint32_t& endBlock) { // NOLINT
- return contiguousRange(&bgnBlock, &endBlock);
- }
- /** \deprecated Use:
- * uint8_t SdFile::createContiguous(SdFile* dirFile,
- * const char* fileName, uint32_t size)
- */
- uint8_t createContiguous(SdFile& dirFile, // NOLINT
- const char* fileName, uint32_t size) {
- return createContiguous(&dirFile, fileName, size);
- }
-
- /**
- * \deprecated Use:
- * static void SdFile::dateTimeCallback(
- * void (*dateTime)(uint16_t* date, uint16_t* time));
- */
- static void dateTimeCallback(
- void (*dateTime)(uint16_t& date, uint16_t& time)) { // NOLINT
- oldDateTime_ = dateTime;
- dateTime_ = dateTime ? oldToNew : 0;
- }
- /** \deprecated Use: uint8_t SdFile::dirEntry(dir_t* dir); */
- uint8_t dirEntry(dir_t& dir) {return dirEntry(&dir);} // NOLINT
- /** \deprecated Use:
- * uint8_t SdFile::makeDir(SdFile* dir, const char* dirName);
- */
- uint8_t makeDir(SdFile& dir, const char* dirName) { // NOLINT
- return makeDir(&dir, dirName);
- }
- /** \deprecated Use:
- * uint8_t SdFile::open(SdFile* dirFile, const char* fileName, uint8_t oflag);
- */
- uint8_t open(SdFile& dirFile, // NOLINT
- const char* fileName, uint8_t oflag) {
- return open(&dirFile, fileName, oflag);
- }
- /** \deprecated Do not use in new apps */
- uint8_t open(SdFile& dirFile, const char* fileName) { // NOLINT
- return open(dirFile, fileName, O_RDWR);
- }
- /** \deprecated Use:
- * uint8_t SdFile::open(SdFile* dirFile, uint16_t index, uint8_t oflag);
- */
- uint8_t open(SdFile& dirFile, uint16_t index, uint8_t oflag) { // NOLINT
- return open(&dirFile, index, oflag);
- }
- /** \deprecated Use: uint8_t SdFile::openRoot(SdVolume* vol); */
- uint8_t openRoot(SdVolume& vol) {return openRoot(&vol);} // NOLINT
-
- /** \deprecated Use: int8_t SdFile::readDir(dir_t* dir); */
- int8_t readDir(dir_t& dir) {return readDir(&dir);} // NOLINT
- /** \deprecated Use:
- * static uint8_t SdFile::remove(SdFile* dirFile, const char* fileName);
- */
- static uint8_t remove(SdFile& dirFile, const char* fileName) { // NOLINT
- return remove(&dirFile, fileName);
- }
-//------------------------------------------------------------------------------
-// rest are private
- private:
- static void (*oldDateTime_)(uint16_t& date, uint16_t& time); // NOLINT
- static void oldToNew(uint16_t* date, uint16_t* time) {
- uint16_t d;
- uint16_t t;
- oldDateTime_(d, t);
- *date = d;
- *time = t;
- }
-#endif // ALLOW_DEPRECATED_FUNCTIONS
- private:
- // bits defined in flags_
- // should be 0XF
- static uint8_t const F_OFLAG = (O_ACCMODE | O_APPEND | O_SYNC);
- // available bits
- static uint8_t const F_UNUSED = 0X30;
- // use unbuffered SD read
- static uint8_t const F_FILE_UNBUFFERED_READ = 0X40;
- // sync of directory entry required
- static uint8_t const F_FILE_DIR_DIRTY = 0X80;
-
-// make sure F_OFLAG is ok
-#if ((F_UNUSED | F_FILE_UNBUFFERED_READ | F_FILE_DIR_DIRTY) & F_OFLAG)
-#error flags_ bits conflict
-#endif // flags_ bits
-
- // private data
- uint8_t flags_; // See above for definition of flags_ bits
- uint8_t type_; // type of file see above for values
- uint32_t curCluster_; // cluster for current file position
- uint32_t curPosition_; // current file position in bytes from beginning
- uint32_t dirBlock_; // SD block that contains directory entry for file
- uint8_t dirIndex_; // index of entry in dirBlock 0 <= dirIndex_ <= 0XF
- uint32_t fileSize_; // file size in bytes
- uint32_t firstCluster_; // first cluster of file
- SdVolume* vol_; // volume where file is located
-
- // private functions
- uint8_t addCluster(void);
- uint8_t addDirCluster(void);
- dir_t* cacheDirEntry(uint8_t action);
- static void (*dateTime_)(uint16_t* date, uint16_t* time);
- static uint8_t make83Name(const char* str, uint8_t* name);
- uint8_t openCachedEntry(uint8_t cacheIndex, uint8_t oflags);
- dir_t* readDirCache(void);
-};
-//==============================================================================
-// SdVolume class
-/**
- * \brief Cache for an SD data block
- */
-union cache_t {
- /** Used to access cached file data blocks. */
- uint8_t data[512];
- /** Used to access cached FAT16 entries. */
- uint16_t fat16[256];
- /** Used to access cached FAT32 entries. */
- uint32_t fat32[128];
- /** Used to access cached directory entries. */
- dir_t dir[16];
- /** Used to access a cached MasterBoot Record. */
- mbr_t mbr;
- /** Used to access to a cached FAT boot sector. */
- fbs_t fbs;
-};
-//------------------------------------------------------------------------------
-/**
- * \class SdVolume
- * \brief Access FAT16 and FAT32 volumes on SD and SDHC cards.
- */
-class SdVolume {
- public:
- /** Create an instance of SdVolume */
- SdVolume(void) :allocSearchStart_(2), fatType_(0) {}
- /** Clear the cache and returns a pointer to the cache. Used by the WaveRP
- * recorder to do raw write to the SD card. Not for normal apps.
- */
- static uint8_t* cacheClear(void) {
- cacheFlush();
- cacheBlockNumber_ = 0XFFFFFFFF;
- return cacheBuffer_.data;
- }
- /**
- * Initialize a FAT volume. Try partition one first then try super
- * floppy format.
- *
- * \param[in] dev The Sd2Card where the volume is located.
- *
- * \return The value one, true, is returned for success and
- * the value zero, false, is returned for failure. Reasons for
- * failure include not finding a valid partition, not finding a valid
- * FAT file system or an I/O error.
- */
- uint8_t init(Sd2Card* dev) { return init(dev, 1) ? true : init(dev, 0);}
- uint8_t init(Sd2Card* dev, uint8_t part);
-
- // inline functions that return volume info
- /** \return The volume's cluster size in blocks. */
- uint8_t blocksPerCluster(void) const {return blocksPerCluster_;}
- /** \return The number of blocks in one FAT. */
- uint32_t blocksPerFat(void) const {return blocksPerFat_;}
- /** \return The total number of clusters in the volume. */
- uint32_t clusterCount(void) const {return clusterCount_;}
- /** \return The shift count required to multiply by blocksPerCluster. */
- uint8_t clusterSizeShift(void) const {return clusterSizeShift_;}
- /** \return The logical block number for the start of file data. */
- uint32_t dataStartBlock(void) const {return dataStartBlock_;}
- /** \return The number of FAT structures on the volume. */
- uint8_t fatCount(void) /*const*/ {
-
- SerialDebug.print("#fatCount_ ");
- SerialDebug.print((int)&fatCount_);
- SerialDebug.print(" # ");
- SerialDebug.print((int)fatCount_);
- SerialDebug.print("#");
- return fatCount_;}
- /** \return The logical block number for the start of the first FAT. */
- uint32_t fatStartBlock(void) const {return fatStartBlock_;}
- /** \return The FAT type of the volume. Values are 12, 16 or 32. */
- uint8_t fatType(void) const {return fatType_;}
- /** \return The number of entries in the root directory for FAT16 volumes. */
- uint32_t rootDirEntryCount(void) const {return rootDirEntryCount_;}
- /** \return The logical block number for the start of the root directory
- on FAT16 volumes or the first cluster number on FAT32 volumes. */
- uint32_t rootDirStart(void) const {return rootDirStart_;}
- /** return a pointer to the Sd2Card object for this volume */
- static Sd2Card* sdCard(void) {return sdCard_;}
-//------------------------------------------------------------------------------
-#if ALLOW_DEPRECATED_FUNCTIONS
- // Deprecated functions - suppress cpplint warnings with NOLINT comment
- /** \deprecated Use: uint8_t SdVolume::init(Sd2Card* dev); */
- uint8_t init(Sd2Card& dev) {return init(&dev);} // NOLINT
-
- /** \deprecated Use: uint8_t SdVolume::init(Sd2Card* dev, uint8_t vol); */
- uint8_t init(Sd2Card& dev, uint8_t part) { // NOLINT
- return init(&dev, part);
- }
-#endif // ALLOW_DEPRECATED_FUNCTIONS
-//------------------------------------------------------------------------------
- private:
- // Allow SdFile access to SdVolume private data.
- friend class SdFile;
-
- // value for action argument in cacheRawBlock to indicate read from cache
- static uint8_t const CACHE_FOR_READ = 0;
- // value for action argument in cacheRawBlock to indicate cache dirty
- static uint8_t const CACHE_FOR_WRITE = 1;
-
- static cache_t cacheBuffer_; // 512 byte cache for device blocks
- static uint32_t cacheBlockNumber_; // Logical number of block in the cache
- static Sd2Card* sdCard_; // Sd2Card object for cache
- static uint8_t cacheDirty_; // cacheFlush() will write block if true
- static uint32_t cacheMirrorBlock_; // block number for mirror FAT
-//
- uint32_t allocSearchStart_; // start cluster for alloc search
- uint32_t blocksPerFat_; // FAT size in blocks
- uint32_t clusterCount_; // clusters in one FAT
- uint32_t dataStartBlock_; // first data block number
- uint32_t fatStartBlock_; // start block for first FAT
- uint32_t rootDirStart_; // root start block for FAT16, cluster for FAT32
- uint8_t fatCount_; // number of FATs on volume
- uint8_t fatType_; // volume type (12, 16, OR 32)
- uint8_t blocksPerCluster_; // cluster size in blocks
- uint8_t clusterSizeShift_; // shift to convert cluster count to block count
- uint16_t rootDirEntryCount_; // number of entries in FAT16 root dir
- //----------------------------------------------------------------------------
- uint8_t allocContiguous(uint32_t count, uint32_t* curCluster);
- uint8_t blockOfCluster(uint32_t position) const {
- return (position >> 9) & (blocksPerCluster_ - 1);}
- uint32_t clusterStartBlock(uint32_t cluster) const {
- return dataStartBlock_ + ((cluster - 2) << clusterSizeShift_);}
- uint32_t blockNumber(uint32_t cluster, uint32_t position) const {
- return clusterStartBlock(cluster) + blockOfCluster(position);}
- static uint8_t cacheFlush(void);
- static uint8_t cacheRawBlock(uint32_t blockNumber, uint8_t action);
- static void cacheSetDirty(void) {cacheDirty_ |= CACHE_FOR_WRITE;}
- static uint8_t cacheZeroBlock(uint32_t blockNumber);
- uint8_t chainSize(uint32_t beginCluster, uint32_t* size) const;
- uint8_t fatGet(uint32_t cluster, uint32_t* value) const;
- uint8_t fatPut(uint32_t cluster, uint32_t value);
- uint8_t fatPutEOC(uint32_t cluster) {
- return fatPut(cluster, 0x0FFFFFFF);
- }
- uint8_t freeChain(uint32_t cluster);
- uint8_t isEOC(uint32_t cluster) const {
- return cluster >= (fatType_ == 16 ? FAT16EOC_MIN : FAT32EOC_MIN);
- }
- uint8_t readBlock(uint32_t block, uint8_t* dst) {
- return sdCard_->readBlock(block, dst);}
- uint8_t readData(uint32_t block, uint16_t offset,
- uint16_t count, uint8_t* dst) {
- return sdCard_->readData(block, offset, count, dst);
- }
- uint8_t writeBlock(uint32_t block, const uint8_t* dst) {
- return sdCard_->writeBlock(block, dst);
- }
-};
-#endif // SdFat_h
+/* Arduino SdFat Library
+ * Copyright (C) 2009 by William Greiman
+ *
+ * This file is part of the Arduino SdFat Library
+ *
+ * This Library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Arduino SdFat Library. If not, see
+ * .
+ */
+#ifndef SdFat_h
+#define SdFat_h
+/**
+ * \file
+ * SdFile and SdVolume classes
+ */
+//#include
+#include
+#include "Sd2Card.h"
+#include "FatStructs.h"
+#include "Print.h"
+//------------------------------------------------------------------------------
+/**
+ * Allow use of deprecated functions if non-zero
+ */
+#define ALLOW_DEPRECATED_FUNCTIONS 1
+//------------------------------------------------------------------------------
+// forward declaration since SdVolume is used in SdFile
+class SdVolume;
+//==============================================================================
+// SdFile class
+
+// flags for ls()
+/** ls() flag to print modify date */
+uint8_t const LS_DATE = 1;
+/** ls() flag to print file size */
+uint8_t const LS_SIZE = 2;
+/** ls() flag for recursive list of subdirectories */
+uint8_t const LS_R = 4;
+
+// use the gnu style oflag in open()
+/** open() oflag for reading */
+uint8_t const O_READ = 0X01;
+/** open() oflag - same as O_READ */
+uint8_t const O_RDONLY = O_READ;
+/** open() oflag for write */
+uint8_t const O_WRITE = 0X02;
+/** open() oflag - same as O_WRITE */
+uint8_t const O_WRONLY = O_WRITE;
+/** open() oflag for reading and writing */
+uint8_t const O_RDWR = (O_READ | O_WRITE);
+/** open() oflag mask for access modes */
+uint8_t const O_ACCMODE = (O_READ | O_WRITE);
+/** The file offset shall be set to the end of the file prior to each write. */
+uint8_t const O_APPEND = 0X04;
+/** synchronous writes - call sync() after each write */
+uint8_t const O_SYNC = 0X08;
+/** create the file if nonexistent */
+uint8_t const O_CREAT = 0X10;
+/** If O_CREAT and O_EXCL are set, open() shall fail if the file exists */
+uint8_t const O_EXCL = 0X20;
+/** truncate the file to zero length */
+uint8_t const O_TRUNC = 0X40;
+
+// flags for timestamp
+/** set the file's last access date */
+uint8_t const T_ACCESS = 1;
+/** set the file's creation date and time */
+uint8_t const T_CREATE = 2;
+/** Set the file's write date and time */
+uint8_t const T_WRITE = 4;
+// values for type_
+/** This SdFile has not been opened. */
+uint8_t const FAT_FILE_TYPE_CLOSED = 0;
+/** SdFile for a file */
+uint8_t const FAT_FILE_TYPE_NORMAL = 1;
+/** SdFile for a FAT16 root directory */
+uint8_t const FAT_FILE_TYPE_ROOT16 = 2;
+/** SdFile for a FAT32 root directory */
+uint8_t const FAT_FILE_TYPE_ROOT32 = 3;
+/** SdFile for a subdirectory */
+uint8_t const FAT_FILE_TYPE_SUBDIR = 4;
+/** Test value for directory type */
+uint8_t const FAT_FILE_TYPE_MIN_DIR = FAT_FILE_TYPE_ROOT16;
+
+/** date field for FAT directory entry */
+static inline uint16_t FAT_DATE(uint16_t year, uint8_t month, uint8_t day) {
+ return (year - 1980) << 9 | month << 5 | day;
+}
+/** year part of FAT directory date field */
+static inline uint16_t FAT_YEAR(uint16_t fatDate) {
+ return 1980 + (fatDate >> 9);
+}
+/** month part of FAT directory date field */
+static inline uint8_t FAT_MONTH(uint16_t fatDate) {
+ return (fatDate >> 5) & 0XF;
+}
+/** day part of FAT directory date field */
+static inline uint8_t FAT_DAY(uint16_t fatDate) {
+ return fatDate & 0X1F;
+}
+/** time field for FAT directory entry */
+static inline uint16_t FAT_TIME(uint8_t hour, uint8_t minute, uint8_t second) {
+ return hour << 11 | minute << 5 | second >> 1;
+}
+/** hour part of FAT directory time field */
+static inline uint8_t FAT_HOUR(uint16_t fatTime) {
+ return fatTime >> 11;
+}
+/** minute part of FAT directory time field */
+static inline uint8_t FAT_MINUTE(uint16_t fatTime) {
+ return(fatTime >> 5) & 0X3F;
+}
+/** second part of FAT directory time field */
+static inline uint8_t FAT_SECOND(uint16_t fatTime) {
+ return 2*(fatTime & 0X1F);
+}
+/** Default date for file timestamps is 1 Jan 2000 */
+uint16_t const FAT_DEFAULT_DATE = ((2000 - 1980) << 9) | (1 << 5) | 1;
+/** Default time for file timestamp is 1 am */
+uint16_t const FAT_DEFAULT_TIME = (1 << 11);
+//------------------------------------------------------------------------------
+/**
+ * \class SdFile
+ * \brief Access FAT16 and FAT32 files on SD and SDHC cards.
+ */
+class SdFile : public Print {
+ public:
+ /** Create an instance of SdFile. */
+ SdFile(void) : type_(FAT_FILE_TYPE_CLOSED) {}
+ /**
+ * writeError is set to true if an error occurs during a write().
+ * Set writeError to false before calling print() and/or write() and check
+ * for true after calls to print() and/or write().
+ */
+ bool writeError;
+ /**
+ * Cancel unbuffered reads for this file.
+ * See setUnbufferedRead()
+ */
+ void clearUnbufferedRead(void) {
+ flags_ &= ~F_FILE_UNBUFFERED_READ;
+ }
+ uint8_t close(void);
+ uint8_t contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock);
+ uint8_t createContiguous(SdFile* dirFile,
+ const char* fileName, uint32_t size);
+ /** \return The current cluster number for a file or directory. */
+ uint32_t curCluster(void) const {return curCluster_;}
+ /** \return The current position for a file or directory. */
+ uint32_t curPosition(void) const {return curPosition_;}
+ /**
+ * Set the date/time callback function
+ *
+ * \param[in] dateTime The user's call back function. The callback
+ * function is of the form:
+ *
+ * \code
+ * void dateTime(uint16_t* date, uint16_t* time) {
+ * uint16_t year;
+ * uint8_t month, day, hour, minute, second;
+ *
+ * // User gets date and time from GPS or real-time clock here
+ *
+ * // return date using FAT_DATE macro to format fields
+ * *date = FAT_DATE(year, month, day);
+ *
+ * // return time using FAT_TIME macro to format fields
+ * *time = FAT_TIME(hour, minute, second);
+ * }
+ * \endcode
+ *
+ * Sets the function that is called when a file is created or when
+ * a file's directory entry is modified by sync(). All timestamps,
+ * access, creation, and modify, are set when a file is created.
+ * sync() maintains the last access date and last modify date/time.
+ *
+ * See the timestamp() function.
+ */
+ static void dateTimeCallback(
+ void (*dateTime)(uint16_t* date, uint16_t* time)) {
+ dateTime_ = dateTime;
+ }
+ /**
+ * Cancel the date/time callback function.
+ */
+ static void dateTimeCallbackCancel(void) {
+ // use explicit zero since NULL is not defined for Sanguino
+ dateTime_ = 0;
+ }
+ /** \return Address of the block that contains this file's directory. */
+ uint32_t dirBlock(void) const {return dirBlock_;}
+ uint8_t dirEntry(dir_t* dir);
+ /** \return Index of this file's directory in the block dirBlock. */
+ uint8_t dirIndex(void) const {return dirIndex_;}
+ static void dirName(const dir_t& dir, char* name);
+ /** \return The total number of bytes in a file or directory. */
+ uint32_t fileSize(void) const {return fileSize_;}
+ /** \return The first cluster number for a file or directory. */
+ uint32_t firstCluster(void) const {return firstCluster_;}
+ /** \return True if this is a SdFile for a directory else false. */
+ uint8_t isDir(void) const {return type_ >= FAT_FILE_TYPE_MIN_DIR;}
+ /** \return True if this is a SdFile for a file else false. */
+ uint8_t isFile(void) const {return type_ == FAT_FILE_TYPE_NORMAL;}
+ /** \return True if this is a SdFile for an open file/directory else false. */
+ uint8_t isOpen(void) const {return type_ != FAT_FILE_TYPE_CLOSED;}
+ /** \return True if this is a SdFile for a subdirectory else false. */
+ uint8_t isSubDir(void) const {return type_ == FAT_FILE_TYPE_SUBDIR;}
+ /** \return True if this is a SdFile for the root directory. */
+ uint8_t isRoot(void) const {
+ return type_ == FAT_FILE_TYPE_ROOT16 || type_ == FAT_FILE_TYPE_ROOT32;
+ }
+ void ls(uint8_t flags = 0, uint8_t indent = 0);
+ uint8_t makeDir(SdFile* dir, const char* dirName);
+ uint8_t open(SdFile* dirFile, uint16_t index, uint8_t oflag);
+ uint8_t open(SdFile* dirFile, const char* fileName, uint8_t oflag);
+
+ uint8_t openRoot(SdVolume* vol);
+ static void printDirName(const dir_t& dir, uint8_t width);
+ static void printFatDate(uint16_t fatDate);
+ static void printFatTime(uint16_t fatTime);
+ static void printTwoDigits(uint8_t v);
+ /**
+ * Read the next byte from a file.
+ *
+ * \return For success read returns the next byte in the file as an int.
+ * If an error occurs or end of file is reached -1 is returned.
+ */
+ int16_t read(void) {
+ uint8_t b;
+ return read(&b, 1) == 1 ? b : -1;
+ }
+ int16_t read(void* buf, uint16_t nbyte);
+ int8_t readDir(dir_t* dir);
+ static uint8_t remove(SdFile* dirFile, const char* fileName);
+ uint8_t remove(void);
+ /** Set the file's current position to zero. */
+ void rewind(void) {
+ curPosition_ = curCluster_ = 0;
+ }
+ uint8_t rmDir(void);
+ uint8_t rmRfStar(void);
+ /** Set the files position to current position + \a pos. See seekSet(). */
+ uint8_t seekCur(uint32_t pos) {
+ return seekSet(curPosition_ + pos);
+ }
+ /**
+ * Set the files current position to end of file. Useful to position
+ * a file for append. See seekSet().
+ */
+ uint8_t seekEnd(void) {return seekSet(fileSize_);}
+ uint8_t seekSet(uint32_t pos);
+ /**
+ * Use unbuffered reads to access this file. Used with Wave
+ * Shield ISR. Used with Sd2Card::partialBlockRead() in WaveRP.
+ *
+ * Not recommended for normal applications.
+ */
+ void setUnbufferedRead(void) {
+ if (isFile()) flags_ |= F_FILE_UNBUFFERED_READ;
+ }
+ uint8_t timestamp(uint8_t flag, uint16_t year, uint8_t month, uint8_t day,
+ uint8_t hour, uint8_t minute, uint8_t second);
+ uint8_t sync(void);
+ /** Type of this SdFile. You should use isFile() or isDir() instead of type()
+ * if possible.
+ *
+ * \return The file or directory type.
+ */
+ uint8_t type(void) const {return type_;}
+ uint8_t truncate(uint32_t size);
+ /** \return Unbuffered read flag. */
+ uint8_t unbufferedRead(void) const {
+ return flags_ & F_FILE_UNBUFFERED_READ;
+ }
+ /** \return SdVolume that contains this file. */
+ SdVolume* volume(void) const {return vol_;}
+ void write(uint8_t b);
+ int16_t write(const void* buf, uint16_t nbyte);
+ void write(const char* str);
+// void write_P(PGM_P str);
+// void writeln_P(PGM_P str);
+//------------------------------------------------------------------------------
+#if ALLOW_DEPRECATED_FUNCTIONS
+// Deprecated functions - suppress cpplint warnings with NOLINT comment
+ /** \deprecated Use:
+ * uint8_t SdFile::contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock);
+ */
+ uint8_t contiguousRange(uint32_t& bgnBlock, uint32_t& endBlock) { // NOLINT
+ return contiguousRange(&bgnBlock, &endBlock);
+ }
+ /** \deprecated Use:
+ * uint8_t SdFile::createContiguous(SdFile* dirFile,
+ * const char* fileName, uint32_t size)
+ */
+ uint8_t createContiguous(SdFile& dirFile, // NOLINT
+ const char* fileName, uint32_t size) {
+ return createContiguous(&dirFile, fileName, size);
+ }
+
+ /**
+ * \deprecated Use:
+ * static void SdFile::dateTimeCallback(
+ * void (*dateTime)(uint16_t* date, uint16_t* time));
+ */
+ static void dateTimeCallback(
+ void (*dateTime)(uint16_t& date, uint16_t& time)) { // NOLINT
+ oldDateTime_ = dateTime;
+ dateTime_ = dateTime ? oldToNew : 0;
+ }
+ /** \deprecated Use: uint8_t SdFile::dirEntry(dir_t* dir); */
+ uint8_t dirEntry(dir_t& dir) {return dirEntry(&dir);} // NOLINT
+ /** \deprecated Use:
+ * uint8_t SdFile::makeDir(SdFile* dir, const char* dirName);
+ */
+ uint8_t makeDir(SdFile& dir, const char* dirName) { // NOLINT
+ return makeDir(&dir, dirName);
+ }
+ /** \deprecated Use:
+ * uint8_t SdFile::open(SdFile* dirFile, const char* fileName, uint8_t oflag);
+ */
+ uint8_t open(SdFile& dirFile, // NOLINT
+ const char* fileName, uint8_t oflag) {
+ return open(&dirFile, fileName, oflag);
+ }
+ /** \deprecated Do not use in new apps */
+ uint8_t open(SdFile& dirFile, const char* fileName) { // NOLINT
+ return open(dirFile, fileName, O_RDWR);
+ }
+ /** \deprecated Use:
+ * uint8_t SdFile::open(SdFile* dirFile, uint16_t index, uint8_t oflag);
+ */
+ uint8_t open(SdFile& dirFile, uint16_t index, uint8_t oflag) { // NOLINT
+ return open(&dirFile, index, oflag);
+ }
+ /** \deprecated Use: uint8_t SdFile::openRoot(SdVolume* vol); */
+ uint8_t openRoot(SdVolume& vol) {return openRoot(&vol);} // NOLINT
+
+ /** \deprecated Use: int8_t SdFile::readDir(dir_t* dir); */
+ int8_t readDir(dir_t& dir) {return readDir(&dir);} // NOLINT
+ /** \deprecated Use:
+ * static uint8_t SdFile::remove(SdFile* dirFile, const char* fileName);
+ */
+ static uint8_t remove(SdFile& dirFile, const char* fileName) { // NOLINT
+ return remove(&dirFile, fileName);
+ }
+//------------------------------------------------------------------------------
+// rest are private
+ private:
+ static void (*oldDateTime_)(uint16_t& date, uint16_t& time); // NOLINT
+ static void oldToNew(uint16_t* date, uint16_t* time) {
+ uint16_t d;
+ uint16_t t;
+ oldDateTime_(d, t);
+ *date = d;
+ *time = t;
+ }
+#endif // ALLOW_DEPRECATED_FUNCTIONS
+ private:
+ // bits defined in flags_
+ // should be 0XF
+ static uint8_t const F_OFLAG = (O_ACCMODE | O_APPEND | O_SYNC);
+ // available bits
+ static uint8_t const F_UNUSED = 0X30;
+ // use unbuffered SD read
+ static uint8_t const F_FILE_UNBUFFERED_READ = 0X40;
+ // sync of directory entry required
+ static uint8_t const F_FILE_DIR_DIRTY = 0X80;
+
+// make sure F_OFLAG is ok
+#if ((F_UNUSED | F_FILE_UNBUFFERED_READ | F_FILE_DIR_DIRTY) & F_OFLAG)
+#error flags_ bits conflict
+#endif // flags_ bits
+
+ // private data
+ uint8_t flags_; // See above for definition of flags_ bits
+ uint8_t type_; // type of file see above for values
+ uint32_t curCluster_; // cluster for current file position
+ uint32_t curPosition_; // current file position in bytes from beginning
+ uint32_t dirBlock_; // SD block that contains directory entry for file
+ uint8_t dirIndex_; // index of entry in dirBlock 0 <= dirIndex_ <= 0XF
+ uint32_t fileSize_; // file size in bytes
+ uint32_t firstCluster_; // first cluster of file
+ SdVolume* vol_; // volume where file is located
+
+ // private functions
+ uint8_t addCluster(void);
+ uint8_t addDirCluster(void);
+ dir_t* cacheDirEntry(uint8_t action);
+ static void (*dateTime_)(uint16_t* date, uint16_t* time);
+ static uint8_t make83Name(const char* str, uint8_t* name);
+ uint8_t openCachedEntry(uint8_t cacheIndex, uint8_t oflags);
+ dir_t* readDirCache(void);
+};
+//==============================================================================
+// SdVolume class
+/**
+ * \brief Cache for an SD data block
+ */
+union cache_t {
+ /** Used to access cached file data blocks. */
+ uint8_t data[512];
+ /** Used to access cached FAT16 entries. */
+ uint16_t fat16[256];
+ /** Used to access cached FAT32 entries. */
+ uint32_t fat32[128];
+ /** Used to access cached directory entries. */
+ dir_t dir[16];
+ /** Used to access a cached MasterBoot Record. */
+ mbr_t mbr;
+ /** Used to access to a cached FAT boot sector. */
+ fbs_t fbs;
+};
+//------------------------------------------------------------------------------
+/**
+ * \class SdVolume
+ * \brief Access FAT16 and FAT32 volumes on SD and SDHC cards.
+ */
+class SdVolume {
+ public:
+ /** Create an instance of SdVolume */
+ SdVolume(void) :allocSearchStart_(2), fatType_(0) {}
+ /** Clear the cache and returns a pointer to the cache. Used by the WaveRP
+ * recorder to do raw write to the SD card. Not for normal apps.
+ */
+ static uint8_t* cacheClear(void) {
+ cacheFlush();
+ cacheBlockNumber_ = 0XFFFFFFFF;
+ return cacheBuffer_.data;
+ }
+ /**
+ * Initialize a FAT volume. Try partition one first then try super
+ * floppy format.
+ *
+ * \param[in] dev The Sd2Card where the volume is located.
+ *
+ * \return The value one, true, is returned for success and
+ * the value zero, false, is returned for failure. Reasons for
+ * failure include not finding a valid partition, not finding a valid
+ * FAT file system or an I/O error.
+ */
+ uint8_t init(Sd2Card* dev) { return init(dev, 1) ? true : init(dev, 0);}
+ uint8_t init(Sd2Card* dev, uint8_t part);
+
+ // inline functions that return volume info
+ /** \return The volume's cluster size in blocks. */
+ uint8_t blocksPerCluster(void) const {return blocksPerCluster_;}
+ /** \return The number of blocks in one FAT. */
+ uint32_t blocksPerFat(void) const {return blocksPerFat_;}
+ /** \return The total number of clusters in the volume. */
+ uint32_t clusterCount(void) const {return clusterCount_;}
+ /** \return The shift count required to multiply by blocksPerCluster. */
+ uint8_t clusterSizeShift(void) const {return clusterSizeShift_;}
+ /** \return The logical block number for the start of file data. */
+ uint32_t dataStartBlock(void) const {return dataStartBlock_;}
+ /** \return The number of FAT structures on the volume. */
+ uint8_t fatCount(void) /*const*/ {
+
+ SerialDebug.print("#fatCount_ ");
+ SerialDebug.print((int)&fatCount_);
+ SerialDebug.print(" # ");
+ SerialDebug.print((int)fatCount_);
+ SerialDebug.print("#");
+ return fatCount_;}
+ /** \return The logical block number for the start of the first FAT. */
+ uint32_t fatStartBlock(void) const {return fatStartBlock_;}
+ /** \return The FAT type of the volume. Values are 12, 16 or 32. */
+ uint8_t fatType(void) const {return fatType_;}
+ /** \return The number of entries in the root directory for FAT16 volumes. */
+ uint32_t rootDirEntryCount(void) const {return rootDirEntryCount_;}
+ /** \return The logical block number for the start of the root directory
+ on FAT16 volumes or the first cluster number on FAT32 volumes. */
+ uint32_t rootDirStart(void) const {return rootDirStart_;}
+ /** return a pointer to the Sd2Card object for this volume */
+ static Sd2Card* sdCard(void) {return sdCard_;}
+//------------------------------------------------------------------------------
+#if ALLOW_DEPRECATED_FUNCTIONS
+ // Deprecated functions - suppress cpplint warnings with NOLINT comment
+ /** \deprecated Use: uint8_t SdVolume::init(Sd2Card* dev); */
+ uint8_t init(Sd2Card& dev) {return init(&dev);} // NOLINT
+
+ /** \deprecated Use: uint8_t SdVolume::init(Sd2Card* dev, uint8_t vol); */
+ uint8_t init(Sd2Card& dev, uint8_t part) { // NOLINT
+ return init(&dev, part);
+ }
+#endif // ALLOW_DEPRECATED_FUNCTIONS
+//------------------------------------------------------------------------------
+ private:
+ // Allow SdFile access to SdVolume private data.
+ friend class SdFile;
+
+ // value for action argument in cacheRawBlock to indicate read from cache
+ static uint8_t const CACHE_FOR_READ = 0;
+ // value for action argument in cacheRawBlock to indicate cache dirty
+ static uint8_t const CACHE_FOR_WRITE = 1;
+
+ static cache_t cacheBuffer_; // 512 byte cache for device blocks
+ static uint32_t cacheBlockNumber_; // Logical number of block in the cache
+ static Sd2Card* sdCard_; // Sd2Card object for cache
+ static uint8_t cacheDirty_; // cacheFlush() will write block if true
+ static uint32_t cacheMirrorBlock_; // block number for mirror FAT
+//
+ uint32_t allocSearchStart_; // start cluster for alloc search
+ uint32_t blocksPerFat_; // FAT size in blocks
+ uint32_t clusterCount_; // clusters in one FAT
+ uint32_t dataStartBlock_; // first data block number
+ uint32_t fatStartBlock_; // start block for first FAT
+ uint32_t rootDirStart_; // root start block for FAT16, cluster for FAT32
+ uint8_t fatCount_; // number of FATs on volume
+ uint8_t fatType_; // volume type (12, 16, OR 32)
+ uint8_t blocksPerCluster_; // cluster size in blocks
+ uint8_t clusterSizeShift_; // shift to convert cluster count to block count
+ uint16_t rootDirEntryCount_; // number of entries in FAT16 root dir
+ //----------------------------------------------------------------------------
+ uint8_t allocContiguous(uint32_t count, uint32_t* curCluster);
+ uint8_t blockOfCluster(uint32_t position) const {
+ return (position >> 9) & (blocksPerCluster_ - 1);}
+ uint32_t clusterStartBlock(uint32_t cluster) const {
+ return dataStartBlock_ + ((cluster - 2) << clusterSizeShift_);}
+ uint32_t blockNumber(uint32_t cluster, uint32_t position) const {
+ return clusterStartBlock(cluster) + blockOfCluster(position);}
+ static uint8_t cacheFlush(void);
+ static uint8_t cacheRawBlock(uint32_t blockNumber, uint8_t action);
+ static void cacheSetDirty(void) {cacheDirty_ |= CACHE_FOR_WRITE;}
+ static uint8_t cacheZeroBlock(uint32_t blockNumber);
+ uint8_t chainSize(uint32_t beginCluster, uint32_t* size) const;
+ uint8_t fatGet(uint32_t cluster, uint32_t* value) const;
+ uint8_t fatPut(uint32_t cluster, uint32_t value);
+ uint8_t fatPutEOC(uint32_t cluster) {
+ return fatPut(cluster, 0x0FFFFFFF);
+ }
+ uint8_t freeChain(uint32_t cluster);
+ uint8_t isEOC(uint32_t cluster) const {
+ return cluster >= (fatType_ == 16 ? FAT16EOC_MIN : FAT32EOC_MIN);
+ }
+ uint8_t readBlock(uint32_t block, uint8_t* dst) {
+ return sdCard_->readBlock(block, dst);}
+ uint8_t readData(uint32_t block, uint16_t offset,
+ uint16_t count, uint8_t* dst) {
+ return sdCard_->readData(block, offset, count, dst);
+ }
+ uint8_t writeBlock(uint32_t block, const uint8_t* dst) {
+ return sdCard_->writeBlock(block, dst);
+ }
+};
+#endif // SdFat_h
diff --git a/Libmaple/libmaple/libraries/mapleSDfat/SdFatmainpage.h b/Libmaple/libmaple/libraries/mapleSDfat/SdFatmainpage.h
index 73b3b63b..d26cb854 100644
--- a/Libmaple/libmaple/libraries/mapleSDfat/SdFatmainpage.h
+++ b/Libmaple/libmaple/libraries/mapleSDfat/SdFatmainpage.h
@@ -1,202 +1,202 @@
-/* Arduino SdFat Library
- * Copyright (C) 2009 by William Greiman
- *
- * This file is part of the Arduino SdFat Library
- *
- * This Library is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This Library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with the Arduino SdFat Library. If not, see
- * .
- */
-
-/**
-\mainpage Arduino SdFat Library
-Copyright © 2009 by William Greiman
-
-
-\section Intro Introduction
-The Arduino SdFat Library is a minimal implementation of FAT16 and FAT32
-file systems on SD flash memory cards. Standard SD and high capacity
-SDHC cards are supported.
-
-The SdFat only supports short 8.3 names.
-
-The main classes in SdFat are Sd2Card, SdVolume, and SdFile.
-
-The Sd2Card class supports access to standard SD cards and SDHC cards. Most
-applications will only need to call the Sd2Card::init() member function.
-
-The SdVolume class supports FAT16 and FAT32 partitions. Most applications
-will only need to call the SdVolume::init() member function.
-
-The SdFile class provides file access functions such as open(), read(),
-remove(), write(), close() and sync(). This class supports access to the root
-directory and subdirectories.
-
-A number of example are provided in the SdFat/examples folder. These were
-developed to test SdFat and illustrate its use.
-
-SdFat was developed for high speed data recording. SdFat was used to implement
-an audio record/play class, WaveRP, for the Adafruit Wave Shield. This
-application uses special Sd2Card calls to write to contiguous files in raw mode.
-These functions reduce write latency so that audio can be recorded with the
-small amount of RAM in the Arduino.
-
-\section SDcard SD\SDHC Cards
-
-Arduinos access SD cards using the cards SPI protocol. PCs, Macs, and
-most consumer devices use the 4-bit parallel SD protocol. A card that
-functions well on A PC or Mac may not work well on the Arduino.
-
-Most cards have good SPI read performance but cards vary widely in SPI
-write performance. Write performance is limited by how efficiently the
-card manages internal erase/remapping operations. The Arduino cannot
-optimize writes to reduce erase operations because of its limit RAM.
-
-SanDisk cards generally have good write performance. They seem to have
-more internal RAM buffering than other cards and therefore can limit
-the number of flash erase operations that the Arduino forces due to its
-limited RAM.
-
-\section Hardware Hardware Configuration
-
-SdFat was developed using an
- Adafruit Industries
- Wave Shield.
-
-The hardware interface to the SD card should not use a resistor based level
-shifter. SdFat sets the SPI bus frequency to 8 MHz which results in signal
-rise times that are too slow for the edge detectors in many newer SD card
-controllers when resistor voltage dividers are used.
-
-The 5 to 3.3 V level shifter for 5 V Arduinos should be IC based like the
-74HC4050N based circuit shown in the file SdLevel.png. The Adafruit Wave Shield
-uses a 74AHC125N. Gravitech sells SD and MicroSD Card Adapters based on the
-74LCX245.
-
-If you are using a resistor based level shifter and are having problems try
-setting the SPI bus frequency to 4 MHz. This can be done by using
-card.init(SPI_HALF_SPEED) to initialize the SD card.
-
-\section comment Bugs and Comments
-
-If you wish to report bugs or have comments, send email to fat16lib@sbcglobal.net.
-
-\section SdFatClass SdFat Usage
-
-SdFat uses a slightly restricted form of short names.
-Only printable ASCII characters are supported. No characters with code point
-values greater than 127 are allowed. Space is not allowed even though space
-was allowed in the API of early versions of DOS.
-
-Short names are limited to 8 characters followed by an optional period (.)
-and extension of up to 3 characters. The characters may be any combination
-of letters and digits. The following special characters are also allowed:
-
-$ % ' - _ @ ~ ` ! ( ) { } ^ # &
-
-Short names are always converted to upper case and their original case
-value is lost.
-
-\note
- The Arduino Print class uses character
-at a time writes so it was necessary to use a \link SdFile::sync() sync() \endlink
-function to control when data is written to the SD card.
-
-\par
-An application which writes to a file using \link Print::print() print()\endlink,
-\link Print::println() println() \endlink
-or \link SdFile::write write() \endlink must call \link SdFile::sync() sync() \endlink
-at the appropriate time to force data and directory information to be written
-to the SD Card. Data and directory information are also written to the SD card
-when \link SdFile::close() close() \endlink is called.
-
-\par
-Applications must use care calling \link SdFile::sync() sync() \endlink
-since 2048 bytes of I/O is required to update file and
-directory information. This includes writing the current data block, reading
-the block that contains the directory entry for update, writing the directory
-block back and reading back the current data block.
-
-It is possible to open a file with two or more instances of SdFile. A file may
-be corrupted if data is written to the file by more than one instance of SdFile.
-
-\section HowTo How to format SD Cards as FAT Volumes
-
-You should use a freshly formatted SD card for best performance. FAT
-file systems become slower if many files have been created and deleted.
-This is because the directory entry for a deleted file is marked as deleted,
-but is not deleted. When a new file is created, these entries must be scanned
-before creating the file, a flaw in the FAT design. Also files can become
-fragmented which causes reads and writes to be slower.
-
-Microsoft operating systems support removable media formatted with a
-Master Boot Record, MBR, or formatted as a super floppy with a FAT Boot Sector
-in block zero.
-
-Microsoft operating systems expect MBR formatted removable media
-to have only one partition. The first partition should be used.
-
-Microsoft operating systems do not support partitioning SD flash cards.
-If you erase an SD card with a program like KillDisk, Most versions of
-Windows will format the card as a super floppy.
-
-The best way to restore an SD card's format is to use SDFormatter
-which can be downloaded from:
-
-http://www.sdcard.org/consumers/formatter/
-
-SDFormatter aligns flash erase boundaries with file
-system structures which reduces write latency and file system overhead.
-
-SDFormatter does not have an option for FAT type so it may format
-small cards as FAT12.
-
-After the MBR is restored by SDFormatter you may need to reformat small
-cards that have been formatted FAT12 to force the volume type to be FAT16.
-
-If you reformat the SD card with an OS utility, choose a cluster size that
-will result in:
-
-4084 < CountOfClusters && CountOfClusters < 65525
-
-The volume will then be FAT16.
-
-If you are formatting an SD card on OS X or Linux, be sure to use the first
-partition. Format this partition with a cluster count in above range.
-
-\section References References
-
-Adafruit Industries:
-
-http://www.adafruit.com/
-
-http://www.ladyada.net/make/waveshield/
-
-The Arduino site:
-
-http://www.arduino.cc/
-
-For more information about FAT file systems see:
-
-http://www.microsoft.com/whdc/system/platform/firmware/fatgen.mspx
-
-For information about using SD cards as SPI devices see:
-
-http://www.sdcard.org/developers/tech/sdcard/pls/Simplified_Physical_Layer_Spec.pdf
-
-The ATmega328 datasheet:
-
-http://www.atmel.com/dyn/resources/prod_documents/doc8161.pdf
-
-
- */
+/* Arduino SdFat Library
+ * Copyright (C) 2009 by William Greiman
+ *
+ * This file is part of the Arduino SdFat Library
+ *
+ * This Library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Arduino SdFat Library. If not, see
+ * .
+ */
+
+/**
+\mainpage Arduino SdFat Library
+Copyright © 2009 by William Greiman
+
+
+\section Intro Introduction
+The Arduino SdFat Library is a minimal implementation of FAT16 and FAT32
+file systems on SD flash memory cards. Standard SD and high capacity
+SDHC cards are supported.
+
+The SdFat only supports short 8.3 names.
+
+The main classes in SdFat are Sd2Card, SdVolume, and SdFile.
+
+The Sd2Card class supports access to standard SD cards and SDHC cards. Most
+applications will only need to call the Sd2Card::init() member function.
+
+The SdVolume class supports FAT16 and FAT32 partitions. Most applications
+will only need to call the SdVolume::init() member function.
+
+The SdFile class provides file access functions such as open(), read(),
+remove(), write(), close() and sync(). This class supports access to the root
+directory and subdirectories.
+
+A number of example are provided in the SdFat/examples folder. These were
+developed to test SdFat and illustrate its use.
+
+SdFat was developed for high speed data recording. SdFat was used to implement
+an audio record/play class, WaveRP, for the Adafruit Wave Shield. This
+application uses special Sd2Card calls to write to contiguous files in raw mode.
+These functions reduce write latency so that audio can be recorded with the
+small amount of RAM in the Arduino.
+
+\section SDcard SD\SDHC Cards
+
+Arduinos access SD cards using the cards SPI protocol. PCs, Macs, and
+most consumer devices use the 4-bit parallel SD protocol. A card that
+functions well on A PC or Mac may not work well on the Arduino.
+
+Most cards have good SPI read performance but cards vary widely in SPI
+write performance. Write performance is limited by how efficiently the
+card manages internal erase/remapping operations. The Arduino cannot
+optimize writes to reduce erase operations because of its limit RAM.
+
+SanDisk cards generally have good write performance. They seem to have
+more internal RAM buffering than other cards and therefore can limit
+the number of flash erase operations that the Arduino forces due to its
+limited RAM.
+
+\section Hardware Hardware Configuration
+
+SdFat was developed using an
+ Adafruit Industries
+ Wave Shield.
+
+The hardware interface to the SD card should not use a resistor based level
+shifter. SdFat sets the SPI bus frequency to 8 MHz which results in signal
+rise times that are too slow for the edge detectors in many newer SD card
+controllers when resistor voltage dividers are used.
+
+The 5 to 3.3 V level shifter for 5 V Arduinos should be IC based like the
+74HC4050N based circuit shown in the file SdLevel.png. The Adafruit Wave Shield
+uses a 74AHC125N. Gravitech sells SD and MicroSD Card Adapters based on the
+74LCX245.
+
+If you are using a resistor based level shifter and are having problems try
+setting the SPI bus frequency to 4 MHz. This can be done by using
+card.init(SPI_HALF_SPEED) to initialize the SD card.
+
+\section comment Bugs and Comments
+
+If you wish to report bugs or have comments, send email to fat16lib@sbcglobal.net.
+
+\section SdFatClass SdFat Usage
+
+SdFat uses a slightly restricted form of short names.
+Only printable ASCII characters are supported. No characters with code point
+values greater than 127 are allowed. Space is not allowed even though space
+was allowed in the API of early versions of DOS.
+
+Short names are limited to 8 characters followed by an optional period (.)
+and extension of up to 3 characters. The characters may be any combination
+of letters and digits. The following special characters are also allowed:
+
+$ % ' - _ @ ~ ` ! ( ) { } ^ # &
+
+Short names are always converted to upper case and their original case
+value is lost.
+
+\note
+ The Arduino Print class uses character
+at a time writes so it was necessary to use a \link SdFile::sync() sync() \endlink
+function to control when data is written to the SD card.
+
+\par
+An application which writes to a file using \link Print::print() print()\endlink,
+\link Print::println() println() \endlink
+or \link SdFile::write write() \endlink must call \link SdFile::sync() sync() \endlink
+at the appropriate time to force data and directory information to be written
+to the SD Card. Data and directory information are also written to the SD card
+when \link SdFile::close() close() \endlink is called.
+
+\par
+Applications must use care calling \link SdFile::sync() sync() \endlink
+since 2048 bytes of I/O is required to update file and
+directory information. This includes writing the current data block, reading
+the block that contains the directory entry for update, writing the directory
+block back and reading back the current data block.
+
+It is possible to open a file with two or more instances of SdFile. A file may
+be corrupted if data is written to the file by more than one instance of SdFile.
+
+\section HowTo How to format SD Cards as FAT Volumes
+
+You should use a freshly formatted SD card for best performance. FAT
+file systems become slower if many files have been created and deleted.
+This is because the directory entry for a deleted file is marked as deleted,
+but is not deleted. When a new file is created, these entries must be scanned
+before creating the file, a flaw in the FAT design. Also files can become
+fragmented which causes reads and writes to be slower.
+
+Microsoft operating systems support removable media formatted with a
+Master Boot Record, MBR, or formatted as a super floppy with a FAT Boot Sector
+in block zero.
+
+Microsoft operating systems expect MBR formatted removable media
+to have only one partition. The first partition should be used.
+
+Microsoft operating systems do not support partitioning SD flash cards.
+If you erase an SD card with a program like KillDisk, Most versions of
+Windows will format the card as a super floppy.
+
+The best way to restore an SD card's format is to use SDFormatter
+which can be downloaded from:
+
+http://www.sdcard.org/consumers/formatter/
+
+SDFormatter aligns flash erase boundaries with file
+system structures which reduces write latency and file system overhead.
+
+SDFormatter does not have an option for FAT type so it may format
+small cards as FAT12.
+
+After the MBR is restored by SDFormatter you may need to reformat small
+cards that have been formatted FAT12 to force the volume type to be FAT16.
+
+If you reformat the SD card with an OS utility, choose a cluster size that
+will result in:
+
+4084 < CountOfClusters && CountOfClusters < 65525
+
+The volume will then be FAT16.
+
+If you are formatting an SD card on OS X or Linux, be sure to use the first
+partition. Format this partition with a cluster count in above range.
+
+\section References References
+
+Adafruit Industries:
+
+http://www.adafruit.com/
+
+http://www.ladyada.net/make/waveshield/
+
+The Arduino site:
+
+http://www.arduino.cc/
+
+For more information about FAT file systems see:
+
+http://www.microsoft.com/whdc/system/platform/firmware/fatgen.mspx
+
+For information about using SD cards as SPI devices see:
+
+http://www.sdcard.org/developers/tech/sdcard/pls/Simplified_Physical_Layer_Spec.pdf
+
+The ATmega328 datasheet:
+
+http://www.atmel.com/dyn/resources/prod_documents/doc8161.pdf
+
+
+ */
diff --git a/Libmaple/libmaple/libraries/mapleSDfat/SdFile.cpp b/Libmaple/libmaple/libraries/mapleSDfat/SdFile.cpp
index fd5f8d6d..e9d98152 100644
--- a/Libmaple/libmaple/libraries/mapleSDfat/SdFile.cpp
+++ b/Libmaple/libmaple/libraries/mapleSDfat/SdFile.cpp
@@ -1,1267 +1,1267 @@
-/* Arduino SdFat Library
- * Copyright (C) 2009 by William Greiman
- *
- * This file is part of the Arduino SdFat Library
- *
- * This Library is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This Library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with the Arduino SdFat Library. If not, see
- * .
- */
-#include
-#include "SdFat.h"
-//#include
-#include
-#include "HardwareSPI.h"
-#include
-
-//------------------------------------------------------------------------------
-// callback function for date/time
-void (*SdFile::dateTime_)(uint16_t* date, uint16_t* time) = NULL;
-
-#if ALLOW_DEPRECATED_FUNCTIONS
-// suppress cpplint warnings with NOLINT comment
-void (*SdFile::oldDateTime_)(uint16_t& date, uint16_t& time) = NULL; // NOLINT
-#endif // ALLOW_DEPRECATED_FUNCTIONS
-//------------------------------------------------------------------------------
-// add a cluster to a file
-uint8_t SdFile::addCluster() {
- if (!vol_->allocContiguous(1, &curCluster_)) return false;
-
- // if first cluster of file link to directory entry
- if (firstCluster_ == 0) {
- firstCluster_ = curCluster_;
- flags_ |= F_FILE_DIR_DIRTY;
- }
- return true;
-}
-//------------------------------------------------------------------------------
-// Add a cluster to a directory file and zero the cluster.
-// return with first block of cluster in the cache
-uint8_t SdFile::addDirCluster(void) {
- if (!addCluster()) return false;
-
- // zero data in cluster insure first cluster is in cache
- uint32_t block = vol_->clusterStartBlock(curCluster_);
- for (uint8_t i = vol_->blocksPerCluster_; i != 0; i--) {
- if (!SdVolume::cacheZeroBlock(block + i - 1)) return false;
- }
- // Increase directory file size by cluster size
- fileSize_ += 512UL << vol_->clusterSizeShift_;
- return true;
-}
-//------------------------------------------------------------------------------
-// cache a file's directory entry
-// return pointer to cached entry or null for failure
-dir_t* SdFile::cacheDirEntry(uint8_t action) {
- if (!SdVolume::cacheRawBlock(dirBlock_, action)) return NULL;
- return SdVolume::cacheBuffer_.dir + dirIndex_;
-}
-//------------------------------------------------------------------------------
-/**
- * Close a file and force cached data and directory information
- * to be written to the storage device.
- *
- * \return The value one, true, is returned for success and
- * the value zero, false, is returned for failure.
- * Reasons for failure include no file is open or an I/O error.
- */
-uint8_t SdFile::close(void) {
- if (!sync())return false;
- type_ = FAT_FILE_TYPE_CLOSED;
- return true;
-}
-//------------------------------------------------------------------------------
-/**
- * Check for contiguous file and return its raw block range.
- *
- * \param[out] bgnBlock the first block address for the file.
- * \param[out] endBlock the last block address for the file.
- *
- * \return The value one, true, is returned for success and
- * the value zero, false, is returned for failure.
- * Reasons for failure include file is not contiguous, file has zero length
- * or an I/O error occurred.
- */
-uint8_t SdFile::contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock) {
- // error if no blocks
- if (firstCluster_ == 0) return false;
-
- for (uint32_t c = firstCluster_; ; c++) {
- uint32_t next;
- if (!vol_->fatGet(c, &next)) return false;
-
- // check for contiguous
- if (next != (c + 1)) {
- // error if not end of chain
- if (!vol_->isEOC(next)) return false;
- *bgnBlock = vol_->clusterStartBlock(firstCluster_);
- *endBlock = vol_->clusterStartBlock(c)
- + vol_->blocksPerCluster_ - 1;
- return true;
- }
- }
-}
-//------------------------------------------------------------------------------
-/**
- * Create and open a new contiguous file of a specified size.
- *
- * \note This function only supports short DOS 8.3 names.
- * See open() for more information.
- *
- * \param[in] dirFile The directory where the file will be created.
- * \param[in] fileName A valid DOS 8.3 file name.
- * \param[in] size The desired file size.
- *
- * \return The value one, true, is returned for success and
- * the value zero, false, is returned for failure.
- * Reasons for failure include \a fileName contains
- * an invalid DOS 8.3 file name, the FAT volume has not been initialized,
- * a file is already open, the file already exists, the root
- * directory is full or an I/O error.
- *
- */
-uint8_t SdFile::createContiguous(SdFile* dirFile,
- const char* fileName, uint32_t size) {
- // don't allow zero length file
- if (size == 0) return false;
- if (!open(dirFile, fileName, O_CREAT | O_EXCL | O_RDWR)) return false;
-
- // calculate number of clusters needed
- uint32_t count = ((size - 1) >> (vol_->clusterSizeShift_ + 9)) + 1;
-
- // allocate clusters
- if (!vol_->allocContiguous(count, &firstCluster_)) {
- remove();
- return false;
- }
- fileSize_ = size;
-
- // insure sync() will update dir entry
- flags_ |= F_FILE_DIR_DIRTY;
- return sync();
-}
-//------------------------------------------------------------------------------
-/**
- * Return a files directory entry
- *
- * \param[out] dir Location for return of the files directory entry.
- *
- * \return The value one, true, is returned for success and
- * the value zero, false, is returned for failure.
- */
-uint8_t SdFile::dirEntry(dir_t* dir) {
- // make sure fields on SD are correct
- if (!sync()) return false;
-
- // read entry
- dir_t* p = cacheDirEntry(SdVolume::CACHE_FOR_READ);
- if (!p) return false;
-
- // copy to caller's struct
- memcpy(dir, p, sizeof(dir_t));
- return true;
-}
-//------------------------------------------------------------------------------
-/**
- * Format the name field of \a dir into the 13 byte array
- * \a name in standard 8.3 short name format.
- *
- * \param[in] dir The directory structure containing the name.
- * \param[out] name A 13 byte char array for the formatted name.
- */
-void SdFile::dirName(const dir_t& dir, char* name) {
- uint8_t j = 0;
- for (uint8_t i = 0; i < 11; i++) {
- if (dir.name[i] == ' ')continue;
- if (i == 8) name[j++] = '.';
- name[j++] = dir.name[i];
- }
- name[j] = 0;
-}
-//------------------------------------------------------------------------------
-/** List directory contents to Serial.
- *
- * \param[in] flags The inclusive OR of
- *
- * LS_DATE - %Print file modification date
- *
- * LS_SIZE - %Print file size.
- *
- * LS_R - Recursive list of subdirectories.
- *
- * \param[in] indent Amount of space before file name. Used for recursive
- * list to indicate subdirectory level.
- */
-void SdFile::ls(uint8_t flags, uint8_t indent) {
- dir_t* p;
-
- rewind();
- while ((p = readDirCache())) {
- // done if past last used entry
- if (p->name[0] == DIR_NAME_FREE) break;
-
- // skip deleted entry and entries for . and ..
- if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') continue;
-
- // only list subdirectories and files
- if (!DIR_IS_FILE_OR_SUBDIR(p)) continue;
-
- // print any indent spaces
- for (int8_t i = 0; i < indent; i++) SerialDebug.print(' ');
-
- // print file name with possible blank fill
- printDirName(*p, flags & (LS_DATE | LS_SIZE) ? 14 : 0);
-
- // print modify date/time if requested
- if (flags & LS_DATE) {
- printFatDate(p->lastWriteDate);
- SerialDebug.print(' ');
- printFatTime(p->lastWriteTime);
- }
- // print size if requested
- if (!DIR_IS_SUBDIR(p) && (flags & LS_SIZE)) {
- SerialDebug.print(' ');
- SerialDebug.print(p->fileSize);
- }
- SerialDebug.println();
-
- // list subdirectory content if requested
- if ((flags & LS_R) && DIR_IS_SUBDIR(p)) {
- uint16_t index = curPosition()/32 - 1;
- SdFile s;
- if (s.open(this, index, O_READ)) s.ls(flags, indent + 2);
- seekSet(32 * (index + 1));
- }
- }
-}
-//------------------------------------------------------------------------------
-// format directory name field from a 8.3 name string
-uint8_t SdFile::make83Name(const char* str, uint8_t* name) {
- uint8_t c;
- uint8_t n = 7; // max index for part before dot
- uint8_t i = 0;
- // blank fill name and extension
- while (i < 11) name[i++] = ' ';
- i = 0;
- while ((c = *str++) != '\0') {
- if (c == '.') {
- if (n == 10) return false; // only one dot allowed
- n = 10; // max index for full 8.3 name
- i = 8; // place for extension
- } else {
- // illegal FAT characters
-// PGM_P p = PSTR("|<>^+=?/[];,*\"\\");
- char p[17] = {"|<>^+=?/[];,*\"\\"};
- char *ptr = p;
- uint8_t b;
- while ((b = *(ptr++)))
- if (b == c)
- return false;
- // check size and only allow ASCII printable characters
- if (i > n || c < 0X21 || c > 0X7E)return false;
- // only upper case allowed in 8.3 names - convert lower to upper
- name[i++] = c < 'a' || c > 'z' ? c : c + ('A' - 'a');
- }
- }
- // must have a file name, extension is optional
- return name[0] != ' ';
-}
-//------------------------------------------------------------------------------
-/** Make a new directory.
- *
- * \param[in] dir An open SdFat instance for the directory that will containing
- * the new directory.
- *
- * \param[in] dirName A valid 8.3 DOS name for the new directory.
- *
- * \return The value one, true, is returned for success and
- * the value zero, false, is returned for failure.
- * Reasons for failure include this SdFile is already open, \a dir is not a
- * directory, \a dirName is invalid or already exists in \a dir.
- */
-uint8_t SdFile::makeDir(SdFile* dir, const char* dirName) {
- dir_t d;
-
- // create a normal file
- if (!open(dir, dirName, O_CREAT | O_EXCL | O_RDWR)) return false;
-
- // convert SdFile to directory
- flags_ = O_READ;
- type_ = FAT_FILE_TYPE_SUBDIR;
-
- // allocate and zero first cluster
- if (!addDirCluster())return false;
-
- // force entry to SD
- if (!sync()) return false;
-
- // cache entry - should already be in cache due to sync() call
- dir_t* p = cacheDirEntry(SdVolume::CACHE_FOR_WRITE);
- if (!p) return false;
-
- // change directory entry attribute
- p->attributes = DIR_ATT_DIRECTORY;
-
- // make entry for '.'
- memcpy(&d, p, sizeof(d));
- for (uint8_t i = 1; i < 11; i++) d.name[i] = ' ';
- d.name[0] = '.';
-
- // cache block for '.' and '..'
- uint32_t block = vol_->clusterStartBlock(firstCluster_);
- if (!SdVolume::cacheRawBlock(block, SdVolume::CACHE_FOR_WRITE)) return false;
-
- // copy '.' to block
- memcpy(&SdVolume::cacheBuffer_.dir[0], &d, sizeof(d));
-
- // make entry for '..'
- d.name[1] = '.';
- if (dir->isRoot()) {
- d.firstClusterLow = 0;
- d.firstClusterHigh = 0;
- } else {
- d.firstClusterLow = dir->firstCluster_ & 0XFFFF;
- d.firstClusterHigh = dir->firstCluster_ >> 16;
- }
- // copy '..' to block
- memcpy(&SdVolume::cacheBuffer_.dir[1], &d, sizeof(d));
-
- // set position after '..'
- curPosition_ = 2 * sizeof(d);
-
- // write first block
- return SdVolume::cacheFlush();
-}
-//------------------------------------------------------------------------------
-/**
- * Open a file or directory by name.
- *
- * \param[in] dirFile An open SdFat instance for the directory containing the
- * file to be opened.
- *
- * \param[in] fileName A valid 8.3 DOS name for a file to be opened.
- *
- * \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive
- * OR of flags from the following list
- *
- * O_READ - Open for reading.
- *
- * O_RDONLY - Same as O_READ.
- *
- * O_WRITE - Open for writing.
- *
- * O_WRONLY - Same as O_WRITE.
- *
- * O_RDWR - Open for reading and writing.
- *
- * O_APPEND - If set, the file offset shall be set to the end of the
- * file prior to each write.
- *
- * O_CREAT - If the file exists, this flag has no effect except as noted
- * under O_EXCL below. Otherwise, the file shall be created
- *
- * O_EXCL - If O_CREAT and O_EXCL are set, open() shall fail if the file exists.
- *
- * O_SYNC - Call sync() after each write. This flag should not be used with
- * write(uint8_t), write_P(PGM_P), writeln_P(PGM_P), or the Arduino Print class.
- * These functions do character at a time writes so sync() will be called
- * after each byte.
- *
- * O_TRUNC - If the file exists and is a regular file, and the file is
- * successfully opened and is not read only, its length shall be truncated to 0.
- *
- * \note Directory files must be opened read only. Write and truncation is
- * not allowed for directory files.
- *
- * \return The value one, true, is returned for success and
- * the value zero, false, is returned for failure.
- * Reasons for failure include this SdFile is already open, \a difFile is not
- * a directory, \a fileName is invalid, the file does not exist
- * or can't be opened in the access mode specified by oflag.
- */
-uint8_t SdFile::open(SdFile* dirFile, const char* fileName, uint8_t oflag) {
- uint8_t dname[11];
- dir_t* p;
-
- // error if already open
- if (isOpen())return false;
-
- if (!make83Name(fileName, dname)) return false;
- vol_ = dirFile->vol_;
- dirFile->rewind();
-
- // bool for empty entry found
- uint8_t emptyFound = false;
-
- // search for file
- while (dirFile->curPosition_ < dirFile->fileSize_) {
- uint8_t index = 0XF & (dirFile->curPosition_ >> 5);
- p = dirFile->readDirCache();
- if (p == NULL) return false;
-
- if (p->name[0] == DIR_NAME_FREE || p->name[0] == DIR_NAME_DELETED) {
- // remember first empty slot
- if (!emptyFound) {
- emptyFound = true;
- dirIndex_ = index;
- dirBlock_ = SdVolume::cacheBlockNumber_;
- }
- // done if no entries follow
- if (p->name[0] == DIR_NAME_FREE) break;
- } else if (!memcmp(dname, p->name, 11)) {
- // don't open existing file if O_CREAT and O_EXCL
- if ((oflag & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) return false;
-
- // open found file
- return openCachedEntry(0XF & index, oflag);
- }
- }
- // only create file if O_CREAT and O_WRITE
- if ((oflag & (O_CREAT | O_WRITE)) != (O_CREAT | O_WRITE)) return false;
-
- // cache found slot or add cluster if end of file
- if (emptyFound) {
- p = cacheDirEntry(SdVolume::CACHE_FOR_WRITE);
- if (!p) return false;
- } else {
- if (dirFile->type_ == FAT_FILE_TYPE_ROOT16) return false;
-
- // add and zero cluster for dirFile - first cluster is in cache for write
- if (!dirFile->addDirCluster()) return false;
-
- // use first entry in cluster
- dirIndex_ = 0;
- p = SdVolume::cacheBuffer_.dir;
- }
- // initialize as empty file
- memset(p, 0, sizeof(dir_t));
- memcpy(p->name, dname, 11);
-
- // set timestamps
- if (dateTime_) {
- // call user function
- dateTime_(&p->creationDate, &p->creationTime);
- } else {
- // use default date/time
- p->creationDate = FAT_DEFAULT_DATE;
- p->creationTime = FAT_DEFAULT_TIME;
- }
- p->lastAccessDate = p->creationDate;
- p->lastWriteDate = p->creationDate;
- p->lastWriteTime = p->creationTime;
-
- // force write of entry to SD
- if (!SdVolume::cacheFlush()) return false;
-
- // open entry in cache
- return openCachedEntry(dirIndex_, oflag);
-}
-//------------------------------------------------------------------------------
-/**
- * Open a file by index.
- *
- * \param[in] dirFile An open SdFat instance for the directory.
- *
- * \param[in] index The \a index of the directory entry for the file to be
- * opened. The value for \a index is (directory file position)/32.
- *
- * \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive
- * OR of flags O_READ, O_WRITE, O_TRUNC, and O_SYNC.
- *
- * See open() by fileName for definition of flags and return values.
- *
- */
-uint8_t SdFile::open(SdFile* dirFile, uint16_t index, uint8_t oflag) {
- // error if already open
- if (isOpen())return false;
-
- // don't open existing file if O_CREAT and O_EXCL - user call error
- if ((oflag & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) return false;
-
- vol_ = dirFile->vol_;
-
- // seek to location of entry
- if (!dirFile->seekSet(32 * index)) return false;
-
- // read entry into cache
- dir_t* p = dirFile->readDirCache();
- if (p == NULL) return false;
-
- // error if empty slot or '.' or '..'
- if (p->name[0] == DIR_NAME_FREE ||
- p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') {
- return false;
- }
- // open cached entry
- return openCachedEntry(index & 0XF, oflag);
-}
-//------------------------------------------------------------------------------
-// open a cached directory entry. Assumes vol_ is initializes
-uint8_t SdFile::openCachedEntry(uint8_t dirIndex, uint8_t oflag) {
- // location of entry in cache
- dir_t* p = SdVolume::cacheBuffer_.dir + dirIndex;
-
- // write or truncate is an error for a directory or read-only file
- if (p->attributes & (DIR_ATT_READ_ONLY | DIR_ATT_DIRECTORY)) {
- if (oflag & (O_WRITE | O_TRUNC)) return false;
- }
- // remember location of directory entry on SD
- dirIndex_ = dirIndex;
- dirBlock_ = SdVolume::cacheBlockNumber_;
-
- // copy first cluster number for directory fields
- firstCluster_ = (uint32_t)p->firstClusterHigh << 16;
- firstCluster_ |= p->firstClusterLow;
-
- // make sure it is a normal file or subdirectory
- if (DIR_IS_FILE(p)) {
- fileSize_ = p->fileSize;
- type_ = FAT_FILE_TYPE_NORMAL;
- } else if (DIR_IS_SUBDIR(p)) {
- if (!vol_->chainSize(firstCluster_, &fileSize_)) return false;
- type_ = FAT_FILE_TYPE_SUBDIR;
- } else {
- return false;
- }
- // save open flags for read/write
- flags_ = oflag & (O_ACCMODE | O_SYNC | O_APPEND);
-
- // set to start of file
- curCluster_ = 0;
- curPosition_ = 0;
-
- // truncate file to zero length if requested
- if (oflag & O_TRUNC) return truncate(0);
- return true;
-}
-//------------------------------------------------------------------------------
-/**
- * Open a volume's root directory.
- *
- * \param[in] vol The FAT volume containing the root directory to be opened.
- *
- * \return The value one, true, is returned for success and
- * the value zero, false, is returned for failure.
- * Reasons for failure include the FAT volume has not been initialized
- * or it a FAT12 volume.
- */
-uint8_t SdFile::openRoot(SdVolume* vol) {
- // error if file is already open
- if (isOpen()) return false;
-
- if (vol->fatType() == 16) {
- type_ = FAT_FILE_TYPE_ROOT16;
- firstCluster_ = 0;
- fileSize_ = 32 * vol->rootDirEntryCount();
- } else if (vol->fatType() == 32) {
- type_ = FAT_FILE_TYPE_ROOT32;
- firstCluster_ = vol->rootDirStart();
- if (!vol->chainSize(firstCluster_, &fileSize_)) return false;
- } else {
- // volume is not initialized or FAT12
- return false;
- }
- vol_ = vol;
- // read only
- flags_ = O_READ;
-
- // set to start of file
- curCluster_ = 0;
- curPosition_ = 0;
-
- // root has no directory entry
- dirBlock_ = 0;
- dirIndex_ = 0;
- return true;
-}
-//------------------------------------------------------------------------------
-/** %Print the name field of a directory entry in 8.3 format to Serial.
- *
- * \param[in] dir The directory structure containing the name.
- * \param[in] width Blank fill name if length is less than \a width.
- */
-void SdFile::printDirName(const dir_t& dir, uint8_t width) {
- uint8_t w = 0;
- for (uint8_t i = 0; i < 11; i++) {
- if (dir.name[i] == ' ')continue;
- if (i == 8) {
- SerialDebug.print('.');
- w++;
- }
- SerialDebug.print((char)dir.name[i]);
- w++;
- }
- if (DIR_IS_SUBDIR(&dir)) {
- SerialDebug.print('/');
- w++;
- }
- while (w < width) {
- SerialDebug.print(' ');
- w++;
- }
-}
-//------------------------------------------------------------------------------
-/** %Print a directory date field to Serial.
- *
- * Format is yyyy-mm-dd.
- *
- * \param[in] fatDate The date field from a directory entry.
- */
-void SdFile::printFatDate(uint16_t fatDate) {
- SerialDebug.print(FAT_YEAR(fatDate));
- SerialDebug.print('-');
- printTwoDigits(FAT_MONTH(fatDate));
- SerialDebug.print('-');
- printTwoDigits(FAT_DAY(fatDate));
-}
-//------------------------------------------------------------------------------
-/** %Print a directory time field to Serial.
- *
- * Format is hh:mm:ss.
- *
- * \param[in] fatTime The time field from a directory entry.
- */
-void SdFile::printFatTime(uint16_t fatTime) {
- printTwoDigits(FAT_HOUR(fatTime));
- SerialDebug.print(':');
- printTwoDigits(FAT_MINUTE(fatTime));
- SerialDebug.print(':');
- printTwoDigits(FAT_SECOND(fatTime));
-}
-//------------------------------------------------------------------------------
-/** %Print a value as two digits to Serial.
- *
- * \param[in] v Value to be printed, 0 <= \a v <= 99
- */
-void SdFile::printTwoDigits(uint8_t v) {
- char str[3];
- str[0] = '0' + v/10;
- str[1] = '0' + v % 10;
- str[2] = 0;
- SerialDebug.print(str);
-}
-//------------------------------------------------------------------------------
-/**
- * Read data from a file starting at the current position.
- *
- * \param[out] buf Pointer to the location that will receive the data.
- *
- * \param[in] nbyte Maximum number of bytes to read.
- *
- * \return For success read() returns the number of bytes read.
- * A value less than \a nbyte, including zero, will be returned
- * if end of file is reached.
- * If an error occurs, read() returns -1. Possible errors include
- * read() called before a file has been opened, corrupt file system
- * or an I/O error occurred.
- */
-int16_t SdFile::read(void* buf, uint16_t nbyte) {
- uint8_t* dst = reinterpret_cast(buf);
-
- // error if not open or write only
- if (!isOpen() || !(flags_ & O_READ)) return -1;
-
- // max bytes left in file
- if (nbyte > (fileSize_ - curPosition_)) nbyte = fileSize_ - curPosition_;
-
- // amount left to read
- uint16_t toRead = nbyte;
- while (toRead > 0) {
- uint32_t block; // raw device block number
- uint16_t offset = curPosition_ & 0X1FF; // offset in block
- if (type_ == FAT_FILE_TYPE_ROOT16) {
- block = vol_->rootDirStart() + (curPosition_ >> 9);
- } else {
- uint8_t blockOfCluster = vol_->blockOfCluster(curPosition_);
- if (offset == 0 && blockOfCluster == 0) {
- // start of new cluster
- if (curPosition_ == 0) {
- // use first cluster in file
- curCluster_ = firstCluster_;
- } else {
- // get next cluster from FAT
- if (!vol_->fatGet(curCluster_, &curCluster_)) return -1;
- }
- }
- block = vol_->clusterStartBlock(curCluster_) + blockOfCluster;
- }
- uint16_t n = toRead;
-
- // amount to be read from current block
- if (n > (512 - offset)) n = 512 - offset;
-
-#if 0
- SerialDebug.print("block ");
- SerialDebug.print(block);
- SerialDebug.print(" n ");
- SerialDebug.println(n);
-#endif
- // no buffering needed if n == 512 or user requests no buffering
- if ((unbufferedRead() || n == 512) && block != SdVolume::cacheBlockNumber_) {
- if (!vol_->readData(block, offset, n, dst)) return -1;
- dst += n;
- } else {
- // read block to cache and copy data to caller
- if (!SdVolume::cacheRawBlock(block, SdVolume::CACHE_FOR_READ)) return -1;
- uint8_t* src = SdVolume::cacheBuffer_.data + offset;
- uint8_t* end = src + n;
- while (src != end) *dst++ = *src++;
- }
- curPosition_ += n;
- toRead -= n;
- }
- return nbyte;
-}
-//------------------------------------------------------------------------------
-/**
- * Read the next directory entry from a directory file.
- *
- * \param[out] dir The dir_t struct that will receive the data.
- *
- * \return For success readDir() returns the number of bytes read.
- * A value of zero will be returned if end of file is reached.
- * If an error occurs, readDir() returns -1. Possible errors include
- * readDir() called before a directory has been opened, this is not
- * a directory file or an I/O error occurred.
- */
-int8_t SdFile::readDir(dir_t* dir) {
- int8_t n;
- // if not a directory file or miss-positioned return an error
- if (!isDir() || (0X1F & curPosition_)) return -1;
-
- while ((n = read(dir, sizeof(dir_t))) == sizeof(dir_t)) {
- // last entry if DIR_NAME_FREE
- if (dir->name[0] == DIR_NAME_FREE) break;
- // skip empty entries and entry for . and ..
- if (dir->name[0] == DIR_NAME_DELETED || dir->name[0] == '.') continue;
- // return if normal file or subdirectory
- if (DIR_IS_FILE_OR_SUBDIR(dir)) return n;
- }
- // error, end of file, or past last entry
- return n < 0 ? -1 : 0;
-}
-//------------------------------------------------------------------------------
-// Read next directory entry into the cache
-// Assumes file is correctly positioned
-dir_t* SdFile::readDirCache(void) {
- // error if not directory
- if (!isDir()) return NULL;
-
- // index of entry in cache
- uint8_t i = (curPosition_ >> 5) & 0XF;
-
- // use read to locate and cache block
- if (read() < 0) return NULL;
-
- // advance to next entry
- curPosition_ += 31;
-
- // return pointer to entry
- return (SdVolume::cacheBuffer_.dir + i);
-}
-//------------------------------------------------------------------------------
-/**
- * Remove a file.
- *
- * The directory entry and all data for the file are deleted.
- *
- * \note This function should not be used to delete the 8.3 version of a
- * file that has a long name. For example if a file has the long name
- * "New Text Document.txt" you should not delete the 8.3 name "NEWTEX~1.TXT".
- *
- * \return The value one, true, is returned for success and
- * the value zero, false, is returned for failure.
- * Reasons for failure include the file read-only, is a directory,
- * or an I/O error occurred.
- */
-uint8_t SdFile::remove(void) {
- // free any clusters - will fail if read-only or directory
- if (!truncate(0)) return false;
-
- // cache directory entry
- dir_t* d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE);
- if (!d) return false;
-
- // mark entry deleted
- d->name[0] = DIR_NAME_DELETED;
-
- // set this SdFile closed
- type_ = FAT_FILE_TYPE_CLOSED;
-
- // write entry to SD
- return SdVolume::cacheFlush();
-}
-//------------------------------------------------------------------------------
-/**
- * Remove a file.
- *
- * The directory entry and all data for the file are deleted.
- *
- * \param[in] dirFile The directory that contains the file.
- * \param[in] fileName The name of the file to be removed.
- *
- * \note This function should not be used to delete the 8.3 version of a
- * file that has a long name. For example if a file has the long name
- * "New Text Document.txt" you should not delete the 8.3 name "NEWTEX~1.TXT".
- *
- * \return The value one, true, is returned for success and
- * the value zero, false, is returned for failure.
- * Reasons for failure include the file is a directory, is read only,
- * \a dirFile is not a directory, \a fileName is not found
- * or an I/O error occurred.
- */
-uint8_t SdFile::remove(SdFile* dirFile, const char* fileName) {
- SdFile file;
- if (!file.open(dirFile, fileName, O_WRITE)) return false;
- return file.remove();
-}
-//------------------------------------------------------------------------------
-/** Remove a directory file.
- *
- * The directory file will be removed only if it is empty and is not the
- * root directory. rmDir() follows DOS and Windows and ignores the
- * read-only attribute for the directory.
- *
- * \note This function should not be used to delete the 8.3 version of a
- * directory that has a long name. For example if a directory has the
- * long name "New folder" you should not delete the 8.3 name "NEWFOL~1".
- *
- * \return The value one, true, is returned for success and
- * the value zero, false, is returned for failure.
- * Reasons for failure include the file is not a directory, is the root
- * directory, is not empty, or an I/O error occurred.
- */
-uint8_t SdFile::rmDir(void) {
- // must be open subdirectory
- if (!isSubDir()) return false;
-
- rewind();
-
- // make sure directory is empty
- while (curPosition_ < fileSize_) {
- dir_t* p = readDirCache();
- if (p == NULL) return false;
- // done if past last used entry
- if (p->name[0] == DIR_NAME_FREE) break;
- // skip empty slot or '.' or '..'
- if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') continue;
- // error not empty
- if (DIR_IS_FILE_OR_SUBDIR(p)) return false;
- }
- // convert empty directory to normal file for remove
- type_ = FAT_FILE_TYPE_NORMAL;
- flags_ |= O_WRITE;
- return remove();
-}
-//------------------------------------------------------------------------------
-/** Recursively delete a directory and all contained files.
- *
- * This is like the Unix/Linux 'rm -rf *' if called with the root directory
- * hence the name.
- *
- * Warning - This will remove all contents of the directory including
- * subdirectories. The directory will then be removed if it is not root.
- * The read-only attribute for files will be ignored.
- *
- * \note This function should not be used to delete the 8.3 version of
- * a directory that has a long name. See remove() and rmDir().
- *
- * \return The value one, true, is returned for success and
- * the value zero, false, is returned for failure.
- */
-uint8_t SdFile::rmRfStar(void) {
- rewind();
- while (curPosition_ < fileSize_) {
- SdFile f;
-
- // remember position
- uint16_t index = curPosition_/32;
-
- dir_t* p = readDirCache();
- if (!p) return false;
-
- // done if past last entry
- if (p->name[0] == DIR_NAME_FREE) break;
-
- // skip empty slot or '.' or '..'
- if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') continue;
-
- // skip if part of long file name or volume label in root
- if (!DIR_IS_FILE_OR_SUBDIR(p)) continue;
-
- if (!f.open(this, index, O_READ)) return false;
- if (f.isSubDir()) {
- // recursively delete
- if (!f.rmRfStar()) return false;
- } else {
- // ignore read-only
- f.flags_ |= O_WRITE;
- if (!f.remove()) return false;
- }
- // position to next entry if required
- if (curPosition_ != (32*(index + 1))) {
- if (!seekSet(32*(index + 1))) return false;
- }
- }
- // don't try to delete root
- if (isRoot()) return true;
- return rmDir();
-}
-//------------------------------------------------------------------------------
-/**
- * Sets a file's position.
- *
- * \param[in] pos The new position in bytes from the beginning of the file.
- *
- * \return The value one, true, is returned for success and
- * the value zero, false, is returned for failure.
- */
-uint8_t SdFile::seekSet(uint32_t pos) {
- // error if file not open or seek past end of file
- if (!isOpen() || pos > fileSize_) return false;
-
- if (type_ == FAT_FILE_TYPE_ROOT16) {
- curPosition_ = pos;
- return true;
- }
- if (pos == 0) {
- // set position to start of file
- curCluster_ = 0;
- curPosition_ = 0;
- return true;
- }
- // calculate cluster index for cur and new position
- uint32_t nCur = (curPosition_ - 1) >> (vol_->clusterSizeShift_ + 9);
- uint32_t nNew = (pos - 1) >> (vol_->clusterSizeShift_ + 9);
-
- if (nNew < nCur || curPosition_ == 0) {
- // must follow chain from first cluster
- curCluster_ = firstCluster_;
- } else {
- // advance from curPosition
- nNew -= nCur;
- }
- while (nNew--) {
- if (!vol_->fatGet(curCluster_, &curCluster_)) return false;
- }
- curPosition_ = pos;
- return true;
-}
-//------------------------------------------------------------------------------
-/**
- * The sync() call causes all modified data and directory fields
- * to be written to the storage device.
- *
- * \return The value one, true, is returned for success and
- * the value zero, false, is returned for failure.
- * Reasons for failure include a call to sync() before a file has been
- * opened or an I/O error.
- */
-uint8_t SdFile::sync(void) {
- // only allow open files and directories
- if (!isOpen()) return false;
-
- if (flags_ & F_FILE_DIR_DIRTY) {
- dir_t* d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE);
- if (!d) return false;
-
- // do not set filesize for dir files
- if (!isDir()) d->fileSize = fileSize_;
-
- // update first cluster fields
- d->firstClusterLow = firstCluster_ & 0XFFFF;
- d->firstClusterHigh = firstCluster_ >> 16;
-
- // set modify time if user supplied a callback date/time function
- if (dateTime_) {
- dateTime_(&d->lastWriteDate, &d->lastWriteTime);
- d->lastAccessDate = d->lastWriteDate;
- }
- // clear directory dirty
- flags_ &= ~F_FILE_DIR_DIRTY;
- }
- return SdVolume::cacheFlush();
-}
-//------------------------------------------------------------------------------
-/**
- * Set a file's timestamps in its directory entry.
- *
- * \param[in] flags Values for \a flags are constructed by a bitwise-inclusive
- * OR of flags from the following list
- *
- * T_ACCESS - Set the file's last access date.
- *
- * T_CREATE - Set the file's creation date and time.
- *
- * T_WRITE - Set the file's last write/modification date and time.
- *
- * \param[in] year Valid range 1980 - 2107 inclusive.
- *
- * \param[in] month Valid range 1 - 12 inclusive.
- *
- * \param[in] day Valid range 1 - 31 inclusive.
- *
- * \param[in] hour Valid range 0 - 23 inclusive.
- *
- * \param[in] minute Valid range 0 - 59 inclusive.
- *
- * \param[in] second Valid range 0 - 59 inclusive
- *
- * \note It is possible to set an invalid date since there is no check for
- * the number of days in a month.
- *
- * \note
- * Modify and access timestamps may be overwritten if a date time callback
- * function has been set by dateTimeCallback().
- *
- * \return The value one, true, is returned for success and
- * the value zero, false, is returned for failure.
- */
-uint8_t SdFile::timestamp(uint8_t flags, uint16_t year, uint8_t month,
- uint8_t day, uint8_t hour, uint8_t minute, uint8_t second) {
- if (!isOpen()
- || year < 1980
- || year > 2107
- || month < 1
- || month > 12
- || day < 1
- || day > 31
- || hour > 23
- || minute > 59
- || second > 59) {
- return false;
- }
- dir_t* d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE);
- if (!d) return false;
-
- uint16_t dirDate = FAT_DATE(year, month, day);
- uint16_t dirTime = FAT_TIME(hour, minute, second);
- if (flags & T_ACCESS) {
- d->lastAccessDate = dirDate;
- }
- if (flags & T_CREATE) {
- d->creationDate = dirDate;
- d->creationTime = dirTime;
- // seems to be units of 1/100 second not 1/10 as Microsoft states
- d->creationTimeTenths = second & 1 ? 100 : 0;
- }
- if (flags & T_WRITE) {
- d->lastWriteDate = dirDate;
- d->lastWriteTime = dirTime;
- }
- SdVolume::cacheSetDirty();
- return sync();
-}
-//------------------------------------------------------------------------------
-/**
- * Truncate a file to a specified length. The current file position
- * will be maintained if it is less than or equal to \a length otherwise
- * it will be set to end of file.
- *
- * \param[in] length The desired length for the file.
- *
- * \return The value one, true, is returned for success and
- * the value zero, false, is returned for failure.
- * Reasons for failure include file is read only, file is a directory,
- * \a length is greater than the current file size or an I/O error occurs.
- */
-uint8_t SdFile::truncate(uint32_t length) {
-// error if not a normal file or read-only
- if (!isFile() || !(flags_ & O_WRITE)) return false;
-
- // error if length is greater than current size
- if (length > fileSize_) return false;
-
- // fileSize and length are zero - nothing to do
- if (fileSize_ == 0) return true;
-
- // remember position for seek after truncation
- uint32_t newPos = curPosition_ > length ? length : curPosition_;
-
- // position to last cluster in truncated file
- if (!seekSet(length)) return false;
-
- if (length == 0) {
- // free all clusters
- if (!vol_->freeChain(firstCluster_)) return false;
- firstCluster_ = 0;
- } else {
- uint32_t toFree;
- if (!vol_->fatGet(curCluster_, &toFree)) return false;
-
- if (!vol_->isEOC(toFree)) {
- // free extra clusters
- if (!vol_->freeChain(toFree)) return false;
-
- // current cluster is end of chain
- if (!vol_->fatPutEOC(curCluster_)) return false;
- }
- }
- fileSize_ = length;
-
- // need to update directory entry
- flags_ |= F_FILE_DIR_DIRTY;
-
- if (!sync()) return false;
-
- // set file to correct position
- return seekSet(newPos);
-}
-//------------------------------------------------------------------------------
-/**
- * Write data to an open file.
- *
- * \note Data is moved to the cache but may not be written to the
- * storage device until sync() is called.
- *
- * \param[in] buf Pointer to the location of the data to be written.
- *
- * \param[in] nbyte Number of bytes to write.
- *
- * \return For success write() returns the number of bytes written, always
- * \a nbyte. If an error occurs, write() returns -1. Possible errors
- * include write() is called before a file has been opened, write is called
- * for a read-only file, device is full, a corrupt file system or an I/O error.
- *
- */
-int16_t SdFile::write(const void* buf, uint16_t nbyte) {
- // convert void* to uint8_t* - must be before goto statements
- const uint8_t* src = reinterpret_cast(buf);
-
- // number of bytes left to write - must be before goto statements
- uint16_t nToWrite = nbyte;
-
- // error if not a normal file or is read-only
- if (!isFile() || !(flags_ & O_WRITE)) goto writeErrorReturn;
-
- // seek to end of file if append flag
- if ((flags_ & O_APPEND) && curPosition_ != fileSize_) {
- if (!seekEnd()) goto writeErrorReturn;
- }
-
- while (nToWrite > 0) {
- uint8_t blockOfCluster = vol_->blockOfCluster(curPosition_);
- uint16_t blockOffset = curPosition_ & 0X1FF;
- if (blockOfCluster == 0 && blockOffset == 0) {
- // start of new cluster
- if (curCluster_ == 0) {
- if (firstCluster_ == 0) {
- // allocate first cluster of file
- if (!addCluster()) goto writeErrorReturn;
- } else {
- curCluster_ = firstCluster_;
- }
- } else {
- uint32_t next;
- if (!vol_->fatGet(curCluster_, &next)) return false;
- if (vol_->isEOC(next)) {
- // add cluster if at end of chain
- if (!addCluster()) goto writeErrorReturn;
- } else {
- curCluster_ = next;
- }
- }
- }
- // max space in block
- uint16_t n = 512 - blockOffset;
-
- // lesser of space and amount to write
- if (n > nToWrite) n = nToWrite;
-
- // block for data write
- uint32_t block = vol_->clusterStartBlock(curCluster_) + blockOfCluster;
- if (n == 512) {
- // full block - don't need to use cache
- // invalidate cache if block is in cache
- if (SdVolume::cacheBlockNumber_ == block) {
- SdVolume::cacheBlockNumber_ = 0XFFFFFFFF;
- }
- if (!vol_->writeBlock(block, src)) goto writeErrorReturn;
- src += 512;
- } else {
- if (blockOffset == 0 && curPosition_ >= fileSize_) {
- // start of new block don't need to read into cache
- if (!SdVolume::cacheFlush()) goto writeErrorReturn;
- SdVolume::cacheBlockNumber_ = block;
- SdVolume::cacheSetDirty();
- } else {
- // rewrite part of block
- if (!SdVolume::cacheRawBlock(block, SdVolume::CACHE_FOR_WRITE)) {
- goto writeErrorReturn;
- }
- }
- uint8_t* dst = SdVolume::cacheBuffer_.data + blockOffset;
- uint8_t* end = dst + n;
- while (dst != end) *dst++ = *src++;
- }
- nToWrite -= n;
- curPosition_ += n;
- }
- if (curPosition_ > fileSize_) {
- // update fileSize and insure sync will update dir entry
- fileSize_ = curPosition_;
- flags_ |= F_FILE_DIR_DIRTY;
- } else if (dateTime_ && nbyte) {
- // insure sync will update modified date and time
- flags_ |= F_FILE_DIR_DIRTY;
- }
-
- if (flags_ & O_SYNC) {
- if (!sync()) goto writeErrorReturn;
- }
- return nbyte;
-
- writeErrorReturn:
- // return for write error
- writeError = true;
- return -1;
-}
-//------------------------------------------------------------------------------
-/**
- * Write a byte to a file. Required by the Arduino Print class.
- *
- * Use SdFile::writeError to check for errors.
- */
-void SdFile::write(uint8_t b) {
- write(&b, 1);
-}
-//------------------------------------------------------------------------------
-/**
- * Write a string to a file. Used by the Arduino Print class.
- *
- * Use SdFile::writeError to check for errors.
- */
-void SdFile::write(const char* str) {
- write(str, strlen(str));
-}
-//------------------------------------------------------------------------------
-/**
- * Write a PROGMEM string to a file.
- *
- * Use SdFile::writeError to check for errors.
-
-void SdFile::write_P(PGM_P str) {
- for (uint8_t c; (c = pgm_read_byte(str)); str++) write(c);
-}
-*/
-//------------------------------------------------------------------------------
-/**
- * Write a PROGMEM string followed by CR/LF to a file.
- *
- * Use SdFile::writeError to check for errors.
-
-void SdFile::writeln_P(PGM_P str) {
- write_P(str);
- println();
-}
+/* Arduino SdFat Library
+ * Copyright (C) 2009 by William Greiman
+ *
+ * This file is part of the Arduino SdFat Library
+ *
+ * This Library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Arduino SdFat Library. If not, see
+ * .
+ */
+#include
+#include "SdFat.h"
+//#include
+#include
+#include "HardwareSPI.h"
+#include
+
+//------------------------------------------------------------------------------
+// callback function for date/time
+void (*SdFile::dateTime_)(uint16_t* date, uint16_t* time) = NULL;
+
+#if ALLOW_DEPRECATED_FUNCTIONS
+// suppress cpplint warnings with NOLINT comment
+void (*SdFile::oldDateTime_)(uint16_t& date, uint16_t& time) = NULL; // NOLINT
+#endif // ALLOW_DEPRECATED_FUNCTIONS
+//------------------------------------------------------------------------------
+// add a cluster to a file
+uint8_t SdFile::addCluster() {
+ if (!vol_->allocContiguous(1, &curCluster_)) return false;
+
+ // if first cluster of file link to directory entry
+ if (firstCluster_ == 0) {
+ firstCluster_ = curCluster_;
+ flags_ |= F_FILE_DIR_DIRTY;
+ }
+ return true;
+}
+//------------------------------------------------------------------------------
+// Add a cluster to a directory file and zero the cluster.
+// return with first block of cluster in the cache
+uint8_t SdFile::addDirCluster(void) {
+ if (!addCluster()) return false;
+
+ // zero data in cluster insure first cluster is in cache
+ uint32_t block = vol_->clusterStartBlock(curCluster_);
+ for (uint8_t i = vol_->blocksPerCluster_; i != 0; i--) {
+ if (!SdVolume::cacheZeroBlock(block + i - 1)) return false;
+ }
+ // Increase directory file size by cluster size
+ fileSize_ += 512UL << vol_->clusterSizeShift_;
+ return true;
+}
+//------------------------------------------------------------------------------
+// cache a file's directory entry
+// return pointer to cached entry or null for failure
+dir_t* SdFile::cacheDirEntry(uint8_t action) {
+ if (!SdVolume::cacheRawBlock(dirBlock_, action)) return NULL;
+ return SdVolume::cacheBuffer_.dir + dirIndex_;
+}
+//------------------------------------------------------------------------------
+/**
+ * Close a file and force cached data and directory information
+ * to be written to the storage device.
+ *
+ * \return The value one, true, is returned for success and
+ * the value zero, false, is returned for failure.
+ * Reasons for failure include no file is open or an I/O error.
+ */
+uint8_t SdFile::close(void) {
+ if (!sync())return false;
+ type_ = FAT_FILE_TYPE_CLOSED;
+ return true;
+}
+//------------------------------------------------------------------------------
+/**
+ * Check for contiguous file and return its raw block range.
+ *
+ * \param[out] bgnBlock the first block address for the file.
+ * \param[out] endBlock the last block address for the file.
+ *
+ * \return The value one, true, is returned for success and
+ * the value zero, false, is returned for failure.
+ * Reasons for failure include file is not contiguous, file has zero length
+ * or an I/O error occurred.
+ */
+uint8_t SdFile::contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock) {
+ // error if no blocks
+ if (firstCluster_ == 0) return false;
+
+ for (uint32_t c = firstCluster_; ; c++) {
+ uint32_t next;
+ if (!vol_->fatGet(c, &next)) return false;
+
+ // check for contiguous
+ if (next != (c + 1)) {
+ // error if not end of chain
+ if (!vol_->isEOC(next)) return false;
+ *bgnBlock = vol_->clusterStartBlock(firstCluster_);
+ *endBlock = vol_->clusterStartBlock(c)
+ + vol_->blocksPerCluster_ - 1;
+ return true;
+ }
+ }
+}
+//------------------------------------------------------------------------------
+/**
+ * Create and open a new contiguous file of a specified size.
+ *
+ * \note This function only supports short DOS 8.3 names.
+ * See open() for more information.
+ *
+ * \param[in] dirFile The directory where the file will be created.
+ * \param[in] fileName A valid DOS 8.3 file name.
+ * \param[in] size The desired file size.
+ *
+ * \return The value one, true, is returned for success and
+ * the value zero, false, is returned for failure.
+ * Reasons for failure include \a fileName contains
+ * an invalid DOS 8.3 file name, the FAT volume has not been initialized,
+ * a file is already open, the file already exists, the root
+ * directory is full or an I/O error.
+ *
+ */
+uint8_t SdFile::createContiguous(SdFile* dirFile,
+ const char* fileName, uint32_t size) {
+ // don't allow zero length file
+ if (size == 0) return false;
+ if (!open(dirFile, fileName, O_CREAT | O_EXCL | O_RDWR)) return false;
+
+ // calculate number of clusters needed
+ uint32_t count = ((size - 1) >> (vol_->clusterSizeShift_ + 9)) + 1;
+
+ // allocate clusters
+ if (!vol_->allocContiguous(count, &firstCluster_)) {
+ remove();
+ return false;
+ }
+ fileSize_ = size;
+
+ // insure sync() will update dir entry
+ flags_ |= F_FILE_DIR_DIRTY;
+ return sync();
+}
+//------------------------------------------------------------------------------
+/**
+ * Return a files directory entry
+ *
+ * \param[out] dir Location for return of the files directory entry.
+ *
+ * \return The value one, true, is returned for success and
+ * the value zero, false, is returned for failure.
+ */
+uint8_t SdFile::dirEntry(dir_t* dir) {
+ // make sure fields on SD are correct
+ if (!sync()) return false;
+
+ // read entry
+ dir_t* p = cacheDirEntry(SdVolume::CACHE_FOR_READ);
+ if (!p) return false;
+
+ // copy to caller's struct
+ memcpy(dir, p, sizeof(dir_t));
+ return true;
+}
+//------------------------------------------------------------------------------
+/**
+ * Format the name field of \a dir into the 13 byte array
+ * \a name in standard 8.3 short name format.
+ *
+ * \param[in] dir The directory structure containing the name.
+ * \param[out] name A 13 byte char array for the formatted name.
+ */
+void SdFile::dirName(const dir_t& dir, char* name) {
+ uint8_t j = 0;
+ for (uint8_t i = 0; i < 11; i++) {
+ if (dir.name[i] == ' ')continue;
+ if (i == 8) name[j++] = '.';
+ name[j++] = dir.name[i];
+ }
+ name[j] = 0;
+}
+//------------------------------------------------------------------------------
+/** List directory contents to Serial.
+ *
+ * \param[in] flags The inclusive OR of
+ *
+ * LS_DATE - %Print file modification date
+ *
+ * LS_SIZE - %Print file size.
+ *
+ * LS_R - Recursive list of subdirectories.
+ *
+ * \param[in] indent Amount of space before file name. Used for recursive
+ * list to indicate subdirectory level.
+ */
+void SdFile::ls(uint8_t flags, uint8_t indent) {
+ dir_t* p;
+
+ rewind();
+ while ((p = readDirCache())) {
+ // done if past last used entry
+ if (p->name[0] == DIR_NAME_FREE) break;
+
+ // skip deleted entry and entries for . and ..
+ if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') continue;
+
+ // only list subdirectories and files
+ if (!DIR_IS_FILE_OR_SUBDIR(p)) continue;
+
+ // print any indent spaces
+ for (int8_t i = 0; i < indent; i++) SerialDebug.print(' ');
+
+ // print file name with possible blank fill
+ printDirName(*p, flags & (LS_DATE | LS_SIZE) ? 14 : 0);
+
+ // print modify date/time if requested
+ if (flags & LS_DATE) {
+ printFatDate(p->lastWriteDate);
+ SerialDebug.print(' ');
+ printFatTime(p->lastWriteTime);
+ }
+ // print size if requested
+ if (!DIR_IS_SUBDIR(p) && (flags & LS_SIZE)) {
+ SerialDebug.print(' ');
+ SerialDebug.print(p->fileSize);
+ }
+ SerialDebug.println();
+
+ // list subdirectory content if requested
+ if ((flags & LS_R) && DIR_IS_SUBDIR(p)) {
+ uint16_t index = curPosition()/32 - 1;
+ SdFile s;
+ if (s.open(this, index, O_READ)) s.ls(flags, indent + 2);
+ seekSet(32 * (index + 1));
+ }
+ }
+}
+//------------------------------------------------------------------------------
+// format directory name field from a 8.3 name string
+uint8_t SdFile::make83Name(const char* str, uint8_t* name) {
+ uint8_t c;
+ uint8_t n = 7; // max index for part before dot
+ uint8_t i = 0;
+ // blank fill name and extension
+ while (i < 11) name[i++] = ' ';
+ i = 0;
+ while ((c = *str++) != '\0') {
+ if (c == '.') {
+ if (n == 10) return false; // only one dot allowed
+ n = 10; // max index for full 8.3 name
+ i = 8; // place for extension
+ } else {
+ // illegal FAT characters
+// PGM_P p = PSTR("|<>^+=?/[];,*\"\\");
+ char p[17] = {"|<>^+=?/[];,*\"\\"};
+ char *ptr = p;
+ uint8_t b;
+ while ((b = *(ptr++)))
+ if (b == c)
+ return false;
+ // check size and only allow ASCII printable characters
+ if (i > n || c < 0X21 || c > 0X7E)return false;
+ // only upper case allowed in 8.3 names - convert lower to upper
+ name[i++] = c < 'a' || c > 'z' ? c : c + ('A' - 'a');
+ }
+ }
+ // must have a file name, extension is optional
+ return name[0] != ' ';
+}
+//------------------------------------------------------------------------------
+/** Make a new directory.
+ *
+ * \param[in] dir An open SdFat instance for the directory that will containing
+ * the new directory.
+ *
+ * \param[in] dirName A valid 8.3 DOS name for the new directory.
+ *
+ * \return The value one, true, is returned for success and
+ * the value zero, false, is returned for failure.
+ * Reasons for failure include this SdFile is already open, \a dir is not a
+ * directory, \a dirName is invalid or already exists in \a dir.
+ */
+uint8_t SdFile::makeDir(SdFile* dir, const char* dirName) {
+ dir_t d;
+
+ // create a normal file
+ if (!open(dir, dirName, O_CREAT | O_EXCL | O_RDWR)) return false;
+
+ // convert SdFile to directory
+ flags_ = O_READ;
+ type_ = FAT_FILE_TYPE_SUBDIR;
+
+ // allocate and zero first cluster
+ if (!addDirCluster())return false;
+
+ // force entry to SD
+ if (!sync()) return false;
+
+ // cache entry - should already be in cache due to sync() call
+ dir_t* p = cacheDirEntry(SdVolume::CACHE_FOR_WRITE);
+ if (!p) return false;
+
+ // change directory entry attribute
+ p->attributes = DIR_ATT_DIRECTORY;
+
+ // make entry for '.'
+ memcpy(&d, p, sizeof(d));
+ for (uint8_t i = 1; i < 11; i++) d.name[i] = ' ';
+ d.name[0] = '.';
+
+ // cache block for '.' and '..'
+ uint32_t block = vol_->clusterStartBlock(firstCluster_);
+ if (!SdVolume::cacheRawBlock(block, SdVolume::CACHE_FOR_WRITE)) return false;
+
+ // copy '.' to block
+ memcpy(&SdVolume::cacheBuffer_.dir[0], &d, sizeof(d));
+
+ // make entry for '..'
+ d.name[1] = '.';
+ if (dir->isRoot()) {
+ d.firstClusterLow = 0;
+ d.firstClusterHigh = 0;
+ } else {
+ d.firstClusterLow = dir->firstCluster_ & 0XFFFF;
+ d.firstClusterHigh = dir->firstCluster_ >> 16;
+ }
+ // copy '..' to block
+ memcpy(&SdVolume::cacheBuffer_.dir[1], &d, sizeof(d));
+
+ // set position after '..'
+ curPosition_ = 2 * sizeof(d);
+
+ // write first block
+ return SdVolume::cacheFlush();
+}
+//------------------------------------------------------------------------------
+/**
+ * Open a file or directory by name.
+ *
+ * \param[in] dirFile An open SdFat instance for the directory containing the
+ * file to be opened.
+ *
+ * \param[in] fileName A valid 8.3 DOS name for a file to be opened.
+ *
+ * \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive
+ * OR of flags from the following list
+ *
+ * O_READ - Open for reading.
+ *
+ * O_RDONLY - Same as O_READ.
+ *
+ * O_WRITE - Open for writing.
+ *
+ * O_WRONLY - Same as O_WRITE.
+ *
+ * O_RDWR - Open for reading and writing.
+ *
+ * O_APPEND - If set, the file offset shall be set to the end of the
+ * file prior to each write.
+ *
+ * O_CREAT - If the file exists, this flag has no effect except as noted
+ * under O_EXCL below. Otherwise, the file shall be created
+ *
+ * O_EXCL - If O_CREAT and O_EXCL are set, open() shall fail if the file exists.
+ *
+ * O_SYNC - Call sync() after each write. This flag should not be used with
+ * write(uint8_t), write_P(PGM_P), writeln_P(PGM_P), or the Arduino Print class.
+ * These functions do character at a time writes so sync() will be called
+ * after each byte.
+ *
+ * O_TRUNC - If the file exists and is a regular file, and the file is
+ * successfully opened and is not read only, its length shall be truncated to 0.
+ *
+ * \note Directory files must be opened read only. Write and truncation is
+ * not allowed for directory files.
+ *
+ * \return The value one, true, is returned for success and
+ * the value zero, false, is returned for failure.
+ * Reasons for failure include this SdFile is already open, \a difFile is not
+ * a directory, \a fileName is invalid, the file does not exist
+ * or can't be opened in the access mode specified by oflag.
+ */
+uint8_t SdFile::open(SdFile* dirFile, const char* fileName, uint8_t oflag) {
+ uint8_t dname[11];
+ dir_t* p;
+
+ // error if already open
+ if (isOpen())return false;
+
+ if (!make83Name(fileName, dname)) return false;
+ vol_ = dirFile->vol_;
+ dirFile->rewind();
+
+ // bool for empty entry found
+ uint8_t emptyFound = false;
+
+ // search for file
+ while (dirFile->curPosition_ < dirFile->fileSize_) {
+ uint8_t index = 0XF & (dirFile->curPosition_ >> 5);
+ p = dirFile->readDirCache();
+ if (p == NULL) return false;
+
+ if (p->name[0] == DIR_NAME_FREE || p->name[0] == DIR_NAME_DELETED) {
+ // remember first empty slot
+ if (!emptyFound) {
+ emptyFound = true;
+ dirIndex_ = index;
+ dirBlock_ = SdVolume::cacheBlockNumber_;
+ }
+ // done if no entries follow
+ if (p->name[0] == DIR_NAME_FREE) break;
+ } else if (!memcmp(dname, p->name, 11)) {
+ // don't open existing file if O_CREAT and O_EXCL
+ if ((oflag & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) return false;
+
+ // open found file
+ return openCachedEntry(0XF & index, oflag);
+ }
+ }
+ // only create file if O_CREAT and O_WRITE
+ if ((oflag & (O_CREAT | O_WRITE)) != (O_CREAT | O_WRITE)) return false;
+
+ // cache found slot or add cluster if end of file
+ if (emptyFound) {
+ p = cacheDirEntry(SdVolume::CACHE_FOR_WRITE);
+ if (!p) return false;
+ } else {
+ if (dirFile->type_ == FAT_FILE_TYPE_ROOT16) return false;
+
+ // add and zero cluster for dirFile - first cluster is in cache for write
+ if (!dirFile->addDirCluster()) return false;
+
+ // use first entry in cluster
+ dirIndex_ = 0;
+ p = SdVolume::cacheBuffer_.dir;
+ }
+ // initialize as empty file
+ memset(p, 0, sizeof(dir_t));
+ memcpy(p->name, dname, 11);
+
+ // set timestamps
+ if (dateTime_) {
+ // call user function
+ dateTime_(&p->creationDate, &p->creationTime);
+ } else {
+ // use default date/time
+ p->creationDate = FAT_DEFAULT_DATE;
+ p->creationTime = FAT_DEFAULT_TIME;
+ }
+ p->lastAccessDate = p->creationDate;
+ p->lastWriteDate = p->creationDate;
+ p->lastWriteTime = p->creationTime;
+
+ // force write of entry to SD
+ if (!SdVolume::cacheFlush()) return false;
+
+ // open entry in cache
+ return openCachedEntry(dirIndex_, oflag);
+}
+//------------------------------------------------------------------------------
+/**
+ * Open a file by index.
+ *
+ * \param[in] dirFile An open SdFat instance for the directory.
+ *
+ * \param[in] index The \a index of the directory entry for the file to be
+ * opened. The value for \a index is (directory file position)/32.
+ *
+ * \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive
+ * OR of flags O_READ, O_WRITE, O_TRUNC, and O_SYNC.
+ *
+ * See open() by fileName for definition of flags and return values.
+ *
+ */
+uint8_t SdFile::open(SdFile* dirFile, uint16_t index, uint8_t oflag) {
+ // error if already open
+ if (isOpen())return false;
+
+ // don't open existing file if O_CREAT and O_EXCL - user call error
+ if ((oflag & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) return false;
+
+ vol_ = dirFile->vol_;
+
+ // seek to location of entry
+ if (!dirFile->seekSet(32 * index)) return false;
+
+ // read entry into cache
+ dir_t* p = dirFile->readDirCache();
+ if (p == NULL) return false;
+
+ // error if empty slot or '.' or '..'
+ if (p->name[0] == DIR_NAME_FREE ||
+ p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') {
+ return false;
+ }
+ // open cached entry
+ return openCachedEntry(index & 0XF, oflag);
+}
+//------------------------------------------------------------------------------
+// open a cached directory entry. Assumes vol_ is initializes
+uint8_t SdFile::openCachedEntry(uint8_t dirIndex, uint8_t oflag) {
+ // location of entry in cache
+ dir_t* p = SdVolume::cacheBuffer_.dir + dirIndex;
+
+ // write or truncate is an error for a directory or read-only file
+ if (p->attributes & (DIR_ATT_READ_ONLY | DIR_ATT_DIRECTORY)) {
+ if (oflag & (O_WRITE | O_TRUNC)) return false;
+ }
+ // remember location of directory entry on SD
+ dirIndex_ = dirIndex;
+ dirBlock_ = SdVolume::cacheBlockNumber_;
+
+ // copy first cluster number for directory fields
+ firstCluster_ = (uint32_t)p->firstClusterHigh << 16;
+ firstCluster_ |= p->firstClusterLow;
+
+ // make sure it is a normal file or subdirectory
+ if (DIR_IS_FILE(p)) {
+ fileSize_ = p->fileSize;
+ type_ = FAT_FILE_TYPE_NORMAL;
+ } else if (DIR_IS_SUBDIR(p)) {
+ if (!vol_->chainSize(firstCluster_, &fileSize_)) return false;
+ type_ = FAT_FILE_TYPE_SUBDIR;
+ } else {
+ return false;
+ }
+ // save open flags for read/write
+ flags_ = oflag & (O_ACCMODE | O_SYNC | O_APPEND);
+
+ // set to start of file
+ curCluster_ = 0;
+ curPosition_ = 0;
+
+ // truncate file to zero length if requested
+ if (oflag & O_TRUNC) return truncate(0);
+ return true;
+}
+//------------------------------------------------------------------------------
+/**
+ * Open a volume's root directory.
+ *
+ * \param[in] vol The FAT volume containing the root directory to be opened.
+ *
+ * \return The value one, true, is returned for success and
+ * the value zero, false, is returned for failure.
+ * Reasons for failure include the FAT volume has not been initialized
+ * or it a FAT12 volume.
+ */
+uint8_t SdFile::openRoot(SdVolume* vol) {
+ // error if file is already open
+ if (isOpen()) return false;
+
+ if (vol->fatType() == 16) {
+ type_ = FAT_FILE_TYPE_ROOT16;
+ firstCluster_ = 0;
+ fileSize_ = 32 * vol->rootDirEntryCount();
+ } else if (vol->fatType() == 32) {
+ type_ = FAT_FILE_TYPE_ROOT32;
+ firstCluster_ = vol->rootDirStart();
+ if (!vol->chainSize(firstCluster_, &fileSize_)) return false;
+ } else {
+ // volume is not initialized or FAT12
+ return false;
+ }
+ vol_ = vol;
+ // read only
+ flags_ = O_READ;
+
+ // set to start of file
+ curCluster_ = 0;
+ curPosition_ = 0;
+
+ // root has no directory entry
+ dirBlock_ = 0;
+ dirIndex_ = 0;
+ return true;
+}
+//------------------------------------------------------------------------------
+/** %Print the name field of a directory entry in 8.3 format to Serial.
+ *
+ * \param[in] dir The directory structure containing the name.
+ * \param[in] width Blank fill name if length is less than \a width.
+ */
+void SdFile::printDirName(const dir_t& dir, uint8_t width) {
+ uint8_t w = 0;
+ for (uint8_t i = 0; i < 11; i++) {
+ if (dir.name[i] == ' ')continue;
+ if (i == 8) {
+ SerialDebug.print('.');
+ w++;
+ }
+ SerialDebug.print((char)dir.name[i]);
+ w++;
+ }
+ if (DIR_IS_SUBDIR(&dir)) {
+ SerialDebug.print('/');
+ w++;
+ }
+ while (w < width) {
+ SerialDebug.print(' ');
+ w++;
+ }
+}
+//------------------------------------------------------------------------------
+/** %Print a directory date field to Serial.
+ *
+ * Format is yyyy-mm-dd.
+ *
+ * \param[in] fatDate The date field from a directory entry.
+ */
+void SdFile::printFatDate(uint16_t fatDate) {
+ SerialDebug.print(FAT_YEAR(fatDate));
+ SerialDebug.print('-');
+ printTwoDigits(FAT_MONTH(fatDate));
+ SerialDebug.print('-');
+ printTwoDigits(FAT_DAY(fatDate));
+}
+//------------------------------------------------------------------------------
+/** %Print a directory time field to Serial.
+ *
+ * Format is hh:mm:ss.
+ *
+ * \param[in] fatTime The time field from a directory entry.
+ */
+void SdFile::printFatTime(uint16_t fatTime) {
+ printTwoDigits(FAT_HOUR(fatTime));
+ SerialDebug.print(':');
+ printTwoDigits(FAT_MINUTE(fatTime));
+ SerialDebug.print(':');
+ printTwoDigits(FAT_SECOND(fatTime));
+}
+//------------------------------------------------------------------------------
+/** %Print a value as two digits to Serial.
+ *
+ * \param[in] v Value to be printed, 0 <= \a v <= 99
+ */
+void SdFile::printTwoDigits(uint8_t v) {
+ char str[3];
+ str[0] = '0' + v/10;
+ str[1] = '0' + v % 10;
+ str[2] = 0;
+ SerialDebug.print(str);
+}
+//------------------------------------------------------------------------------
+/**
+ * Read data from a file starting at the current position.
+ *
+ * \param[out] buf Pointer to the location that will receive the data.
+ *
+ * \param[in] nbyte Maximum number of bytes to read.
+ *
+ * \return For success read() returns the number of bytes read.
+ * A value less than \a nbyte, including zero, will be returned
+ * if end of file is reached.
+ * If an error occurs, read() returns -1. Possible errors include
+ * read() called before a file has been opened, corrupt file system
+ * or an I/O error occurred.
+ */
+int16_t SdFile::read(void* buf, uint16_t nbyte) {
+ uint8_t* dst = reinterpret_cast(buf);
+
+ // error if not open or write only
+ if (!isOpen() || !(flags_ & O_READ)) return -1;
+
+ // max bytes left in file
+ if (nbyte > (fileSize_ - curPosition_)) nbyte = fileSize_ - curPosition_;
+
+ // amount left to read
+ uint16_t toRead = nbyte;
+ while (toRead > 0) {
+ uint32_t block; // raw device block number
+ uint16_t offset = curPosition_ & 0X1FF; // offset in block
+ if (type_ == FAT_FILE_TYPE_ROOT16) {
+ block = vol_->rootDirStart() + (curPosition_ >> 9);
+ } else {
+ uint8_t blockOfCluster = vol_->blockOfCluster(curPosition_);
+ if (offset == 0 && blockOfCluster == 0) {
+ // start of new cluster
+ if (curPosition_ == 0) {
+ // use first cluster in file
+ curCluster_ = firstCluster_;
+ } else {
+ // get next cluster from FAT
+ if (!vol_->fatGet(curCluster_, &curCluster_)) return -1;
+ }
+ }
+ block = vol_->clusterStartBlock(curCluster_) + blockOfCluster;
+ }
+ uint16_t n = toRead;
+
+ // amount to be read from current block
+ if (n > (512 - offset)) n = 512 - offset;
+
+#if 0
+ SerialDebug.print("block ");
+ SerialDebug.print(block);
+ SerialDebug.print(" n ");
+ SerialDebug.println(n);
+#endif
+ // no buffering needed if n == 512 or user requests no buffering
+ if ((unbufferedRead() || n == 512) && block != SdVolume::cacheBlockNumber_) {
+ if (!vol_->readData(block, offset, n, dst)) return -1;
+ dst += n;
+ } else {
+ // read block to cache and copy data to caller
+ if (!SdVolume::cacheRawBlock(block, SdVolume::CACHE_FOR_READ)) return -1;
+ uint8_t* src = SdVolume::cacheBuffer_.data + offset;
+ uint8_t* end = src + n;
+ while (src != end) *dst++ = *src++;
+ }
+ curPosition_ += n;
+ toRead -= n;
+ }
+ return nbyte;
+}
+//------------------------------------------------------------------------------
+/**
+ * Read the next directory entry from a directory file.
+ *
+ * \param[out] dir The dir_t struct that will receive the data.
+ *
+ * \return For success readDir() returns the number of bytes read.
+ * A value of zero will be returned if end of file is reached.
+ * If an error occurs, readDir() returns -1. Possible errors include
+ * readDir() called before a directory has been opened, this is not
+ * a directory file or an I/O error occurred.
+ */
+int8_t SdFile::readDir(dir_t* dir) {
+ int8_t n;
+ // if not a directory file or miss-positioned return an error
+ if (!isDir() || (0X1F & curPosition_)) return -1;
+
+ while ((n = read(dir, sizeof(dir_t))) == sizeof(dir_t)) {
+ // last entry if DIR_NAME_FREE
+ if (dir->name[0] == DIR_NAME_FREE) break;
+ // skip empty entries and entry for . and ..
+ if (dir->name[0] == DIR_NAME_DELETED || dir->name[0] == '.') continue;
+ // return if normal file or subdirectory
+ if (DIR_IS_FILE_OR_SUBDIR(dir)) return n;
+ }
+ // error, end of file, or past last entry
+ return n < 0 ? -1 : 0;
+}
+//------------------------------------------------------------------------------
+// Read next directory entry into the cache
+// Assumes file is correctly positioned
+dir_t* SdFile::readDirCache(void) {
+ // error if not directory
+ if (!isDir()) return NULL;
+
+ // index of entry in cache
+ uint8_t i = (curPosition_ >> 5) & 0XF;
+
+ // use read to locate and cache block
+ if (read() < 0) return NULL;
+
+ // advance to next entry
+ curPosition_ += 31;
+
+ // return pointer to entry
+ return (SdVolume::cacheBuffer_.dir + i);
+}
+//------------------------------------------------------------------------------
+/**
+ * Remove a file.
+ *
+ * The directory entry and all data for the file are deleted.
+ *
+ * \note This function should not be used to delete the 8.3 version of a
+ * file that has a long name. For example if a file has the long name
+ * "New Text Document.txt" you should not delete the 8.3 name "NEWTEX~1.TXT".
+ *
+ * \return The value one, true, is returned for success and
+ * the value zero, false, is returned for failure.
+ * Reasons for failure include the file read-only, is a directory,
+ * or an I/O error occurred.
+ */
+uint8_t SdFile::remove(void) {
+ // free any clusters - will fail if read-only or directory
+ if (!truncate(0)) return false;
+
+ // cache directory entry
+ dir_t* d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE);
+ if (!d) return false;
+
+ // mark entry deleted
+ d->name[0] = DIR_NAME_DELETED;
+
+ // set this SdFile closed
+ type_ = FAT_FILE_TYPE_CLOSED;
+
+ // write entry to SD
+ return SdVolume::cacheFlush();
+}
+//------------------------------------------------------------------------------
+/**
+ * Remove a file.
+ *
+ * The directory entry and all data for the file are deleted.
+ *
+ * \param[in] dirFile The directory that contains the file.
+ * \param[in] fileName The name of the file to be removed.
+ *
+ * \note This function should not be used to delete the 8.3 version of a
+ * file that has a long name. For example if a file has the long name
+ * "New Text Document.txt" you should not delete the 8.3 name "NEWTEX~1.TXT".
+ *
+ * \return The value one, true, is returned for success and
+ * the value zero, false, is returned for failure.
+ * Reasons for failure include the file is a directory, is read only,
+ * \a dirFile is not a directory, \a fileName is not found
+ * or an I/O error occurred.
+ */
+uint8_t SdFile::remove(SdFile* dirFile, const char* fileName) {
+ SdFile file;
+ if (!file.open(dirFile, fileName, O_WRITE)) return false;
+ return file.remove();
+}
+//------------------------------------------------------------------------------
+/** Remove a directory file.
+ *
+ * The directory file will be removed only if it is empty and is not the
+ * root directory. rmDir() follows DOS and Windows and ignores the
+ * read-only attribute for the directory.
+ *
+ * \note This function should not be used to delete the 8.3 version of a
+ * directory that has a long name. For example if a directory has the
+ * long name "New folder" you should not delete the 8.3 name "NEWFOL~1".
+ *
+ * \return The value one, true, is returned for success and
+ * the value zero, false, is returned for failure.
+ * Reasons for failure include the file is not a directory, is the root
+ * directory, is not empty, or an I/O error occurred.
+ */
+uint8_t SdFile::rmDir(void) {
+ // must be open subdirectory
+ if (!isSubDir()) return false;
+
+ rewind();
+
+ // make sure directory is empty
+ while (curPosition_ < fileSize_) {
+ dir_t* p = readDirCache();
+ if (p == NULL) return false;
+ // done if past last used entry
+ if (p->name[0] == DIR_NAME_FREE) break;
+ // skip empty slot or '.' or '..'
+ if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') continue;
+ // error not empty
+ if (DIR_IS_FILE_OR_SUBDIR(p)) return false;
+ }
+ // convert empty directory to normal file for remove
+ type_ = FAT_FILE_TYPE_NORMAL;
+ flags_ |= O_WRITE;
+ return remove();
+}
+//------------------------------------------------------------------------------
+/** Recursively delete a directory and all contained files.
+ *
+ * This is like the Unix/Linux 'rm -rf *' if called with the root directory
+ * hence the name.
+ *
+ * Warning - This will remove all contents of the directory including
+ * subdirectories. The directory will then be removed if it is not root.
+ * The read-only attribute for files will be ignored.
+ *
+ * \note This function should not be used to delete the 8.3 version of
+ * a directory that has a long name. See remove() and rmDir().
+ *
+ * \return The value one, true, is returned for success and
+ * the value zero, false, is returned for failure.
+ */
+uint8_t SdFile::rmRfStar(void) {
+ rewind();
+ while (curPosition_ < fileSize_) {
+ SdFile f;
+
+ // remember position
+ uint16_t index = curPosition_/32;
+
+ dir_t* p = readDirCache();
+ if (!p) return false;
+
+ // done if past last entry
+ if (p->name[0] == DIR_NAME_FREE) break;
+
+ // skip empty slot or '.' or '..'
+ if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') continue;
+
+ // skip if part of long file name or volume label in root
+ if (!DIR_IS_FILE_OR_SUBDIR(p)) continue;
+
+ if (!f.open(this, index, O_READ)) return false;
+ if (f.isSubDir()) {
+ // recursively delete
+ if (!f.rmRfStar()) return false;
+ } else {
+ // ignore read-only
+ f.flags_ |= O_WRITE;
+ if (!f.remove()) return false;
+ }
+ // position to next entry if required
+ if (curPosition_ != (32*(index + 1))) {
+ if (!seekSet(32*(index + 1))) return false;
+ }
+ }
+ // don't try to delete root
+ if (isRoot()) return true;
+ return rmDir();
+}
+//------------------------------------------------------------------------------
+/**
+ * Sets a file's position.
+ *
+ * \param[in] pos The new position in bytes from the beginning of the file.
+ *
+ * \return The value one, true, is returned for success and
+ * the value zero, false, is returned for failure.
+ */
+uint8_t SdFile::seekSet(uint32_t pos) {
+ // error if file not open or seek past end of file
+ if (!isOpen() || pos > fileSize_) return false;
+
+ if (type_ == FAT_FILE_TYPE_ROOT16) {
+ curPosition_ = pos;
+ return true;
+ }
+ if (pos == 0) {
+ // set position to start of file
+ curCluster_ = 0;
+ curPosition_ = 0;
+ return true;
+ }
+ // calculate cluster index for cur and new position
+ uint32_t nCur = (curPosition_ - 1) >> (vol_->clusterSizeShift_ + 9);
+ uint32_t nNew = (pos - 1) >> (vol_->clusterSizeShift_ + 9);
+
+ if (nNew < nCur || curPosition_ == 0) {
+ // must follow chain from first cluster
+ curCluster_ = firstCluster_;
+ } else {
+ // advance from curPosition
+ nNew -= nCur;
+ }
+ while (nNew--) {
+ if (!vol_->fatGet(curCluster_, &curCluster_)) return false;
+ }
+ curPosition_ = pos;
+ return true;
+}
+//------------------------------------------------------------------------------
+/**
+ * The sync() call causes all modified data and directory fields
+ * to be written to the storage device.
+ *
+ * \return The value one, true, is returned for success and
+ * the value zero, false, is returned for failure.
+ * Reasons for failure include a call to sync() before a file has been
+ * opened or an I/O error.
+ */
+uint8_t SdFile::sync(void) {
+ // only allow open files and directories
+ if (!isOpen()) return false;
+
+ if (flags_ & F_FILE_DIR_DIRTY) {
+ dir_t* d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE);
+ if (!d) return false;
+
+ // do not set filesize for dir files
+ if (!isDir()) d->fileSize = fileSize_;
+
+ // update first cluster fields
+ d->firstClusterLow = firstCluster_ & 0XFFFF;
+ d->firstClusterHigh = firstCluster_ >> 16;
+
+ // set modify time if user supplied a callback date/time function
+ if (dateTime_) {
+ dateTime_(&d->lastWriteDate, &d->lastWriteTime);
+ d->lastAccessDate = d->lastWriteDate;
+ }
+ // clear directory dirty
+ flags_ &= ~F_FILE_DIR_DIRTY;
+ }
+ return SdVolume::cacheFlush();
+}
+//------------------------------------------------------------------------------
+/**
+ * Set a file's timestamps in its directory entry.
+ *
+ * \param[in] flags Values for \a flags are constructed by a bitwise-inclusive
+ * OR of flags from the following list
+ *
+ * T_ACCESS - Set the file's last access date.
+ *
+ * T_CREATE - Set the file's creation date and time.
+ *
+ * T_WRITE - Set the file's last write/modification date and time.
+ *
+ * \param[in] year Valid range 1980 - 2107 inclusive.
+ *
+ * \param[in] month Valid range 1 - 12 inclusive.
+ *
+ * \param[in] day Valid range 1 - 31 inclusive.
+ *
+ * \param[in] hour Valid range 0 - 23 inclusive.
+ *
+ * \param[in] minute Valid range 0 - 59 inclusive.
+ *
+ * \param[in] second Valid range 0 - 59 inclusive
+ *
+ * \note It is possible to set an invalid date since there is no check for
+ * the number of days in a month.
+ *
+ * \note
+ * Modify and access timestamps may be overwritten if a date time callback
+ * function has been set by dateTimeCallback().
+ *
+ * \return The value one, true, is returned for success and
+ * the value zero, false, is returned for failure.
+ */
+uint8_t SdFile::timestamp(uint8_t flags, uint16_t year, uint8_t month,
+ uint8_t day, uint8_t hour, uint8_t minute, uint8_t second) {
+ if (!isOpen()
+ || year < 1980
+ || year > 2107
+ || month < 1
+ || month > 12
+ || day < 1
+ || day > 31
+ || hour > 23
+ || minute > 59
+ || second > 59) {
+ return false;
+ }
+ dir_t* d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE);
+ if (!d) return false;
+
+ uint16_t dirDate = FAT_DATE(year, month, day);
+ uint16_t dirTime = FAT_TIME(hour, minute, second);
+ if (flags & T_ACCESS) {
+ d->lastAccessDate = dirDate;
+ }
+ if (flags & T_CREATE) {
+ d->creationDate = dirDate;
+ d->creationTime = dirTime;
+ // seems to be units of 1/100 second not 1/10 as Microsoft states
+ d->creationTimeTenths = second & 1 ? 100 : 0;
+ }
+ if (flags & T_WRITE) {
+ d->lastWriteDate = dirDate;
+ d->lastWriteTime = dirTime;
+ }
+ SdVolume::cacheSetDirty();
+ return sync();
+}
+//------------------------------------------------------------------------------
+/**
+ * Truncate a file to a specified length. The current file position
+ * will be maintained if it is less than or equal to \a length otherwise
+ * it will be set to end of file.
+ *
+ * \param[in] length The desired length for the file.
+ *
+ * \return The value one, true, is returned for success and
+ * the value zero, false, is returned for failure.
+ * Reasons for failure include file is read only, file is a directory,
+ * \a length is greater than the current file size or an I/O error occurs.
+ */
+uint8_t SdFile::truncate(uint32_t length) {
+// error if not a normal file or read-only
+ if (!isFile() || !(flags_ & O_WRITE)) return false;
+
+ // error if length is greater than current size
+ if (length > fileSize_) return false;
+
+ // fileSize and length are zero - nothing to do
+ if (fileSize_ == 0) return true;
+
+ // remember position for seek after truncation
+ uint32_t newPos = curPosition_ > length ? length : curPosition_;
+
+ // position to last cluster in truncated file
+ if (!seekSet(length)) return false;
+
+ if (length == 0) {
+ // free all clusters
+ if (!vol_->freeChain(firstCluster_)) return false;
+ firstCluster_ = 0;
+ } else {
+ uint32_t toFree;
+ if (!vol_->fatGet(curCluster_, &toFree)) return false;
+
+ if (!vol_->isEOC(toFree)) {
+ // free extra clusters
+ if (!vol_->freeChain(toFree)) return false;
+
+ // current cluster is end of chain
+ if (!vol_->fatPutEOC(curCluster_)) return false;
+ }
+ }
+ fileSize_ = length;
+
+ // need to update directory entry
+ flags_ |= F_FILE_DIR_DIRTY;
+
+ if (!sync()) return false;
+
+ // set file to correct position
+ return seekSet(newPos);
+}
+//------------------------------------------------------------------------------
+/**
+ * Write data to an open file.
+ *
+ * \note Data is moved to the cache but may not be written to the
+ * storage device until sync() is called.
+ *
+ * \param[in] buf Pointer to the location of the data to be written.
+ *
+ * \param[in] nbyte Number of bytes to write.
+ *
+ * \return For success write() returns the number of bytes written, always
+ * \a nbyte. If an error occurs, write() returns -1. Possible errors
+ * include write() is called before a file has been opened, write is called
+ * for a read-only file, device is full, a corrupt file system or an I/O error.
+ *
+ */
+int16_t SdFile::write(const void* buf, uint16_t nbyte) {
+ // convert void* to uint8_t* - must be before goto statements
+ const uint8_t* src = reinterpret_cast