Imported upstream version 1.20 upstream
authorBdale Garbee <bdale@gag.com>
Wed, 6 Feb 2008 06:08:51 +0000 (23:08 -0700)
committerBdale Garbee <bdale@gag.com>
Wed, 6 Feb 2008 06:08:51 +0000 (23:08 -0700)
130 files changed:
FreeRTOS/Makefile [new file with mode: 0644]
FreeRTOS/croutine.c [new file with mode: 0644]
FreeRTOS/include/FreeRTOS.h [new file with mode: 0644]
FreeRTOS/include/croutine.h [new file with mode: 0644]
FreeRTOS/include/list.h [new file with mode: 0644]
FreeRTOS/include/portable.h [new file with mode: 0644]
FreeRTOS/include/projdefs.h [new file with mode: 0644]
FreeRTOS/include/queue.h [new file with mode: 0644]
FreeRTOS/include/semphr.h [new file with mode: 0644]
FreeRTOS/include/task.h [new file with mode: 0644]
FreeRTOS/list.c [new file with mode: 0644]
FreeRTOS/portable/GCC/ARM7_LPC2000/Makefile [new file with mode: 0644]
FreeRTOS/portable/GCC/ARM7_LPC2000/port.c [new file with mode: 0644]
FreeRTOS/portable/GCC/ARM7_LPC2000/portISR.c [new file with mode: 0644]
FreeRTOS/portable/GCC/ARM7_LPC2000/portmacro.h [new file with mode: 0644]
FreeRTOS/portable/GCC/Makefile [new file with mode: 0644]
FreeRTOS/portable/Makefile [new file with mode: 0644]
FreeRTOS/portable/MemMang/Makefile [new file with mode: 0644]
FreeRTOS/portable/MemMang/heap_1.c [new file with mode: 0644]
FreeRTOS/portable/MemMang/heap_2.c [new file with mode: 0644]
FreeRTOS/portable/MemMang/heap_3.c [new file with mode: 0644]
FreeRTOS/queue.c [new file with mode: 0644]
FreeRTOS/tasks.c [new file with mode: 0644]
FreeRTOSConfig.h [new file with mode: 0644]
Makefile [new file with mode: 0644]
README [new file with mode: 0644]
Windows/usbser.inf [new file with mode: 0644]
Windows/usbser.sys [new file with mode: 0755]
adc/Makefile [new file with mode: 0644]
adc/adc.c [new file with mode: 0644]
adc/adc.h [new file with mode: 0644]
boot.s [new file with mode: 0644]
cpu/Makefile [new file with mode: 0644]
cpu/cpu.c [new file with mode: 0644]
cpu/cpu.h [new file with mode: 0644]
dac/Makefile [new file with mode: 0644]
dac/dac.c [new file with mode: 0644]
dac/dac.h [new file with mode: 0644]
eints/Makefile [new file with mode: 0644]
eints/eints.c [new file with mode: 0644]
eints/eints.h [new file with mode: 0644]
eints/eintsISR.c [new file with mode: 0644]
eints/eintsISR.h [new file with mode: 0644]
fatfs/Makefile [new file with mode: 0644]
fatfs/disk.h [new file with mode: 0644]
fatfs/diskio.h [new file with mode: 0644]
fatfs/ff.c [new file with mode: 0644]
fatfs/ff.h [new file with mode: 0644]
fatfs/mmc.c [new file with mode: 0644]
fatfs/mmc.h [new file with mode: 0644]
fatfs/spi.c [new file with mode: 0644]
fatfs/spi.h [new file with mode: 0644]
fiq/Makefile [new file with mode: 0644]
fiq/fiq.c [new file with mode: 0644]
fiq/fiq.h [new file with mode: 0644]
gps/Makefile [new file with mode: 0644]
gps/gps.c [new file with mode: 0644]
gps/gps.h [new file with mode: 0644]
i2c/Makefile [new file with mode: 0644]
i2c/eeprom.c [new file with mode: 0644]
i2c/eeprom.h [new file with mode: 0644]
i2c/eeprom_working.c [new file with mode: 0644]
i2c/i2c.c [new file with mode: 0644]
i2c/i2c.h [new file with mode: 0644]
i2c/i2cInt.c [new file with mode: 0644]
i2c/i2cIntWorking.c [new file with mode: 0644]
i2c/i2cPolled.c [new file with mode: 0644]
i2c/lm75.c [new file with mode: 0644]
i2c/lm75.h [new file with mode: 0644]
iap/Makefile [new file with mode: 0644]
iap/iap.c [new file with mode: 0644]
iap/iap.h [new file with mode: 0644]
leds/Makefile [new file with mode: 0644]
leds/leds.c [new file with mode: 0644]
leds/leds.h [new file with mode: 0644]
leds/leds_reuse.c [new file with mode: 0644]
lpc210x.h [new file with mode: 0644]
lpc2148-rom.ld [new file with mode: 0644]
lpc2148_demo.fms [new file with mode: 0755]
main.c [new file with mode: 0644]
main.h [new file with mode: 0644]
monitor/Makefile [new file with mode: 0644]
monitor/args.c [new file with mode: 0644]
monitor/args.h [new file with mode: 0644]
monitor/monitor.c [new file with mode: 0644]
monitor/monitor.h [new file with mode: 0644]
newlib/Makefile [new file with mode: 0644]
newlib/syscalls.c [new file with mode: 0644]
rtc/Makefile [new file with mode: 0644]
rtc/rtc.c [new file with mode: 0644]
rtc/rtc.h [new file with mode: 0644]
rtc/rtcISR.c [new file with mode: 0644]
rtc/rtcISR.h [new file with mode: 0644]
sensors/Makefile [new file with mode: 0644]
sensors/sensors.c [new file with mode: 0644]
sensors/sensors.h [new file with mode: 0644]
swi/Makefile [new file with mode: 0644]
swi/swi.c [new file with mode: 0644]
swi/swi.h [new file with mode: 0644]
swi/swidispatch.s [new file with mode: 0644]
sysdefs.h [new file with mode: 0644]
uart/Makefile [new file with mode: 0644]
uart/uart.c [new file with mode: 0644]
uart/uart.h [new file with mode: 0644]
uart/uartISR.c [new file with mode: 0644]
uart/uartISR.h [new file with mode: 0644]
usb/Makefile [new file with mode: 0644]
usb/usbISR.c [new file with mode: 0644]
usb/usbISR.h [new file with mode: 0644]
usb/usbapi.h [new file with mode: 0644]
usb/usbcontrol.c [new file with mode: 0644]
usb/usbinit.c [new file with mode: 0644]
usb/usbstdreq.c [new file with mode: 0644]
usb/usbstruct.h [new file with mode: 0644]
usbmass/Makefile [new file with mode: 0644]
usbmass/mscblock.c [new file with mode: 0644]
usbmass/mscblock.h [new file with mode: 0644]
usbmass/mscbot.c [new file with mode: 0644]
usbmass/mscbot.h [new file with mode: 0644]
usbmass/mscdebug.h [new file with mode: 0644]
usbmass/mscscsi.c [new file with mode: 0644]
usbmass/mscscsi.h [new file with mode: 0644]
usbmass/mscspi.c [new file with mode: 0644]
usbmass/mscspi.h [new file with mode: 0644]
usbmass/mscspi2.c [new file with mode: 0644]
usbmass/usbmass.c [new file with mode: 0644]
usbmass/usbmass.h [new file with mode: 0644]
usbser/Makefile [new file with mode: 0644]
usbser/usbser.c [new file with mode: 0644]
usbser/usbser.h [new file with mode: 0644]

diff --git a/FreeRTOS/Makefile b/FreeRTOS/Makefile
new file mode 100644 (file)
index 0000000..03f281c
--- /dev/null
@@ -0,0 +1,29 @@
+SRC_FILES=croutine.c list.c queue.c tasks.c
+
+SUBDIRS=portable
+
+#
+# Define all object files.
+#
+ARM_OBJ = $(SRC_FILES:.c=.o)
+
+.PHONY: all
+all: $(ARM_OBJ)
+       @for i in $(SUBDIRS); do \
+       (cd $$i; $(MAKE) $(MFLAGS) $(MYMAKEFLAGS) all); done
+
+$(ARM_OBJ) : %.o : %.c Makefile .depend
+       $(CC) -c $(CFLAGS) $< -o $@
+       $(AR) r $(COMMON)/common.a $@
+
+#
+#  The .depend files contains the list of header files that the
+#  various source files depend on.  By doing this, we'll only
+#  rebuild the .o's that are affected by header files changing.
+#
+.depend:
+                       $(CC) $(CFLAGS) -M $(SRC_FILES) > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff --git a/FreeRTOS/croutine.c b/FreeRTOS/croutine.c
new file mode 100644 (file)
index 0000000..4f2ba87
--- /dev/null
@@ -0,0 +1,345 @@
+/*
+       FreeRTOS.org V4.4.0 - Copyright (C) 2003-2007 Richard Barry.
+
+       This file is part of the FreeRTOS.org distribution.
+
+       FreeRTOS.org 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 2 of the License, or
+       (at your option) any later version.
+
+       FreeRTOS.org 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 FreeRTOS.org; if not, write to the Free Software
+       Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+       A special exception to the GPL can be applied should you wish to distribute
+       a combined work that includes FreeRTOS.org, without being obliged to provide
+       the source code for any proprietary components.  See the licensing section
+       of http://www.FreeRTOS.org for full details of how and when the exception
+       can be applied.
+
+       ***************************************************************************
+       See http://www.FreeRTOS.org for documentation, latest information, license
+       and contact details.  Please ensure to read the configuration and relevant
+       port sections of the online documentation.
+
+       Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along
+       with commercial development and support options.
+       ***************************************************************************
+*/
+
+#include "FreeRTOS.h"
+#include "task.h"
+#include "croutine.h"
+
+/* Lists for ready and blocked co-routines. --------------------*/
+static xList pxReadyCoRoutineLists[ configMAX_CO_ROUTINE_PRIORITIES ]; /*< Prioritised ready co-routines. */
+static xList xDelayedCoRoutineList1;                                                                   /*< Delayed co-routines. */
+static xList xDelayedCoRoutineList2;                                                                   /*< Delayed co-routines (two lists are used - one for delays that have overflowed the current tick count. */
+static xList * pxDelayedCoRoutineList;                                                                 /*< Points to the delayed co-routine list currently being used. */
+static xList * pxOverflowDelayedCoRoutineList;                                                 /*< Points to the delayed co-routine list currently being used to hold co-routines that have overflowed the current tick count. */
+static xList xPendingReadyList;                                                                                        /*< Holds co-routines that have been readied by an external event.  They cannot be added directly to the ready lists as the ready lists cannot be accessed by interrupts. */
+
+/* Other file private variables. --------------------------------*/
+corCRCB * pxCurrentCoRoutine = NULL;
+static unsigned portBASE_TYPE uxTopCoRoutineReadyPriority = 0;
+static portTickType xCoRoutineTickCount = 0;
+
+/* The initial state of the co-routine when it is created. */
+#define corINITIAL_STATE       ( 0 )
+
+/*
+ * Place the co-routine represented by pxCRCB into the appropriate ready queue
+ * for the priority.  It is inserted at the end of the list.
+ *
+ * This macro accesses the co-routine ready lists and therefore must not be
+ * used from within an ISR.
+ */
+#define prvAddCoRoutineToReadyQueue( pxCRCB )                                                                                                                                          \
+{                                                                                                                                                                                                                                      \
+       if( pxCRCB->uxPriority > uxTopCoRoutineReadyPriority )                                                                                                                  \
+       {                                                                                                                                                                                                                               \
+               uxTopCoRoutineReadyPriority = pxCRCB->uxPriority;                                                                                                                       \
+       }                                                                                                                                                                                                                               \
+       vListInsertEnd( ( xList * ) &( pxReadyCoRoutineLists[ pxCRCB->uxPriority ] ), &( pxCRCB->xGenericListItem ) );  \
+}      
+
+/*
+ * Utility to ready all the lists used by the scheduler.  This is called
+ * automatically upon the creation of the first co-routine.
+ */
+static void prvInitialiseCoRoutineLists( void );
+
+/*
+ * Co-routines that are readied by an interrupt cannot be placed directly into
+ * the ready lists (there is no mutual exclusion).  Instead they are placed in
+ * in the pending ready list in order that they can later be moved to the ready
+ * list by the co-routine scheduler.
+ */
+static inline void prvCheckPendingReadyList( void );
+
+/*
+ * Macro that looks at the list of co-routines that are currently delayed to
+ * see if any require waking.
+ *
+ * Co-routines are stored in the queue in the order of their wake time -
+ * meaning once one co-routine has been found whose timer has not expired
+ * we need not look any further down the list.
+ */
+static inline void prvCheckDelayedList( void );
+
+/*-----------------------------------------------------------*/
+
+signed portBASE_TYPE xCoRoutineCreate( crCOROUTINE_CODE pxCoRoutineCode, unsigned portBASE_TYPE uxPriority, unsigned portBASE_TYPE uxIndex )
+{
+signed portBASE_TYPE xReturn;
+corCRCB *pxCoRoutine;
+
+       /* Allocate the memory that will store the co-routine control block. */
+       pxCoRoutine = ( corCRCB * ) pvPortMalloc( sizeof( corCRCB ) );
+       if( pxCoRoutine )
+       {
+               /* If pxCurrentCoRoutine is NULL then this is the first co-routine to
+               be created and the co-routine data structures need initialising. */
+               if( pxCurrentCoRoutine == NULL )
+               {
+                       pxCurrentCoRoutine = pxCoRoutine;
+                       prvInitialiseCoRoutineLists();
+               }
+
+               /* Check the priority is within limits. */
+               if( uxPriority >= configMAX_CO_ROUTINE_PRIORITIES )
+               {
+                       uxPriority = configMAX_CO_ROUTINE_PRIORITIES - 1;
+               }
+
+               /* Fill out the co-routine control block from the function parameters. */
+               pxCoRoutine->uxState = corINITIAL_STATE;
+               pxCoRoutine->uxPriority = uxPriority;
+               pxCoRoutine->uxIndex = uxIndex;
+               pxCoRoutine->pxCoRoutineFunction = pxCoRoutineCode;
+
+               /* Initialise all the other co-routine control block parameters. */
+               vListInitialiseItem( &( pxCoRoutine->xGenericListItem ) );
+               vListInitialiseItem( &( pxCoRoutine->xEventListItem ) );
+
+               /* Set the co-routine control block as a link back from the xListItem.
+               This is so we can get back to the containing CRCB from a generic item
+               in a list. */
+               listSET_LIST_ITEM_OWNER( &( pxCoRoutine->xGenericListItem ), pxCoRoutine );
+               listSET_LIST_ITEM_OWNER( &( pxCoRoutine->xEventListItem ), pxCoRoutine );
+       
+               /* Event lists are always in priority order. */
+               listSET_LIST_ITEM_VALUE( &( pxCoRoutine->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) uxPriority );
+               
+               /* Now the co-routine has been initialised it can be added to the ready
+               list at the correct priority. */
+               prvAddCoRoutineToReadyQueue( pxCoRoutine );
+
+               xReturn = pdPASS;
+       }
+       else
+       {               
+               xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
+       }
+       
+       return xReturn; 
+}
+/*-----------------------------------------------------------*/
+
+void vCoRoutineAddToDelayedList( portTickType xTicksToDelay, xList *pxEventList )
+{
+portTickType xTimeToWake;
+
+       /* Calculate the time to wake - this may overflow but this is
+       not a problem. */
+       xTimeToWake = xCoRoutineTickCount + 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 * ) &( pxCurrentCoRoutine->xGenericListItem ) );
+
+       /* The list item will be inserted in wake time order. */
+       listSET_LIST_ITEM_VALUE( &( pxCurrentCoRoutine->xGenericListItem ), xTimeToWake );
+
+       if( xTimeToWake < xCoRoutineTickCount )
+       {
+               /* Wake time has overflowed.  Place this item in the
+               overflow list. */
+               vListInsert( ( xList * ) pxOverflowDelayedCoRoutineList, ( xListItem * ) &( pxCurrentCoRoutine->xGenericListItem ) );
+       }
+       else
+       {
+               /* The wake time has not overflowed, so we can use the
+               current block list. */
+               vListInsert( ( xList * ) pxDelayedCoRoutineList, ( xListItem * ) &( pxCurrentCoRoutine->xGenericListItem ) );
+       }
+
+       if( pxEventList )
+       {
+               /* Also add the co-routine to an event list.  If this is done then the
+               function must be called with interrupts disabled. */
+               vListInsert( pxEventList, &( pxCurrentCoRoutine->xEventListItem ) );
+       }
+}
+/*-----------------------------------------------------------*/
+
+static inline void prvCheckPendingReadyList( void )
+{
+       /* Are there any co-routines waiting to get moved to the ready list?  These
+       are co-routines that have been readied by an ISR.  The ISR cannot access
+       the     ready lists itself. */
+       while( !listLIST_IS_EMPTY( &xPendingReadyList ) )
+       {
+               corCRCB *pxUnblockedCRCB;
+
+               /* The pending ready list can be accessed by an ISR. */
+               portDISABLE_INTERRUPTS();
+               {       
+                       pxUnblockedCRCB = ( corCRCB * ) listGET_OWNER_OF_HEAD_ENTRY( (&xPendingReadyList) );                    
+                       vListRemove( &( pxUnblockedCRCB->xEventListItem ) );
+               }
+               portENABLE_INTERRUPTS();
+
+               vListRemove( &( pxUnblockedCRCB->xGenericListItem ) );
+               prvAddCoRoutineToReadyQueue( pxUnblockedCRCB ); 
+       }
+}
+/*-----------------------------------------------------------*/
+
+static inline void prvCheckDelayedList( void )
+{
+static portTickType xLastTickCount, xPassedTicks;
+corCRCB *pxCRCB;
+
+       xPassedTicks = xTaskGetTickCount() - xLastTickCount;
+       while( xPassedTicks )
+       {
+               xCoRoutineTickCount++;
+               xPassedTicks--;
+
+               /* If the tick count has overflowed we need to swap the ready lists. */
+               if( xCoRoutineTickCount == 0 )
+               {
+                       xList * pxTemp;
+
+                       /* Tick count has overflowed so we need to swap the delay lists.  If there are
+                       any items in pxDelayedCoRoutineList here then there is an error! */
+                       pxTemp = pxDelayedCoRoutineList;
+                       pxDelayedCoRoutineList = pxOverflowDelayedCoRoutineList;
+                       pxOverflowDelayedCoRoutineList = pxTemp;
+               }
+
+               /* See if this tick has made a timeout expire. */
+               while( ( pxCRCB = ( corCRCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedCoRoutineList ) ) != NULL )
+               {       
+                       if( xCoRoutineTickCount < listGET_LIST_ITEM_VALUE( &( pxCRCB->xGenericListItem ) ) )                            
+                       {                       
+                               /* Timeout not yet expired. */                                                                                                                                                  
+                               break;                                                                                                                                                          
+                       }                                                                                                                                                                               
+
+                       portDISABLE_INTERRUPTS();
+                       {
+                               /* The event could have occurred just before this critical
+                               section.  If this is the case then the generic list item will
+                               have been moved to the pending ready list and the following
+                               line is still valid.  Also the pvContainer parameter will have
+                               been set to NULL so the following lines are also valid. */
+                               vListRemove( &( pxCRCB->xGenericListItem ) );                                                                                   
+
+                               /* Is the co-routine waiting on an event also? */                                                                                               
+                               if( pxCRCB->xEventListItem.pvContainer )                                                                                                        
+                               {                                                                                                                       
+                                       vListRemove( &( pxCRCB->xEventListItem ) );                                                                                     
+                               }
+                       }
+                       portENABLE_INTERRUPTS();
+
+                       prvAddCoRoutineToReadyQueue( pxCRCB );                                                                                                  
+               }                                                                                                                                                                                                       
+       }
+
+       xLastTickCount = xCoRoutineTickCount;
+}
+/*-----------------------------------------------------------*/
+
+void vCoRoutineSchedule( void )
+{
+       /* See if any co-routines readied by events need moving to the ready lists. */
+       prvCheckPendingReadyList();
+
+       /* See if any delayed co-routines have timed out. */
+       prvCheckDelayedList();
+
+       /* Find the highest priority queue that contains ready co-routines. */
+       while( listLIST_IS_EMPTY( &( pxReadyCoRoutineLists[ uxTopCoRoutineReadyPriority ] ) ) )
+       {
+               if( uxTopCoRoutineReadyPriority == 0 )
+               {
+                       /* No more co-routines to check. */
+                       return;
+               }
+               --uxTopCoRoutineReadyPriority;
+       }
+
+       /* listGET_OWNER_OF_NEXT_ENTRY walks through the list, so the co-routines
+        of the same priority get an equal share of the processor time. */
+       listGET_OWNER_OF_NEXT_ENTRY( pxCurrentCoRoutine, &( pxReadyCoRoutineLists[ uxTopCoRoutineReadyPriority ] ) );
+
+       /* Call the co-routine. */
+       ( pxCurrentCoRoutine->pxCoRoutineFunction )( pxCurrentCoRoutine, pxCurrentCoRoutine->uxIndex );
+
+       return;
+}
+/*-----------------------------------------------------------*/
+
+static void prvInitialiseCoRoutineLists( void )
+{
+unsigned portBASE_TYPE uxPriority;
+
+       for( uxPriority = 0; uxPriority < configMAX_CO_ROUTINE_PRIORITIES; uxPriority++ )
+       {
+               vListInitialise( ( xList * ) &( pxReadyCoRoutineLists[ uxPriority ] ) );
+       }
+
+       vListInitialise( ( xList * ) &xDelayedCoRoutineList1 );
+       vListInitialise( ( xList * ) &xDelayedCoRoutineList2 );
+       vListInitialise( ( xList * ) &xPendingReadyList );
+
+       /* Start with pxDelayedCoRoutineList using list1 and the
+       pxOverflowDelayedCoRoutineList using list2. */
+       pxDelayedCoRoutineList = &xDelayedCoRoutineList1;
+       pxOverflowDelayedCoRoutineList = &xDelayedCoRoutineList2;
+}
+/*-----------------------------------------------------------*/
+
+signed portBASE_TYPE xCoRoutineRemoveFromEventList( const xList *pxEventList )
+{
+corCRCB *pxUnblockedCRCB;
+signed portBASE_TYPE xReturn;
+
+       /* This function is called from within an interrupt.  It can only access
+       event lists and the pending ready list. */
+       pxUnblockedCRCB = ( corCRCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList );
+       vListRemove( &( pxUnblockedCRCB->xEventListItem ) );
+       vListInsertEnd( ( xList * ) &( xPendingReadyList ), &( pxUnblockedCRCB->xEventListItem ) );
+
+       if( pxUnblockedCRCB->uxPriority >= pxCurrentCoRoutine->uxPriority )
+       {
+               xReturn = pdTRUE;
+       }
+       else
+       {
+               xReturn = pdFALSE;
+       }
+
+       return xReturn;
+}
+
diff --git a/FreeRTOS/include/FreeRTOS.h b/FreeRTOS/include/FreeRTOS.h
new file mode 100644 (file)
index 0000000..676bda3
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+       FreeRTOS.org V4.4.0 - Copyright (C) 2003-2007 Richard Barry.
+
+       This file is part of the FreeRTOS.org distribution.
+
+       FreeRTOS.org 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 2 of the License, or
+       (at your option) any later version.
+
+       FreeRTOS.org 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 FreeRTOS.org; if not, write to the Free Software
+       Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+       A special exception to the GPL can be applied should you wish to distribute
+       a combined work that includes FreeRTOS.org, without being obliged to provide
+       the source code for any proprietary components.  See the licensing section 
+       of http://www.FreeRTOS.org for full details of how and when the exception
+       can be applied.
+
+       ***************************************************************************
+       See http://www.FreeRTOS.org for documentation, latest information, license 
+       and contact details.  Please ensure to read the configuration and relevant 
+       port sections of the online documentation.
+
+       Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along
+       with commercial development and support options.
+       ***************************************************************************
+*/
+
+#ifndef INC_FREERTOS_H
+#define INC_FREERTOS_H
+
+
+/* 
+ * Include the generic headers required for the FreeRTOS port being used. 
+ */
+#include <stddef.h>
+
+/* Basic FreeRTOS definitions. */
+#include "projdefs.h"
+
+/* Application specific configuration options. */
+#include "FreeRTOSConfig.h"
+
+/* Definitions specific to the port being used. */
+#include "portable.h"
+
+
+
+
+
+
+
+/*
+ * Check all the required application specific macros have been defined. 
+ * These macros are application specific and (as downloaded) are defined
+ * within FreeRTOSConfig.h.
+ */
+
+#ifndef configUSE_PREEMPTION
+       #error Missing definition:  configUSE_PREEMPTION should be defined in FreeRTOSConfig.h as either 1 or 0.  See the Configuration section of the FreeRTOS API documentation for details.
+#endif
+
+#ifndef configUSE_IDLE_HOOK
+       #error Missing definition:  configUSE_IDLE_HOOK should be defined in FreeRTOSConfig.h as either 1 or 0.  See the Configuration section of the FreeRTOS API documentation for details.
+#endif
+
+#ifndef configUSE_TICK_HOOK
+       #error Missing definition:  configUSE_TICK_HOOK should be defined in FreeRTOSConfig.h as either 1 or 0.  See the Configuration section of the FreeRTOS API documentation for details.
+#endif
+
+#ifndef configUSE_CO_ROUTINES
+       #error  Missing definition:  configUSE_CO_ROUTINES should be defined in FreeRTOSConfig.h as either 1 or 0.  See the Configuration section of the FreeRTOS API documentation for details.
+#endif
+
+#ifndef INCLUDE_vTaskPrioritySet
+       #error Missing definition:  INCLUDE_vTaskPrioritySet should be defined in FreeRTOSConfig.h as either 1 or 0.  See the Configuration section of the FreeRTOS API documentation for details.
+#endif
+
+#ifndef INCLUDE_uxTaskPriorityGet
+       #error Missing definition:  INCLUDE_uxTaskPriorityGet should be defined in FreeRTOSConfig.h as either 1 or 0.  See the Configuration section of the FreeRTOS API documentation for details.
+#endif
+
+#ifndef INCLUDE_vTaskDelete            
+       #error Missing definition:  INCLUDE_vTaskDelete          should be defined in FreeRTOSConfig.h as either 1 or 0.  See the Configuration section of the FreeRTOS API documentation for details.
+#endif
+
+#ifndef INCLUDE_vTaskCleanUpResources
+       #error Missing definition:  INCLUDE_vTaskCleanUpResources should be defined in FreeRTOSConfig.h as either 1 or 0.  See the Configuration section of the FreeRTOS API documentation for details.
+#endif
+
+#ifndef INCLUDE_vTaskSuspend   
+       #error Missing definition:  INCLUDE_vTaskSuspend         should be defined in FreeRTOSConfig.h as either 1 or 0.  See the Configuration section of the FreeRTOS API documentation for details.
+#endif
+
+#ifndef INCLUDE_vTaskDelayUntil
+       #error Missing definition:  INCLUDE_vTaskDelayUntil should be defined in FreeRTOSConfig.h as either 1 or 0.  See the Configuration section of the FreeRTOS API documentation for details.
+#endif
+
+#ifndef INCLUDE_vTaskDelay
+       #error Missing definition:  INCLUDE_vTaskDelay should be defined in FreeRTOSConfig.h as either 1 or 0.  See the Configuration section of the FreeRTOS API documentation for details.
+#endif
+
+#ifndef configUSE_16_BIT_TICKS
+       #error Missing definition:  configUSE_16_BIT_TICKS should be defined in FreeRTOSConfig.h as either 1 or 0.  See the Configuration section of the FreeRTOS API documentation for details.
+#endif
+
+#endif
diff --git a/FreeRTOS/include/croutine.h b/FreeRTOS/include/croutine.h
new file mode 100644 (file)
index 0000000..d3b5216
--- /dev/null
@@ -0,0 +1,716 @@
+/*
+       FreeRTOS.org V4.4.0 - Copyright (C) 2003-2007 Richard Barry.
+
+       This file is part of the FreeRTOS.org distribution.
+
+       FreeRTOS.org 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 2 of the License, or
+       (at your option) any later version.
+
+       FreeRTOS.org 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 FreeRTOS.org; if not, write to the Free Software
+       Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+       A special exception to the GPL can be applied should you wish to distribute
+       a combined work that includes FreeRTOS.org, without being obliged to provide
+       the source code for any proprietary components.  See the licensing section
+       of http://www.FreeRTOS.org for full details of how and when the exception
+       can be applied.
+
+       ***************************************************************************
+       See http://www.FreeRTOS.org for documentation, latest information, license
+       and contact details.  Please ensure to read the configuration and relevant
+       port sections of the online documentation.
+
+       Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along
+       with commercial development and support options.
+       ***************************************************************************
+*/
+#ifndef CO_ROUTINE_H
+#define CO_ROUTINE_H
+
+#include "list.h"
+
+/* Used to hide the implementation of the co-routine control block.  The
+control block structure however has to be included in the header due to
+the macro implementation of the co-routine functionality. */
+typedef void * xCoRoutineHandle;
+
+/* Defines the prototype to which co-routine functions must conform. */
+typedef void (*crCOROUTINE_CODE)( xCoRoutineHandle, unsigned portBASE_TYPE );
+
+typedef struct corCoRoutineControlBlock
+{
+       crCOROUTINE_CODE                pxCoRoutineFunction;
+       xListItem                               xGenericListItem;       /*< List item used to place the CRCB in ready and blocked queues. */
+       xListItem                               xEventListItem;         /*< List item used to place the CRCB in event lists. */
+       unsigned portBASE_TYPE  uxPriority;                     /*< The priority of the co-routine in relation to other co-routines. */
+       unsigned portBASE_TYPE  uxIndex;                        /*< Used to distinguish between co-routines when multiple co-routines use the same co-routine function. */
+       unsigned portSHORT              uxState;                        /*< Used internally by the co-routine implementation. */
+} corCRCB; /* Co-routine control block.  Note must be identical in size down to uxPriority with tskTCB. */
+
+/**
+ * croutine. h
+ *<pre>
+ portBASE_TYPE xCoRoutineCreate(
+                                 crCOROUTINE_CODE pxCoRoutineCode,
+                                 unsigned portBASE_TYPE uxPriority,
+                                 unsigned portBASE_TYPE uxIndex
+                               );</pre>
+ *
+ * Create a new co-routine and add it to the list of co-routines that are
+ * ready to run.
+ *
+ * @param pxCoRoutineCode Pointer to the co-routine function.  Co-routine
+ * functions require special syntax - see the co-routine section of the WEB
+ * documentation for more information.
+ *
+ * @param uxPriority The priority with respect to other co-routines at which
+ *  the co-routine will run.
+ *
+ * @param uxIndex Used to distinguish between different co-routines that
+ * execute the same function.  See the example below and the co-routine section
+ * of the WEB documentation for further information.
+ *
+ * @return pdPASS if the co-routine was successfully created and added to a ready
+ * list, otherwise an error code defined with ProjDefs.h.
+ *
+ * Example usage:
+   <pre>
+ // Co-routine to be created.
+ void vFlashCoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )
+ {
+ // Variables in co-routines must be declared static if they must maintain value across a blocking call.
+ // This may not be necessary for const variables.
+ static const char cLedToFlash[ 2 ] = { 5, 6 };
+ static const portTickType xTimeToDelay[ 2 ] = { 200, 400 };
+
+     // Must start every co-routine with a call to crSTART();
+     crSTART( xHandle );
+
+     for( ;; )
+     {
+         // This co-routine just delays for a fixed period, then toggles
+         // an LED.  Two co-routines are created using this function, so
+         // the uxIndex parameter is used to tell the co-routine which
+         // LED to flash and how long to delay.  This assumes xQueue has
+         // already been created.
+         vParTestToggleLED( cLedToFlash[ uxIndex ] );
+         crDELAY( xHandle, uxFlashRates[ uxIndex ] );
+     }
+
+     // Must end every co-routine with a call to crEND();
+     crEND();
+ }
+
+ // Function that creates two co-routines.
+ void vOtherFunction( void )
+ {
+ unsigned char ucParameterToPass;
+ xTaskHandle xHandle;
+               
+     // Create two co-routines at priority 0.  The first is given index 0
+     // so (from the code above) toggles LED 5 every 200 ticks.  The second
+     // is given index 1 so toggles LED 6 every 400 ticks.
+     for( uxIndex = 0; uxIndex < 2; uxIndex++ )
+     {
+         xCoRoutineCreate( vFlashCoRoutine, 0, uxIndex );
+     }
+ }
+   </pre>
+ * \defgroup xCoRoutineCreate xCoRoutineCreate
+ * \ingroup Tasks
+ */
+signed portBASE_TYPE xCoRoutineCreate( crCOROUTINE_CODE pxCoRoutineCode, unsigned portBASE_TYPE uxPriority, unsigned portBASE_TYPE uxIndex );
+
+
+/**
+ * croutine. h
+ *<pre>
+ void vCoRoutineSchedule( void );</pre>
+ *
+ * Run a co-routine.
+ *
+ * vCoRoutineSchedule() executes the highest priority co-routine that is able
+ * to run.  The co-routine will execute until it either blocks, yields or is
+ * preempted by a task.  Co-routines execute cooperatively so one
+ * co-routine cannot be preempted by another, but can be preempted by a task.
+ *
+ * If an application comprises of both tasks and co-routines then
+ * vCoRoutineSchedule should be called from the idle task (in an idle task
+ * hook).
+ *
+ * Example usage:
+   <pre>
+ // This idle task hook will schedule a co-routine each time it is called.
+ // The rest of the idle task will execute between co-routine calls.
+ void vApplicationIdleHook( void )
+ {
+       vCoRoutineSchedule();
+ }
+
+ // Alternatively, if you do not require any other part of the idle task to
+ // execute, the idle task hook can call vCoRoutineScheduler() within an
+ // infinite loop.
+ void vApplicationIdleHook( void )
+ {
+    for( ;; )
+    {
+        vCoRoutineSchedule();
+    }
+ }
+ </pre>
+ * \defgroup vCoRoutineSchedule vCoRoutineSchedule
+ * \ingroup Tasks
+ */
+void vCoRoutineSchedule( void );
+
+/**
+ * croutine. h
+ * <pre>
+ crSTART( xCoRoutineHandle xHandle );</pre>
+ *
+ * This macro MUST always be called at the start of a co-routine function.
+ *
+ * Example usage:
+   <pre>
+ // Co-routine to be created.
+ void vACoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )
+ {
+ // Variables in co-routines must be declared static if they must maintain value across a blocking call.
+ static portLONG ulAVariable;
+
+     // Must start every co-routine with a call to crSTART();
+     crSTART( xHandle );
+
+     for( ;; )
+     {
+          // Co-routine functionality goes here.
+     }
+
+     // Must end every co-routine with a call to crEND();
+     crEND();
+ }</pre>
+ * \defgroup crSTART crSTART
+ * \ingroup Tasks
+ */
+#define crSTART( pxCRCB ) switch( ( ( corCRCB * )pxCRCB )->uxState ) { case 0:
+
+/**
+ * croutine. h
+ * <pre>
+ crEND();</pre>
+ *
+ * This macro MUST always be called at the end of a co-routine function.
+ *
+ * Example usage:
+   <pre>
+ // Co-routine to be created.
+ void vACoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )
+ {
+ // Variables in co-routines must be declared static if they must maintain value across a blocking call.
+ static portLONG ulAVariable;
+
+     // Must start every co-routine with a call to crSTART();
+     crSTART( xHandle );
+
+     for( ;; )
+     {
+          // Co-routine functionality goes here.
+     }
+
+     // Must end every co-routine with a call to crEND();
+     crEND();
+ }</pre>
+ * \defgroup crSTART crSTART
+ * \ingroup Tasks
+ */
+#define crEND() }
+
+/*
+ * These macros are intended for internal use by the co-routine implementation
+ * only.  The macros should not be used directly by application writers.
+ */
+#define crSET_STATE0( xHandle ) ( ( corCRCB * )xHandle)->uxState = (__LINE__ * 2); return; case (__LINE__ * 2):
+#define crSET_STATE1( xHandle ) ( ( corCRCB * )xHandle)->uxState = ((__LINE__ * 2)+1); return; case ((__LINE__ * 2)+1):
+
+/**
+ * croutine. h
+ *<pre>
+ crDELAY( xCoRoutineHandle xHandle, portTickType xTicksToDelay );</pre>
+ *
+ * Delay a co-routine for a fixed period of time.
+ *
+ * crDELAY can only be called from the co-routine function itself - not
+ * from within a function called by the co-routine function.  This is because
+ * co-routines do not maintain their own stack.
+ *
+ * @param xHandle The handle of the co-routine to delay.  This is the xHandle
+ * parameter of the co-routine function.
+ *
+ * @param xTickToDelay The number of ticks that the co-routine should delay
+ * for.  The actual amount of time this equates to is defined by
+ * configTICK_RATE_HZ (set in FreeRTOSConfig.h).  The constant portTICK_RATE_MS
+ * can be used to convert ticks to milliseconds.
+ *
+ * Example usage:
+   <pre>
+ // Co-routine to be created.
+ void vACoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )
+ {
+ // Variables in co-routines must be declared static if they must maintain value across a blocking call.
+ // This may not be necessary for const variables.
+ // We are to delay for 200ms.
+ static const xTickType xDelayTime = 200 / portTICK_RATE_MS;
+
+     // Must start every co-routine with a call to crSTART();
+     crSTART( xHandle );
+
+     for( ;; )
+     {
+        // Delay for 200ms.
+        crDELAY( xHandle, xDelayTime );
+
+        // Do something here.
+     }
+
+     // Must end every co-routine with a call to crEND();
+     crEND();
+ }</pre>
+ * \defgroup crDELAY crDELAY
+ * \ingroup Tasks
+ */
+#define crDELAY( xHandle, xTicksToDelay )                                                                                              \
+       if( xTicksToDelay > 0 )                                                                                                                         \
+       {                                                                                                                                                                       \
+               vCoRoutineAddToDelayedList( xTicksToDelay, NULL );                                                              \
+       }                                                                                                                                                                       \
+       crSET_STATE0( xHandle );
+
+/**
+ * <pre>
+ crQUEUE_SEND(
+                  xCoRoutineHandle xHandle,
+                  xQueueHandle pxQueue,
+                  void *pvItemToQueue,
+                  portTickType xTicksToWait,
+                  portBASE_TYPE *pxResult
+             )</pre>
+ *
+ * The macro's crQUEUE_SEND() and crQUEUE_RECEIVE() are the co-routine
+ * equivalent to the xQueueSend() and xQueueReceive() functions used by tasks.
+ *
+ * crQUEUE_SEND and crQUEUE_RECEIVE can only be used from a co-routine whereas
+ * xQueueSend() and xQueueReceive() can only be used from tasks.
+ *
+ * crQUEUE_SEND can only be called from the co-routine function itself - not
+ * from within a function called by the co-routine function.  This is because
+ * co-routines do not maintain their own stack.
+ *
+ * See the co-routine section of the WEB documentation for information on
+ * passing data between tasks and co-routines and between ISR's and
+ * co-routines.
+ *
+ * @param xHandle The handle of the calling co-routine.  This is the xHandle
+ * parameter of the co-routine function.
+ *
+ * @param pxQueue The handle of the queue on which the data will be posted.
+ * The handle is obtained as the return value when the queue is created using
+ * the xQueueCreate() API function.
+ *
+ * @param pvItemToQueue A pointer to the data being posted onto the queue.
+ * The number of bytes of each queued item is specified when the queue is
+ * created.  This number of bytes is copied from pvItemToQueue into the queue
+ * itself.
+ *
+ * @param xTickToDelay The number of ticks that the co-routine should block
+ * to wait for space to become available on the queue, should space not be
+ * available immediately. The actual amount of time this equates to is defined
+ * by configTICK_RATE_HZ (set in FreeRTOSConfig.h).  The constant
+ * portTICK_RATE_MS can be used to convert ticks to milliseconds (see example
+ * below).
+ *
+ * @param pxResult The variable pointed to by pxResult will be set to pdPASS if
+ * data was successfully posted onto the queue, otherwise it will be set to an
+ * error defined within ProjDefs.h.
+ *
+ * Example usage:
+   <pre>
+ // Co-routine function that blocks for a fixed period then posts a number onto
+ // a queue.
+ static void prvCoRoutineFlashTask( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )
+ {
+ // Variables in co-routines must be declared static if they must maintain value across a blocking call.
+ static portBASE_TYPE xNumberToPost = 0;
+ static portBASE_TYPE xResult;
+
+    // Co-routines must begin with a call to crSTART().
+    crSTART( xHandle );
+
+    for( ;; )
+    {
+        // This assumes the queue has already been created.
+        crQUEUE_SEND( xHandle, xCoRoutineQueue, &xNumberToPost, NO_DELAY, &xResult );
+
+        if( xResult != pdPASS )
+        {
+            // The message was not posted!
+        }
+
+        // Increment the number to be posted onto the queue.
+        xNumberToPost++;
+
+        // Delay for 100 ticks.
+        crDELAY( xHandle, 100 );
+    }
+
+    // Co-routines must end with a call to crEND().
+    crEND();
+ }</pre>
+ * \defgroup crQUEUE_SEND crQUEUE_SEND
+ * \ingroup Tasks
+ */
+#define crQUEUE_SEND( xHandle, pxQueue, pvItemToQueue, xTicksToWait, pxResult )                        \
+{                                                                                                                                                                              \
+       *pxResult = xQueueCRSend( pxQueue, pvItemToQueue, xTicksToWait );                                       \
+       if( *pxResult == errQUEUE_BLOCKED )                                                                                                     \
+       {                                                                                                                                                                       \
+               crSET_STATE0( xHandle );                                                                                                                \
+               *pxResult = xQueueCRSend( pxQueue, pvItemToQueue, 0 );                                                  \
+       }                                                                                                                                                                       \
+       if( *pxResult == errQUEUE_YIELD )                                                                                                       \
+       {                                                                                                                                                                       \
+               crSET_STATE1( xHandle );                                                                                                                \
+               *pxResult = pdPASS;                                                                                                                             \
+       }                                                                                                                                                                       \
+}
+
+/**
+ * croutine. h
+ * <pre>
+  crQUEUE_RECEIVE(
+                     xCoRoutineHandle xHandle,
+                     xQueueHandle pxQueue,
+                     void *pvBuffer,
+                     portTickType xTicksToWait,
+                     portBASE_TYPE *pxResult
+                 )</pre>
+ *
+ * The macro's crQUEUE_SEND() and crQUEUE_RECEIVE() are the co-routine
+ * equivalent to the xQueueSend() and xQueueReceive() functions used by tasks.
+ *
+ * crQUEUE_SEND and crQUEUE_RECEIVE can only be used from a co-routine whereas
+ * xQueueSend() and xQueueReceive() can only be used from tasks.
+ *
+ * crQUEUE_RECEIVE can only be called from the co-routine function itself - not
+ * from within a function called by the co-routine function.  This is because
+ * co-routines do not maintain their own stack.
+ *
+ * See the co-routine section of the WEB documentation for information on
+ * passing data between tasks and co-routines and between ISR's and
+ * co-routines.
+ *
+ * @param xHandle The handle of the calling co-routine.  This is the xHandle
+ * parameter of the co-routine function.
+ *
+ * @param pxQueue The handle of the queue from which the data will be received.
+ * The handle is obtained as the return value when the queue is created using
+ * the xQueueCreate() API function.
+ *
+ * @param pvBuffer The buffer into which the received item is to be copied.
+ * The number of bytes of each queued item is specified when the queue is
+ * created.  This number of bytes is copied into pvBuffer.
+ *
+ * @param xTickToDelay The number of ticks that the co-routine should block
+ * to wait for data to become available from the queue, should data not be
+ * available immediately. The actual amount of time this equates to is defined
+ * by configTICK_RATE_HZ (set in FreeRTOSConfig.h).  The constant
+ * portTICK_RATE_MS can be used to convert ticks to milliseconds (see the
+ * crQUEUE_SEND example).
+ *
+ * @param pxResult The variable pointed to by pxResult will be set to pdPASS if
+ * data was successfully retrieved from the queue, otherwise it will be set to
+ * an error code as defined within ProjDefs.h.
+ *
+ * Example usage:
+ <pre>
+ // A co-routine receives the number of an LED to flash from a queue.  It
+ // blocks on the queue until the number is received.
+ static void prvCoRoutineFlashWorkTask( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )
+ {
+ // Variables in co-routines must be declared static if they must maintain value across a blocking call.
+ static portBASE_TYPE xResult;
+ static unsigned portBASE_TYPE uxLEDToFlash;
+
+    // All co-routines must start with a call to crSTART().
+    crSTART( xHandle );
+
+    for( ;; )
+    {
+        // Wait for data to become available on the queue.
+        crQUEUE_RECEIVE( xHandle, xCoRoutineQueue, &uxLEDToFlash, portMAX_DELAY, &xResult );
+
+        if( xResult == pdPASS )
+        {
+            // We received the LED to flash - flash it!
+            vParTestToggleLED( uxLEDToFlash );
+        }
+    }
+
+    crEND();
+ }</pre>
+ * \defgroup crQUEUE_RECEIVE crQUEUE_RECEIVE
+ * \ingroup Tasks
+ */
+#define crQUEUE_RECEIVE( xHandle, pxQueue, pvBuffer, xTicksToWait, pxResult )                  \
+{                                                                                                                                                                              \
+       *pxResult = xQueueCRReceive( pxQueue, pvBuffer, xTicksToWait );                                         \
+       if( *pxResult == errQUEUE_BLOCKED )                                                                                             \
+       {                                                                                                                                                                       \
+               crSET_STATE0( xHandle );                                                                                                                \
+               *pxResult = xQueueCRReceive( pxQueue, pvBuffer, 0 );                                                    \
+       }                                                                                                                                                                       \
+       if( *pxResult == errQUEUE_YIELD )                                                                                                       \
+       {                                                                                                                                                                       \
+               crSET_STATE1( xHandle );                                                                                                                \
+               *pxResult = pdPASS;                                                                                                                             \
+       }                                                                                                                                                                       \
+}
+
+/**
+ * croutine. h
+ * <pre>
+  crQUEUE_SEND_FROM_ISR(
+                            xQueueHandle pxQueue,
+                            void *pvItemToQueue,
+                            portBASE_TYPE xCoRoutinePreviouslyWoken
+                       )</pre>
+ *
+ * The macro's crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() are the
+ * co-routine equivalent to the xQueueSendFromISR() and xQueueReceiveFromISR()
+ * functions used by tasks.
+ *
+ * crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() can only be used to
+ * pass data between a co-routine and and ISR, whereas xQueueSendFromISR() and
+ * xQueueReceiveFromISR() can only be used to pass data between a task and and
+ * ISR.
+ *
+ * crQUEUE_SEND_FROM_ISR can only be called from an ISR to send data to a queue
+ * that is being used from within a co-routine.
+ *
+ * See the co-routine section of the WEB documentation for information on
+ * passing data between tasks and co-routines and between ISR's and
+ * co-routines.
+ *
+ * @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 xCoRoutinePreviouslyWoken This is included so an ISR can post onto
+ * the same queue multiple times from a single interrupt.  The first call
+ * should always pass in pdFALSE.  Subsequent calls should pass in
+ * the value returned from the previous call.
+ *
+ * @return pdTRUE if a co-routine was woken by posting onto the queue.  This is
+ * used by the ISR to determine if a context switch may be required following
+ * the ISR.
+ *
+ * Example usage:
+ <pre>
+ // A co-routine that blocks on a queue waiting for characters to be received.
+ static void vReceivingCoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )
+ {
+ portCHAR cRxedChar;
+ portBASE_TYPE xResult;
+
+     // All co-routines must start with a call to crSTART().
+     crSTART( xHandle );
+
+     for( ;; )
+     {
+         // Wait for data to become available on the queue.  This assumes the
+         // queue xCommsRxQueue has already been created!
+         crQUEUE_RECEIVE( xHandle, xCommsRxQueue, &uxLEDToFlash, portMAX_DELAY, &xResult );
+
+         // Was a character received?
+         if( xResult == pdPASS )
+         {
+             // Process the character here.
+         }
+     }
+
+     // All co-routines must end with a call to crEND().
+     crEND();
+ }
+
+ // An ISR that uses a queue to send characters received on a serial port to
+ // a co-routine.
+ void vUART_ISR( void )
+ {
+ portCHAR cRxedChar;
+ portBASE_TYPE xCRWokenByPost = pdFALSE;
+
+     // We loop around reading characters until there are none left in the UART.
+     while( UART_RX_REG_NOT_EMPTY() )
+     {
+         // Obtain the character from the UART.
+         cRxedChar = UART_RX_REG;
+
+         // Post the character onto a queue.  xCRWokenByPost will be pdFALSE
+         // the first time around the loop.  If the post causes a co-routine
+         // to be woken (unblocked) then xCRWokenByPost will be set to pdTRUE.
+         // In this manner we can ensure that if more than one co-routine is
+         // blocked on the queue only one is woken by this ISR no matter how
+         // many characters are posted to the queue.
+         xCRWokenByPost = crQUEUE_SEND_FROM_ISR( xCommsRxQueue, &cRxedChar, xCRWokenByPost );
+     }
+ }</pre>
+ * \defgroup crQUEUE_SEND_FROM_ISR crQUEUE_SEND_FROM_ISR
+ * \ingroup Tasks
+ */
+#define crQUEUE_SEND_FROM_ISR( pxQueue, pvItemToQueue, xCoRoutinePreviouslyWoken ) xQueueCRSendFromISR( pxQueue, pvItemToQueue, xCoRoutinePreviouslyWoken )
+
+
+/**
+ * croutine. h
+ * <pre>
+  crQUEUE_SEND_FROM_ISR(
+                            xQueueHandle pxQueue,
+                            void *pvBuffer,
+                            portBASE_TYPE * pxCoRoutineWoken
+                       )</pre>
+ *
+ * The macro's crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() are the
+ * co-routine equivalent to the xQueueSendFromISR() and xQueueReceiveFromISR()
+ * functions used by tasks.
+ *
+ * crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() can only be used to
+ * pass data between a co-routine and and ISR, whereas xQueueSendFromISR() and
+ * xQueueReceiveFromISR() can only be used to pass data between a task and and
+ * ISR.
+ *
+ * crQUEUE_RECEIVE_FROM_ISR can only be called from an ISR to receive data
+ * from a queue that is being used from within a co-routine (a co-routine
+ * posted to the queue).
+ *
+ * See the co-routine section of the WEB documentation for information on
+ * passing data between tasks and co-routines and between ISR's and
+ * co-routines.
+ *
+ * @param xQueue The handle to the queue on which the item is to be posted.
+ *
+ * @param pvBuffer A pointer to a buffer into which the received item will be
+ * placed.  The size of the items the queue will hold was defined when the
+ * queue was created, so this many bytes will be copied from the queue into
+ * pvBuffer.
+ *
+ * @param pxCoRoutineWoken A co-routine may be blocked waiting for space to become
+ * available on the queue.  If crQUEUE_RECEIVE_FROM_ISR causes such a
+ * co-routine to unblock *pxCoRoutineWoken will get set to pdTRUE, otherwise
+ * *pxCoRoutineWoken will remain unchanged.
+ *
+ * @return pdTRUE an item was successfully received from the queue, otherwise
+ * pdFALSE.
+ *
+ * Example usage:
+ <pre>
+ // A co-routine that posts a character to a queue then blocks for a fixed
+ // period.  The character is incremented each time.
+ static void vSendingCoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )
+ {
+ // cChar holds its value while this co-routine is blocked and must therefore
+ // be declared static.
+ static portCHAR cCharToTx = 'a';
+ portBASE_TYPE xResult;
+
+     // All co-routines must start with a call to crSTART().
+     crSTART( xHandle );
+
+     for( ;; )
+     {
+         // Send the next character to the queue.
+         crQUEUE_SEND( xHandle, xCoRoutineQueue, &cCharToTx, NO_DELAY, &xResult );
+
+         if( xResult == pdPASS )
+         {
+             // The character was successfully posted to the queue.
+         }
+                else
+                {
+                       // Could not post the character to the queue.
+                }
+
+         // Enable the UART Tx interrupt to cause an interrupt in this
+                // hypothetical UART.  The interrupt will obtain the character
+                // from the queue and send it.
+                ENABLE_RX_INTERRUPT();
+
+                // Increment to the next character then block for a fixed period.
+                // cCharToTx will maintain its value across the delay as it is
+                // declared static.
+                cCharToTx++;
+                if( cCharToTx > 'x' )
+                {
+                       cCharToTx = 'a';
+                }
+                crDELAY( 100 );
+     }
+
+     // All co-routines must end with a call to crEND().
+     crEND();
+ }
+
+ // An ISR that uses a queue to receive characters to send on a UART.
+ void vUART_ISR( void )
+ {
+ portCHAR cCharToTx;
+ portBASE_TYPE xCRWokenByPost = pdFALSE;
+
+     while( UART_TX_REG_EMPTY() )
+     {
+         // Are there any characters in the queue waiting to be sent?
+                // xCRWokenByPost will automatically be set to pdTRUE if a co-routine
+                // is woken by the post - ensuring that only a single co-routine is
+                // woken no matter how many times we go around this loop.
+         if( crQUEUE_RECEIVE_FROM_ISR( pxQueue, &cCharToTx, &xCRWokenByPost ) )
+                {
+                        SEND_CHARACTER( cCharToTx );
+                }
+     }
+ }</pre>
+ * \defgroup crQUEUE_RECEIVE_FROM_ISR crQUEUE_RECEIVE_FROM_ISR
+ * \ingroup Tasks
+ */
+#define crQUEUE_RECEIVE_FROM_ISR( pxQueue, pvBuffer, pxCoRoutineWoken ) xQueueCRReceiveFromISR( pxQueue, pvBuffer, pxCoRoutineWoken )
+
+/*
+ * This function is intended for internal use by the co-routine macros only.
+ * The macro nature of the co-routine implementation requires that the
+ * prototype appears here.  The function should not be used by application
+ * writers.
+ *
+ * Removes the current co-routine from its ready list and places it in the
+ * appropriate delayed list.
+ */
+void vCoRoutineAddToDelayedList( portTickType xTicksToDelay, xList *pxEventList );
+
+/*
+ * This function is intended for internal use by the queue implementation only.
+ * The function should not be used by application writers.
+ *
+ * Removes the highest priority co-routine from the event list and places it in
+ * the pending ready list.
+ */
+signed portBASE_TYPE xCoRoutineRemoveFromEventList( const xList *pxEventList );
+
+
+#endif /* CO_ROUTINE_H */
diff --git a/FreeRTOS/include/list.h b/FreeRTOS/include/list.h
new file mode 100644 (file)
index 0000000..f3702c1
--- /dev/null
@@ -0,0 +1,282 @@
+/*
+       FreeRTOS.org V4.4.0 - Copyright (C) 2003-2007 Richard Barry.
+
+       This file is part of the FreeRTOS.org distribution.
+
+       FreeRTOS.org 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 2 of the License, or
+       (at your option) any later version.
+
+       FreeRTOS.org 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 FreeRTOS.org; if not, write to the Free Software
+       Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+       A special exception to the GPL can be applied should you wish to distribute
+       a combined work that includes FreeRTOS.org, without being obliged to provide
+       the source code for any proprietary components.  See the licensing section
+       of http://www.FreeRTOS.org for full details of how and when the exception
+       can be applied.
+
+       ***************************************************************************
+       See http://www.FreeRTOS.org for documentation, latest information, license
+       and contact details.  Please ensure to read the configuration and relevant
+       port sections of the online documentation.
+
+       Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along
+       with commercial development and support options.
+       ***************************************************************************
+*/
+
+/*
+ * This is the list implementation used by the scheduler.  While it is tailored
+ * heavily for the schedulers needs, it is also available for use by
+ * application code.
+ *
+ * xLists can only store pointers to xListItems.  Each xListItem contains a
+ * numeric value (xItemValue).  Most of the time the lists are sorted in
+ * descending item value order.
+ *
+ * Lists are created already containing one list item.  The value of this
+ * item is the maximum possible that can be stored, it is therefore always at
+ * the end of the list and acts as a marker.  The list member pxHead always
+ * points to this marker - even though it is at the tail of the list.  This
+ * is because the tail contains a wrap back pointer to the true head of
+ * the list.
+ *
+ * In addition to it's value, each list item contains a pointer to the next
+ * item in the list (pxNext), a pointer to the list it is in (pxContainer)
+ * and a pointer to back to the object that contains it.  These later two
+ * pointers are included for efficiency of list manipulation.  There is
+ * effectively a two way link between the object containing the list item and
+ * the list item itself.
+ *
+ *
+ * \page ListIntroduction List Implementation
+ * \ingroup FreeRTOSIntro
+ */
+
+/*
+       Changes from V4.3.1
+
+       + Included local const within listGET_OWNER_OF_NEXT_ENTRY() to assist
+         compiler with optimisation.  Thanks B.R.
+*/
+
+#ifndef LIST_H
+#define LIST_H
+
+/*
+ * Definition of the only type of object that a list can contain.
+ */
+struct xLIST_ITEM
+{
+       portTickType xItemValue;                                /*< The value being listed.  In most cases this is used to sort the list in descending order. */
+       volatile struct xLIST_ITEM * pxNext;    /*< Pointer to the next xListItem in the list. */
+       volatile struct xLIST_ITEM * pxPrevious;/*< Pointer to the previous xListItem in the list. */
+       void * pvOwner;                                                 /*< Pointer to the object (normally a TCB) that contains the list item.  There is therefore a two way link between the object containing the list item and the list item itself. */
+       void * pvContainer;                                             /*< Pointer to the list in which this list item is placed (if any). */
+};
+typedef struct xLIST_ITEM xListItem;           /* For some reason lint wants this as two separate definitions. */
+
+struct xMINI_LIST_ITEM
+{
+       portTickType xItemValue;
+       volatile struct xLIST_ITEM *pxNext;
+       volatile struct xLIST_ITEM *pxPrevious;
+};
+typedef struct xMINI_LIST_ITEM xMiniListItem;
+
+/*
+ * Definition of the type of queue used by the scheduler.
+ */
+typedef struct xLIST
+{
+       volatile unsigned portBASE_TYPE uxNumberOfItems;
+       volatile xListItem * pxIndex;                   /*< Used to walk through the list.  Points to the last item returned by a call to pvListGetOwnerOfNextEntry (). */
+       volatile xMiniListItem xListEnd;                /*< List item that contains the maximum possible item value meaning it is always at the end of the list and is therefore used as a marker. */
+} xList;
+
+/*
+ * Access macro to set the owner of a list item.  The owner of a list item
+ * is the object (usually a TCB) that contains the list item.
+ *
+ * \page listSET_LIST_ITEM_OWNER listSET_LIST_ITEM_OWNER
+ * \ingroup LinkedList
+ */
+#define listSET_LIST_ITEM_OWNER( pxListItem, pxOwner )         ( pxListItem )->pvOwner = ( void * ) pxOwner
+
+/*
+ * Access macro to set the value of the list item.  In most cases the value is
+ * used to sort the list in descending order.
+ *
+ * \page listSET_LIST_ITEM_VALUE listSET_LIST_ITEM_VALUE
+ * \ingroup LinkedList
+ */
+#define listSET_LIST_ITEM_VALUE( pxListItem, xValue )          ( pxListItem )->xItemValue = xValue
+
+/*
+ * Access macro the retrieve the value of the list item.  The value can
+ * represent anything - for example a the priority of a task, or the time at
+ * which a task should be unblocked.
+ *
+ * \page listGET_LIST_ITEM_VALUE listGET_LIST_ITEM_VALUE
+ * \ingroup LinkedList
+ */
+#define listGET_LIST_ITEM_VALUE( pxListItem )                          ( ( pxListItem )->xItemValue )
+
+/*
+ * Access macro to determine if a list contains any items.  The macro will
+ * only have the value true if the list is empty.
+ *
+ * \page listLIST_IS_EMPTY listLIST_IS_EMPTY
+ * \ingroup LinkedList
+ */
+#define listLIST_IS_EMPTY( pxList )                            ( ( pxList )->uxNumberOfItems == ( unsigned portBASE_TYPE ) 0 )
+
+/*
+ * Access macro to return the number of items in the list.
+ */
+#define listCURRENT_LIST_LENGTH( pxList )              ( ( pxList )->uxNumberOfItems )
+
+/*
+ * Access function to obtain the owner of the next entry in a list.
+ *
+ * The list member pxIndex is used to walk through a list.  Calling
+ * listGET_OWNER_OF_NEXT_ENTRY increments pxIndex to the next item in the list
+ * and returns that entries pxOwner parameter.  Using multiple calls to this
+ * function it is therefore possible to move through every item contained in
+ * a list.
+ *
+ * The pxOwner parameter of a list item is a pointer to the object that owns
+ * the list item.  In the scheduler this is normally a task control block.
+ * The pxOwner parameter effectively creates a two way link between the list
+ * item and its owner.
+ *
+ * @param pxList The list from which the next item owner is to be returned.
+ *
+ * \page listGET_OWNER_OF_NEXT_ENTRY listGET_OWNER_OF_NEXT_ENTRY
+ * \ingroup LinkedList
+ */
+#define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList )                                                                   \
+{                                                                                                                                                                              \
+xList * const pxConstList = pxList;                                                                                                            \
+       /* Increment the index to the next item and return the item, ensuring */                        \
+       /* we don't return the marker used at the end of the list.  */                                          \
+       ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;                                            \
+       if( ( pxConstList )->pxIndex == ( xListItem * ) &( ( pxConstList )->xListEnd ) )        \
+       {                                                                                                                                                                       \
+               ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;                                    \
+       }                                                                                                                                                                       \
+       pxTCB = ( pxConstList )->pxIndex->pvOwner;                                                                                      \
+}
+
+
+/*
+ * Access function to obtain the owner of the first entry in a list.  Lists
+ * are normally sorted in ascending item value order.
+ *
+ * This function returns the pxOwner member of the first item in the list.
+ * The pxOwner parameter of a list item is a pointer to the object that owns
+ * the list item.  In the scheduler this is normally a task control block.
+ * The pxOwner parameter effectively creates a two way link between the list
+ * item and its owner.
+ *
+ * @param pxList The list from which the owner of the head item is to be
+ * returned.
+ *
+ * \page listGET_OWNER_OF_HEAD_ENTRY listGET_OWNER_OF_HEAD_ENTRY
+ * \ingroup LinkedList
+ */
+#define listGET_OWNER_OF_HEAD_ENTRY( pxList )  ( ( pxList->uxNumberOfItems != ( unsigned portBASE_TYPE ) 0 ) ? ( (&( pxList->xListEnd ))->pxNext->pvOwner ) : ( NULL ) )
+
+/*
+ * Check to see if a list item is within a list.  The list item maintains a
+ * "container" pointer that points to the list it is in.  All this macro does
+ * is check to see if the container and the list match.
+ *
+ * @param pxList The list we want to know if the list item is within.
+ * @param pxListItem The list item we want to know if is in the list.
+ * @return pdTRUE is the list item is in the list, otherwise pdFALSE.
+ * pointer against
+ */
+#define listIS_CONTAINED_WITHIN( pxList, pxListItem ) ( ( pxListItem )->pvContainer == ( void * ) pxList )
+
+/*
+ * Must be called before a list is used!  This initialises all the members
+ * of the list structure and inserts the xListEnd item into the list as a
+ * marker to the back of the list.
+ *
+ * @param pxList Pointer to the list being initialised.
+ *
+ * \page vListInitialise vListInitialise
+ * \ingroup LinkedList
+ */
+void vListInitialise( xList *pxList );
+
+/*
+ * Must be called before a list item is used.  This sets the list container to
+ * null so the item does not think that it is already contained in a list.
+ *
+ * @param pxItem Pointer to the list item being initialised.
+ *
+ * \page vListInitialiseItem vListInitialiseItem
+ * \ingroup LinkedList
+ */
+void vListInitialiseItem( xListItem *pxItem );
+
+/*
+ * Insert a list item into a list.  The item will be inserted into the list in
+ * a position determined by its item value (descending item value order).
+ *
+ * @param pxList The list into which the item is to be inserted.
+ *
+ * @param pxNewListItem The item to that is to be placed in the list.
+ *
+ * \page vListInsert vListInsert
+ * \ingroup LinkedList
+ */
+void vListInsert( xList *pxList, xListItem *pxNewListItem );
+
+/*
+ * Insert a list item into a list.  The item will be inserted in a position
+ * such that it will be the last item within the list returned by multiple
+ * calls to listGET_OWNER_OF_NEXT_ENTRY.
+ *
+ * The list member pvIndex is used to walk through a list.  Calling
+ * listGET_OWNER_OF_NEXT_ENTRY increments pvIndex to the next item in the list.
+ * Placing an item in a list using vListInsertEnd effectively places the item
+ * in the list position pointed to by pvIndex.  This means that every other
+ * item within the list will be returned by listGET_OWNER_OF_NEXT_ENTRY before
+ * the pvIndex parameter again points to the item being inserted.
+ *
+ * @param pxList The list into which the item is to be inserted.
+ *
+ * @param pxNewListItem The list item to be inserted into the list.
+ *
+ * \page vListInsertEnd vListInsertEnd
+ * \ingroup LinkedList
+ */
+void vListInsertEnd( xList *pxList, xListItem *pxNewListItem );
+
+/*
+ * Remove an item from a list.  The list item has a pointer to the list that
+ * it is in, so only the list item need be passed into the function.
+ *
+ * @param vListRemove The item to be removed.  The item will remove itself from
+ * the list pointed to by it's pxContainer parameter.
+ *
+ * \page vListRemove vListRemove
+ * \ingroup LinkedList
+ */
+void vListRemove( xListItem *pxItemToRemove );
+
+
+
+#endif
+
diff --git a/FreeRTOS/include/portable.h b/FreeRTOS/include/portable.h
new file mode 100644 (file)
index 0000000..bbd5d9a
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+       FreeRTOS.org V4.4.0 - Copyright (C) 2003-2007 Richard Barry.
+
+       This file is part of the FreeRTOS.org distribution.
+
+       FreeRTOS.org 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 2 of the License, or
+       (at your option) any later version.
+
+       FreeRTOS.org 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 FreeRTOS.org; if not, write to the Free Software
+       Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+       A special exception to the GPL can be applied should you wish to distribute
+       a combined work that includes FreeRTOS.org, without being obliged to provide
+       the source code for any proprietary components.  See the licensing section
+       of http:www.FreeRTOS.org for full details of how and when the exception
+       can be applied.
+
+       ***************************************************************************
+       See http:www.FreeRTOS.org for documentation, latest information, license
+       and contact details.  Please ensure to read the configuration and relevant
+       port sections of the online documentation.
+
+       Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along
+       with commercial development and support options.
+       ***************************************************************************
+*/
+
+/*-----------------------------------------------------------
+ * Portable layer API.  Each function must be defined for each port.
+ *----------------------------------------------------------*/
+
+#ifndef PORTABLE_H
+#define PORTABLE_H
+
+/* Include the macro file relevant to the port being used. */
+
+#ifdef OPEN_WATCOM_INDUSTRIAL_PC_PORT
+       #include "..\..\source\portable\owatcom\16bitdos\pc\portmacro.h"
+       typedef void ( __interrupt __far *pxISR )();
+#endif
+
+#ifdef OPEN_WATCOM_FLASH_LITE_186_PORT
+       #include "..\..\source\portable\owatcom\16bitdos\flsh186\portmacro.h"
+       typedef void ( __interrupt __far *pxISR )();
+#endif
+
+#ifdef GCC_MEGA_AVR
+       #include "../portable/GCC/ATMega323/portmacro.h"
+#endif
+
+#ifdef IAR_MEGA_AVR
+       #include "../portable/IAR/ATMega323/portmacro.h"
+#endif
+
+#ifdef MPLAB_PIC24_PORT
+       #include "..\..\Source\portable\MPLAB\PIC24_dsPIC\portmacro.h"
+#endif
+
+#ifdef MPLAB_DSPIC_PORT
+       #include "..\..\Source\portable\MPLAB\PIC24_dsPIC\portmacro.h"
+#endif
+
+#ifdef MPLAB_PIC18F_PORT
+       #include "..\..\source\portable\MPLAB\PIC18F\portmacro.h"
+#endif
+
+#ifdef _FEDPICC
+       #include "libFreeRTOS/Include/portmacro.h"
+#endif
+
+#ifdef SDCC_CYGNAL
+       #include "../../Source/portable/SDCC/Cygnal/portmacro.h"
+#endif
+
+#ifdef GCC_ARM7
+       #include "FreeRTOS/portable/GCC/ARM7_LPC2000/portmacro.h"
+#endif
+
+#ifdef GCC_ARM7_ECLIPSE
+       #include "portmacro.h"
+#endif
+
+#ifdef ROWLEY_LPC23xx
+       #include "../../Source/portable/GCC/ARM7_LPC23xx/portmacro.h"
+#endif
+
+#ifdef GCC_MSP430
+       #include "../../Source/portable/GCC/MSP430F449/portmacro.h"
+#endif
+
+#ifdef ROWLEY_MSP430
+       #include "../../Source/portable/Rowley/MSP430F449/portmacro.h"
+#endif
+
+#ifdef KEIL_ARM7
+       #include "..\..\Source\portable\Keil\ARM7\portmacro.h"
+#endif
+
+#ifdef SAM7_GCC
+       #include "../../Source/portable/GCC/ARM7_AT91SAM7S/portmacro.h"
+#endif
+
+#ifdef SAM7_IAR
+       #include "..\..\Source\portable\IAR\AtmelSAM7S64\portmacro.h"
+#endif
+
+#ifdef LPC2000_IAR
+       #include "..\..\Source\portable\IAR\LPC2000\portmacro.h"
+#endif
+
+#ifdef STR71X_IAR
+       #include "..\..\Source\portable\IAR\STR71x\portmacro.h"
+#endif
+
+#ifdef STR75X_IAR
+       #include "..\..\Source\portable\IAR\STR75x\portmacro.h"
+#endif
+       
+#ifdef STR75X_GCC
+       #include "..\..\Source\portable\GCC\STR75x\portmacro.h"
+#endif
+
+#ifdef STR91X_IAR
+       #include "..\..\Source\portable\IAR\STR91x\portmacro.h"
+#endif
+       
+#ifdef GCC_H8S
+       #include "../../Source/portable/GCC/H8S2329/portmacro.h"
+#endif
+
+#ifdef GCC_AT91FR40008
+       #include "../../Source/portable/GCC/ARM7_AT91FR40008/portmacro.h"
+#endif
+
+#ifdef RVDS_ARMCM3_LM3S102
+       #include "../../Source/portable/RVDS/ARM_CM3/portmacro.h"
+#endif
+
+#ifdef GCC_ARMCM3_LM3S102
+       #include "../../Source/portable/GCC/ARM_CM3/portmacro.h"
+#endif
+
+#ifdef IAR_ARM_CM3
+       #include "../../Source/portable/IAR/ARM_CM3/portmacro.h"
+#endif
+
+#ifdef IAR_ARMCM3_LM
+       #include "../../Source/portable/IAR/ARM_CM3/portmacro.h"
+#endif
+       
+#ifdef HCS12_CODE_WARRIOR
+       #include "../../Source/portable/CodeWarrior/HCS12/portmacro.h"
+#endif 
+
+#ifdef MICROBLAZE_GCC
+       #include "../../Source/portable/GCC/MicroBlaze/portmacro.h"
+#endif
+
+#ifdef TERN_EE
+       #include "..\..\Source\portable\Paradigm\Tern_EE\small\portmacro.h"
+#endif
+
+#ifdef GCC_HCS12
+       #include "../../Source/portable/GCC/HCS12/portmacro.h"
+#endif
+
+#ifdef GCC_MCF5235
+    #include "../../Source/portable/GCC/MCF5235/portmacro.h"
+#endif
+
+#ifdef BCC_INDUSTRIAL_PC_PORT
+       /* A short file name has to be used in place of the normal
+       FreeRTOSConfig.h when using the Borland compiler. */
+       #include "frconfig.h"
+       #include "..\portable\BCC\16BitDOS\PC\prtmacro.h"
+    typedef void ( __interrupt __far *pxISR )();
+#endif
+
+#ifdef BCC_FLASH_LITE_186_PORT
+       /* A short file name has to be used in place of the normal
+       FreeRTOSConfig.h when using the Borland compiler. */
+       #include "frconfig.h"
+       #include "..\portable\BCC\16BitDOS\flsh186\prtmacro.h"
+    typedef void ( __interrupt __far *pxISR )();
+#endif
+
+#ifdef __GNUC__
+   #ifdef __AVR32_AVR32A__
+          #include "portmacro.h"
+   #endif
+#endif
+
+#ifdef __ICCAVR32__
+   #ifdef __CORE__
+      #if __CORE__ == __AVR32A__
+             #include "portmacro.h"
+      #endif
+   #endif
+#endif
+
+/*
+ * Setup the stack of a new task so it is ready to be placed under the
+ * scheduler control.  The registers have to be placed on the stack in
+ * the order that the port expects to find them.
+ */
+portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters );
+
+/*
+ * Map to the memory management routines required for the port.
+ */
+void vPortUsedMem(int *bytesFree, int *bytesUsed, int *blocksFree);
+void *pvPortMalloc( size_t xSize );
+void vPortFree( void *pv );
+void vPortInitialiseBlocks( void );
+
+/*
+ * Setup the hardware ready for the scheduler to take control.  This generally
+ * sets up a tick interrupt and sets timers for the correct tick frequency.
+ */
+portBASE_TYPE xPortStartScheduler( void );
+
+/*
+ * Undo any hardware/ISR setup that was performed by xPortStartScheduler() so
+ * the hardware is left in its original condition after the scheduler stops
+ * executing.
+ */
+void vPortEndScheduler( void );
+
+
+#endif /* PORTABLE_H */
+
diff --git a/FreeRTOS/include/projdefs.h b/FreeRTOS/include/projdefs.h
new file mode 100644 (file)
index 0000000..37a6622
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+       FreeRTOS.org V4.4.0 - Copyright (C) 2003-2007 Richard Barry.
+
+       This file is part of the FreeRTOS.org distribution.
+
+       FreeRTOS.org 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 2 of the License, or
+       (at your option) any later version.
+
+       FreeRTOS.org 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 FreeRTOS.org; if not, write to the Free Software
+       Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+       A special exception to the GPL can be applied should you wish to distribute
+       a combined work that includes FreeRTOS.org, without being obliged to provide
+       the source code for any proprietary components.  See the licensing section 
+       of http://www.FreeRTOS.org for full details of how and when the exception
+       can be applied.
+
+       ***************************************************************************
+       See http://www.FreeRTOS.org for documentation, latest information, license 
+       and contact details.  Please ensure to read the configuration and relevant 
+       port sections of the online documentation.
+
+       Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along
+       with commercial development and support options.
+       ***************************************************************************
+*/
+
+#ifndef PROJDEFS_H
+#define PROJDEFS_H
+
+/* Defines to prototype to which task functions must conform. */
+typedef void (*pdTASK_CODE)( void * );
+
+#define pdTRUE         ( 1 )
+#define pdFALSE                ( 0 )
+
+#define pdPASS                                                                 ( 1 )
+#define pdFAIL                                                                 ( 0 )
+#define errQUEUE_EMPTY                                                 ( 0 )
+#define errQUEUE_FULL                                                  ( 0 )
+
+/* Error definitions. */
+#define errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY  ( -1 )
+#define errNO_TASK_TO_RUN                                              ( -2 )
+#define errQUEUE_BLOCKED                                               ( -4 )
+#define errQUEUE_YIELD                                                 ( -5 )
+
+#endif /* PROJDEFS_H */
+
+
+
diff --git a/FreeRTOS/include/queue.h b/FreeRTOS/include/queue.h
new file mode 100644 (file)
index 0000000..4a6c9a6
--- /dev/null
@@ -0,0 +1,474 @@
+/*
+       FreeRTOS.org V4.4.0 - Copyright (C) 2003-2007 Richard Barry.
+
+       This file is part of the FreeRTOS.org distribution.
+
+       FreeRTOS.org 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 2 of the License, or
+       (at your option) any later version.
+
+       FreeRTOS.org 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 FreeRTOS.org; if not, write to the Free Software
+       Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+       A special exception to the GPL can be applied should you wish to distribute
+       a combined work that includes FreeRTOS.org, without being obliged to provide
+       the source code for any proprietary components.  See the licensing section 
+       of http://www.FreeRTOS.org for full details of how and when the exception
+       can be applied.
+
+       ***************************************************************************
+       See http://www.FreeRTOS.org for documentation, latest information, license 
+       and contact details.  Please ensure to read the configuration and relevant 
+       port sections of the online documentation.
+
+       Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along
+       with commercial development and support options.
+       ***************************************************************************
+*/
+
+#ifndef QUEUE_H
+#define QUEUE_H
+
+typedef void * xQueueHandle;
+
+/**
+ * queue. h
+ * <pre>
+ xQueueHandle xQueueCreate( 
+                              unsigned portBASE_TYPE uxQueueLength, 
+                              unsigned portBASE_TYPE uxItemSize 
+                          );
+ * </pre>
+ *
+ * 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:
+   <pre>
+ struct AMessage
+ {
+    portCHAR ucMessageID;
+    portCHAR ucData[ 20 ];
+ };
+
+ void vATask( void *pvParameters )
+ {
+ xQueueHandle xQueue1, xQueue2;
+
+    // Create a queue capable of containing 10 unsigned long values.
+    xQueue1 = xQueueCreate( 10, sizeof( unsigned portLONG ) );
+    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.
+ }
+ </pre>
+ * \defgroup xQueueCreate xQueueCreate
+ * \ingroup QueueManagement
+ */
+xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize );
+
+/**
+ * queue. h
+ * <pre>
+ portBASE_TYPE xQueueSend( 
+                             xQueueHandle xQueue, 
+                             const void * pvItemToQueue, 
+                             portTickType xTicksToWait 
+                         );
+ * </pre>
+ *
+ * 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.  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:
+   <pre>
+ struct AMessage
+ {
+    portCHAR ucMessageID;
+    portCHAR ucData[ 20 ];
+ } xMessage;
+
+ unsigned portLONG 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 portLONG ) );
+
+    // 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.
+ }
+ </pre>
+ * \defgroup xQueueSend xQueueSend
+ * \ingroup QueueManagement
+ */
+signed portBASE_TYPE xQueueSend( xQueueHandle xQueue, const void * pvItemToQueue, portTickType xTicksToWait );
+
+/**
+ * queue. h
+ * <pre>
+ portBASE_TYPE xQueueReceive( 
+                                xQueueHandle xQueue, 
+                                void *pvBuffer, 
+                                portTickType xTicksToWait 
+                            );</pre>
+ *
+ * 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.
+ *
+ * @return pdTRUE if an item was successfully received from the queue,
+ * otherwise pdFALSE.
+ *
+ * Example usage:
+   <pre>
+ struct AMessage
+ {
+    portCHAR ucMessageID;
+    portCHAR 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.
+ }
+ </pre>
+ * \defgroup xQueueReceive xQueueReceive
+ * \ingroup QueueManagement
+ */
+signed portBASE_TYPE xQueueReceive( xQueueHandle xQueue, void *pvBuffer, portTickType xTicksToWait );
+
+/**
+ * queue. h
+ * <pre>unsigned portBASE_TYPE uxQueueMessagesWaiting( xQueueHandle xQueue );</pre>
+ *
+ * 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( xQueueHandle xQueue );
+
+/**
+ * queue. h
+ * <pre>void vQueueDelete( xQueueHandle xQueue );</pre>
+ *
+ * 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 xQueue );
+
+/**
+ * queue. h
+ * <pre>
+ portBASE_TYPE xQueueSendFromISR( 
+                                    xQueueHandle pxQueue, 
+                                    const void *pvItemToQueue, 
+                                    portBASE_TYPE xTaskPreviouslyWoken 
+                                );
+ </pre>
+ *
+ * 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 cTaskPreviouslyWoken This is included so an ISR can post onto
+ * the same queue multiple times from a single interrupt.  The first call
+ * should always pass in pdFALSE.  Subsequent calls should pass in
+ * the value returned from the previous call.  See the file serial .c in the
+ * PC port for a good example of this mechanism.
+ *
+ * @return pdTRUE if a task was woken by posting onto the queue.  This is 
+ * used by the ISR to determine if a context switch may be required following
+ * the ISR.
+ *
+ * Example usage for buffered IO (where the ISR can obtain more than one value
+ * per call):
+   <pre>
+ void vBufferISR( void )
+ {
+ portCHAR cIn;
+ portBASE_TYPE xTaskWokenByPost;
+
+    // We have not woken a task at the start of the ISR.
+    cTaskWokenByPost = pdFALSE;
+
+    // Loop until the buffer is empty.
+    do
+    {
+        // Obtain a byte from the buffer.
+        cIn = portINPUT_BYTE( RX_REGISTER_ADDRESS );                                           
+
+        // Post the byte.  The first time round the loop cTaskWokenByPost
+        // will be pdFALSE.  If the queue send causes a task to wake we do
+        // not want the task to run until we have finished the ISR, so
+        // xQueueSendFromISR does not cause a context switch.  Also we 
+        // don't want subsequent posts to wake any other tasks, so we store
+        // the return value back into cTaskWokenByPost so xQueueSendFromISR
+        // knows not to wake any task the next iteration of the loop.
+        xTaskWokenByPost = xQueueSendFromISR( xRxQueue, &cIn, cTaskWokenByPost );
+
+    } while( portINPUT_BYTE( BUFFER_COUNT ) );
+
+    // Now the buffer is empty we can switch context if necessary.
+    if( cTaskWokenByPost )
+    {
+        taskYIELD ();
+    }
+ }
+ </pre>
+ *
+ * \defgroup xQueueSendFromISR xQueueSendFromISR
+ * \ingroup QueueManagement
+ */
+signed portBASE_TYPE xQueueSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xTaskPreviouslyWoken );
+
+/**
+ * queue. h
+ * <pre>
+ portBASE_TYPE xQueueReceiveFromISR( 
+                                       xQueueHandle pxQueue, 
+                                       void *pvBuffer, 
+                                       portBASE_TYPE *pxTaskWoken 
+                                   ); 
+ * </pre>
+ *
+ * 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:
+   <pre>
+ xQueueHandle xQueue;
+ // Function to create a queue and post some values.
+ void vAFunction( void *pvParameters )
+ {
+ portCHAR cValueToPost;
+ const portTickType xBlockTime = ( portTickType )0xff;
+
+    // Create a queue capable of containing 10 characters.
+    xQueue = xQueueCreate( 10, sizeof( portCHAR ) );
+    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;
+ portCHAR 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 != ( portCHAR ) pdFALSE;
+    {
+        taskYIELD ();
+    }
+ }
+ </pre>
+ * \defgroup xQueueReceiveFromISR xQueueReceiveFromISR
+ * \ingroup QueueManagement
+ */
+signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxTaskWoken );
+
+
+/* 
+ * 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-rtoutines.
+ *
+ * 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 );
+
+#endif
+
diff --git a/FreeRTOS/include/semphr.h b/FreeRTOS/include/semphr.h
new file mode 100644 (file)
index 0000000..bae09c7
--- /dev/null
@@ -0,0 +1,292 @@
+/*
+       FreeRTOS.org V4.4.0 - Copyright (C) 2003-2007 Richard Barry.
+
+       This file is part of the FreeRTOS.org distribution.
+
+       FreeRTOS.org 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 2 of the License, or
+       (at your option) any later version.
+
+       FreeRTOS.org 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 FreeRTOS.org; if not, write to the Free Software
+       Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+       A special exception to the GPL can be applied should you wish to distribute
+       a combined work that includes FreeRTOS.org, without being obliged to provide
+       the source code for any proprietary components.  See the licensing section 
+       of http://www.FreeRTOS.org for full details of how and when the exception
+       can be applied.
+
+       ***************************************************************************
+       See http://www.FreeRTOS.org for documentation, latest information, license 
+       and contact details.  Please ensure to read the configuration and relevant 
+       port sections of the online documentation.
+
+       Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along
+       with commercial development and support options.
+       ***************************************************************************
+*/
+
+#include "queue.h"
+
+#ifndef SEMAPHORE_H
+#define SEMAPHORE_H
+
+typedef xQueueHandle xSemaphoreHandle;
+
+#define semBINARY_SEMAPHORE_QUEUE_LENGTH       ( ( unsigned portCHAR ) 1 )
+#define semSEMAPHORE_QUEUE_ITEM_LENGTH         ( ( unsigned portCHAR ) 0 )
+#define semGIVE_BLOCK_TIME                                     ( ( portTickType ) 0 )
+
+
+/**
+ * semphr. h
+ * <pre>vSemaphoreCreateBinary( xSemaphoreHandle xSemaphore )</pre>
+ *
+ * <i>Macro</i> 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.
+ *
+ * @param xSemaphore Handle to the created semaphore.  Should be of type xSemaphoreHandle.
+ *
+ * Example usage:
+ <pre>
+ 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.  
+    }
+ }
+ </pre>
+ * \defgroup vSemaphoreCreateBinary vSemaphoreCreateBinary
+ * \ingroup Semaphores
+ */
+#define vSemaphoreCreateBinary( xSemaphore )           {                                                                                                                                                                                       \
+                                                                                                               xSemaphore = xQueueCreate( ( unsigned portCHAR ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH );   \
+                                                                                                               if( xSemaphore != NULL )                                                                                                                                \
+                                                                                                               {                                                                                                                                                                               \
+                                                                                                                       xSemaphoreGive( xSemaphore );                                                                                                           \
+                                                                                                               }                                                                                                                                                                               \
+                                                                                                       }
+
+/**
+ * semphr. h
+ * xSemaphoreTake( 
+ *                   xSemaphoreHandle xSemaphore, 
+ *                   portTickType xBlockTime 
+ *               )</pre>
+ *
+ * <i>Macro</i> to obtain a semaphore.  The semaphore must of been created using 
+ * vSemaphoreCreateBinary ().
+ *
+ * @param xSemaphore A handle to the semaphore being obtained.  This is the
+ * handle returned by vSemaphoreCreateBinary ();
+ *
+ * @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.
+ *
+ * @return pdTRUE if the semaphore was obtained.  pdFALSE if xBlockTime
+ * expired without the semaphore becoming available.
+ *
+ * Example usage:
+ <pre>
+ 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.
+        }
+    }
+ }
+ </pre>
+ * \defgroup xSemaphoreTake xSemaphoreTake
+ * \ingroup Semaphores
+ */
+#define xSemaphoreTake( xSemaphore, xBlockTime )       xQueueReceive( ( xQueueHandle ) xSemaphore, NULL, xBlockTime )
+
+/**
+ * semphr. h
+ * <pre>xSemaphoreGive( xSemaphoreHandle xSemaphore )</pre>
+ *
+ * <i>Macro</i> to release a semaphore.  The semaphore must of been created using 
+ * vSemaphoreCreateBinary (), and obtained using sSemaphoreTake ().
+ *
+ * This must not be used from an ISR.  See xSemaphoreGiveFromISR () for
+ * an alternative which can be used from an ISR.
+ *
+ * @param xSemaphore A handle to the semaphore being released.  This is the
+ * handle returned by vSemaphoreCreateBinary ();
+ *
+ * @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:
+ <pre>
+ 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.
+            }
+        }
+    }
+ }
+ </pre>
+ * \defgroup xSemaphoreGive xSemaphoreGive
+ * \ingroup Semaphores
+ */
+#define xSemaphoreGive( xSemaphore )                           xQueueSend( ( xQueueHandle ) xSemaphore, NULL, semGIVE_BLOCK_TIME )
+
+/**
+ * semphr. h
+ * <pre>
+ xSemaphoreGiveFromISR( 
+                          xSemaphoreHandle xSemaphore, 
+                          portSHORT sTaskPreviouslyWoken 
+                      )</pre>
+ *
+ * <i>Macro</i> to  release a semaphore.  The semaphore must of been created using 
+ * vSemaphoreCreateBinary (), and obtained using xSemaphoreTake ().
+ *
+ * This macro can be used from an ISR.
+ *
+ * @param xSemaphore A handle to the semaphore being released.  This is the
+ * handle returned by vSemaphoreCreateBinary ();
+ *
+ * @param sTaskPreviouslyWoken This is included so an ISR can make multiple calls
+ * to xSemaphoreGiveFromISR () from a single interrupt.  The first call
+ * should always pass in pdFALSE.  Subsequent calls should pass in
+ * the value returned from the previous call.  See the file serial .c in the
+ * PC port for a good example of using xSemaphoreGiveFromISR ().
+ *
+ * @return pdTRUE if a task was woken by releasing the semaphore.  This is 
+ * used by the ISR to determine if a context switch may be required following
+ * the ISR.
+ *
+ * Example usage:
+ <pre>
+ #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 or 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.
+        }
+    }
+ }
+
+ // Timer ISR
+ void vTimerISR( void * pvParameters )
+ {
+ static unsigned portCHAR ucLocalTickCount = 0;
+
+    // A timer tick has occurred.
+
+    // ... Do other time functions.
+
+    // Is it time for vATask () to run?
+    ucLocalTickCount++;
+    if( ucLocalTickCount >= TICKS_TO_WAIT )
+    {
+        // Unblock the task by releasing the semaphore.
+        xSemaphoreGive( xSemaphore );
+
+        // Reset the count so we release the semaphore again in 10 ticks time.
+        ucLocalTickCount = 0;
+    }
+ }
+ </pre>
+ * \defgroup xSemaphoreGiveFromISR xSemaphoreGiveFromISR
+ * \ingroup Semaphores
+ */
+#define xSemaphoreGiveFromISR( xSemaphore, xTaskPreviouslyWoken )                      xQueueSendFromISR( ( xQueueHandle ) xSemaphore, NULL, xTaskPreviouslyWoken )
+
+
+#endif
+
diff --git a/FreeRTOS/include/task.h b/FreeRTOS/include/task.h
new file mode 100644 (file)
index 0000000..5103f3c
--- /dev/null
@@ -0,0 +1,970 @@
+/*
+       FreeRTOS.org V4.4.0 - Copyright (C) 2003-2007 Richard Barry.
+
+       This file is part of the FreeRTOS.org distribution.
+
+       FreeRTOS.org 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 2 of the License, or
+       (at your option) any later version.
+
+       FreeRTOS.org 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 FreeRTOS.org; if not, write to the Free Software
+       Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+       A special exception to the GPL can be applied should you wish to distribute
+       a combined work that includes FreeRTOS.org, without being obliged to provide
+       the source code for any proprietary components.  See the licensing section
+       of http://www.FreeRTOS.org for full details of how and when the exception
+       can be applied.
+
+       ***************************************************************************
+       See http://www.FreeRTOS.org for documentation, latest information, license
+       and contact details.  Please ensure to read the configuration and relevant
+       port sections of the online documentation.
+
+       Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along
+       with commercial development and support options.
+       ***************************************************************************
+*/
+
+/*
+Changes since V4.3.1:
+
+       + Added xTaskGetSchedulerState() function.
+*/
+
+#ifndef TASK_H
+#define TASK_H
+
+#include "portable.h"
+#include "list.h"
+
+/*-----------------------------------------------------------
+ * MACROS AND DEFINITIONS
+ *----------------------------------------------------------*/
+
+#define tskKERNEL_VERSION_NUMBER "V4.4.0"
+
+/**
+ * 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 priority used by the idle task.  This must not be modified.
+ *
+ * \ingroup TaskUtils
+ */
+#define tskIDLE_PRIORITY                       ( ( unsigned portBASE_TYPE ) 0 )
+
+/**
+ * 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
+ *<pre>
+ portBASE_TYPE xTaskCreate(
+                              pdTASK_CODE pvTaskCode,
+                              const portCHAR * const pcName,
+                              unsigned portSHORT usStackDepth,
+                              void *pvParameters,
+                              unsigned portBASE_TYPE uxPriority,
+                              xTaskHandle *pvCreatedTask
+                          );</pre>
+ *
+ * Create a new task and add it to the list of tasks that are ready to run.
+ *
+ * @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.
+ *
+ * @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:
+   <pre>
+ // Task to be created.
+ void vTaskCode( void * pvParameters )
+ {
+     for( ;; )
+     {
+         // Task code goes here.
+     }
+ }
+
+ // Function that creates a task.
+ void vOtherFunction( void )
+ {
+ unsigned char ucParameterToPass;
+ xTaskHandle xHandle;
+               
+     // Create the task, storing the handle.
+     xTaskCreate( vTaskCode, "NAME", STACK_SIZE, &ucParameterToPass, tskIDLE_PRIORITY, &xHandle );
+               
+     // Use the handle to delete the task.
+     vTaskDelete( xHandle );
+ }
+   </pre>
+ * \defgroup xTaskCreate xTaskCreate
+ * \ingroup Tasks
+ */
+signed portBASE_TYPE xTaskCreate( pdTASK_CODE pvTaskCode, const signed portCHAR * const pcName, unsigned portSHORT usStackDepth, void *pvParameters, unsigned portBASE_TYPE uxPriority, xTaskHandle *pvCreatedTask );
+
+/**
+ * task. h
+ * <pre>void vTaskDelete( xTaskHandle pxTask );</pre>
+ *
+ * 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:
+   <pre>
+ 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 );
+ }
+   </pre>
+ * \defgroup vTaskDelete vTaskDelete
+ * \ingroup Tasks
+ */
+void vTaskDelete( xTaskHandle pxTask );
+
+
+/*-----------------------------------------------------------
+ * TASK CONTROL API
+ *----------------------------------------------------------*/
+
+/**
+ * task. h
+ * <pre>void vTaskDelay( portTickType xTicksToDelay );</pre>
+ *
+ * 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.
+ *
+ * @param xTicksToDelay The amount of time, in tick periods, that
+ * the calling task should block.
+ *
+ * Example usage:
+   <pre>
+ // Wait 10 ticks before performing an action.
+ // NOTE:
+ // This is for demonstration only and would be better achieved
+ // using vTaskDelayUntil ().
+ void vTaskFunction( void * pvParameters )
+ {
+ portTickType xDelay, xNextTime;
+
+     // Calc the time at which we want to perform the action
+     // next.
+     xNextTime = xTaskGetTickCount () + ( portTickType ) 10;
+
+     for( ;; )
+     {
+         xDelay = xNextTime - xTaskGetTickCount ();
+         xNextTime += ( portTickType ) 10;
+
+         // Guard against overflow
+         if( xDelay <= ( portTickType ) 10 )
+         {
+             vTaskDelay( xDelay );
+         }
+
+         // Perform action here.
+     }
+ }
+   </pre>
+ * \defgroup vTaskDelay vTaskDelay
+ * \ingroup TaskCtrl
+ */
+void vTaskDelay( portTickType xTicksToDelay );
+
+/**
+ * task. h
+ * <pre>void vTaskDelayUntil( portTickType *pxPreviousWakeTime, portTickType xTimeIncrement );</pre>
+ *
+ * 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:
+   <pre>
+ // 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.
+     }
+ }
+   </pre>
+ * \defgroup vTaskDelayUntil vTaskDelayUntil
+ * \ingroup TaskCtrl
+ */
+void vTaskDelayUntil( portTickType *pxPreviousWakeTime, portTickType xTimeIncrement );
+
+/**
+ * task. h
+ * <pre>unsigned portBASE_TYPE uxTaskPriorityGet( xTaskHandle pxTask );</pre>
+ *
+ * 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:
+   <pre>
+ 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.
+     }
+ }
+   </pre>
+ * \defgroup uxTaskPriorityGet uxTaskPriorityGet
+ * \ingroup TaskCtrl
+ */
+unsigned portBASE_TYPE uxTaskPriorityGet( xTaskHandle pxTask );
+
+/**
+ * task. h
+ * <pre>void vTaskPrioritySet( xTaskHandle pxTask, unsigned portBASE_TYPE uxNewPriority );</pre>
+ *
+ * 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:
+   <pre>
+ 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 );
+ }
+   </pre>
+ * \defgroup vTaskPrioritySet vTaskPrioritySet
+ * \ingroup TaskCtrl
+ */
+void vTaskPrioritySet( xTaskHandle pxTask, unsigned portBASE_TYPE uxNewPriority );
+
+/**
+ * task. h
+ * <pre>void vTaskSuspend( xTaskHandle pxTaskToSuspend );</pre>
+ *
+ * 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:
+   <pre>
+ 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.
+ }
+   </pre>
+ * \defgroup vTaskSuspend vTaskSuspend
+ * \ingroup TaskCtrl
+ */
+void vTaskSuspend( xTaskHandle pxTaskToSuspend );
+
+/**
+ * task. h
+ * <pre>void vTaskResume( xTaskHandle pxTaskToResume );</pre>
+ *
+ * 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:
+   <pre>
+ 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.
+ }
+   </pre>
+ * \defgroup vTaskResume vTaskResume
+ * \ingroup TaskCtrl
+ */
+void vTaskResume( xTaskHandle pxTaskToResume );
+
+/**
+ * task. h
+ * <pre>void xTaskResumeFromISR( xTaskHandle pxTaskToResume );</pre>
+ *
+ * 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 );
+
+/*-----------------------------------------------------------
+ * SCHEDULER CONTROL
+ *----------------------------------------------------------*/
+
+/**
+ * task. h
+ * <pre>void vTaskStartScheduler( void );</pre>
+ *
+ * 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:
+   <pre>
+ 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 ()
+ }
+   </pre>
+ *
+ * \defgroup vTaskStartScheduler vTaskStartScheduler
+ * \ingroup SchedulerControl
+ */
+void vTaskStartScheduler( void );
+
+/**
+ * task. h
+ * <pre>void vTaskEndScheduler( void );</pre>
+ *
+ * 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:
+   <pre>
+ 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.
+ }
+   </pre>
+ *
+ * \defgroup vTaskEndScheduler vTaskEndScheduler
+ * \ingroup SchedulerControl
+ */
+void vTaskEndScheduler( void );
+
+/**
+ * task. h
+ * <pre>void vTaskSuspendAll( void );</pre>
+ *
+ * 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.
+ *
+ * Example usage:
+   <pre>
+ 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 ();
+     }
+ }
+   </pre>
+ * \defgroup vTaskSuspendAll vTaskSuspendAll
+ * \ingroup SchedulerControl
+ */
+void vTaskSuspendAll( void );
+
+/**
+ * task. h
+ * <pre>portCHAR xTaskResumeAll( void );</pre>
+ *
+ * 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:
+   <pre>
+ 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 ();
+         }
+     }
+ }
+   </pre>
+ * \defgroup xTaskResumeAll xTaskResumeAll
+ * \ingroup SchedulerControl
+ */
+signed portBASE_TYPE xTaskResumeAll( void );
+
+
+/*-----------------------------------------------------------
+ * TASK UTILITIES
+ *----------------------------------------------------------*/
+
+/**
+ * task. h
+ * <PRE>volatile portTickType xTaskGetTickCount( void );</PRE>
+ *
+ * @return The count of ticks since vTaskStartScheduler was called.
+ *
+ * \page xTaskGetTickCount xTaskGetTickCount
+ * \ingroup TaskUtils
+ */
+portTickType xTaskGetTickCount( void );
+
+/**
+ * task. h
+ * <PRE>unsigned portSHORT uxTaskGetNumberOfTasks( void );</PRE>
+ *
+ * @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 );
+
+/**
+ * task. h
+ * <PRE>void vTaskList( portCHAR *pcWriteBuffer );</PRE>
+ *
+ * configUSE_TRACE_FACILITY, INCLUDE_vTaskDelete and INCLUDE_vTaskSuspend
+ * must all 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 portCHAR *pcWriteBuffer );
+
+/**
+ * task. h
+ * <PRE>void vTaskStartTrace( portCHAR * pcBuffer, unsigned portBASE_TYPE uxBufferSize );</PRE>
+ *
+ * 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 portCHAR * pcBuffer, unsigned portLONG ulBufferSize );
+
+/**
+ * task. h
+ * <PRE>unsigned portLONG ulTaskEndTrace( void );</PRE>
+ *
+ * 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 portLONG ulTaskEndTrace( void );
+
+
+/*-----------------------------------------------------------
+ * 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.
+ */
+inline void vTaskIncrementTick( void );
+
+/*
+ * 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( xList *pxEventList, portTickType xTicksToWait );
+
+/*
+ * 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 *pxEventList );
+
+/*
+ * 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 );
+
+/*
+ * 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.
+ */
+inline void vTaskSwitchContext( void );
+
+/*
+ * Return the handle of the calling task.
+ */
+xTaskHandle xTaskGetCurrentTaskHandle( void );
+
+/*
+ * Capture the current time status for future reference.
+ */
+void vTaskSetTimeOutState( xTimeOutType *pxTimeOut );
+
+/*
+ * Compare the time status now with that previously captured to see if the
+ * timeout has expired.
+ */
+portBASE_TYPE xTaskCheckForTimeOut( xTimeOutType *pxTimeOut, portTickType * const pxTicksToWait );
+
+/*
+ * Shortcut used by the queue implementation to prevent unnecessary call to
+ * taskYIELD();
+ */
+void vTaskMissedYield( void );
+
+/*
+ * Returns the scheduler state as taskSCHEDULER_RUNNING,
+ * taskSCHEDULER_NOT_STARTED or taskSCHEDULER_SUSPENDED.
+ */
+portBASE_TYPE xTaskGetSchedulerState( void );
+
+#endif /* TASK_H */
+
+
+
diff --git a/FreeRTOS/list.c b/FreeRTOS/list.c
new file mode 100644 (file)
index 0000000..3faa8b4
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+       FreeRTOS.org V4.4.0 - Copyright (C) 2003-2007 Richard Barry.
+
+       This file is part of the FreeRTOS.org distribution.
+
+       FreeRTOS.org 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 2 of the License, or
+       (at your option) any later version.
+
+       FreeRTOS.org 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 FreeRTOS.org; if not, write to the Free Software
+       Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+       A special exception to the GPL can be applied should you wish to distribute
+       a combined work that includes FreeRTOS.org, without being obliged to provide
+       the source code for any proprietary components.  See the licensing section
+       of http://www.FreeRTOS.org for full details of how and when the exception
+       can be applied.
+
+       ***************************************************************************
+       See http://www.FreeRTOS.org for documentation, latest information, license
+       and contact details.  Please ensure to read the configuration and relevant
+       port sections of the online documentation.
+
+       Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along
+       with commercial development and support options.
+       ***************************************************************************
+*/
+
+/*
+Changes from V1.2.0
+
+       + Removed the volatile modifier from the function parameters.  This was
+         only ever included to prevent compiler warnings.  Now warnings are
+         removed by casting parameters where the calls are made.
+
+       + prvListGetOwnerOfNextEntry() and prvListGetOwnerOfHeadEntry() have been
+         removed from the c file and added as macros to the h file.
+
+       + uxNumberOfItems has been added to the list structure.  This removes the
+         need for a pointer comparison when checking if a list is empty, and so
+         is slightly faster.
+
+       + Removed the NULL check in vListRemove().  This makes the call faster but
+         necessitates any application code utilising the list implementation to
+         ensure NULL pointers are not passed.
+
+Changes from V2.0.0
+
+       + Double linked the lists to allow faster removal item removal.
+
+Changes from V2.6.1
+
+       + Make use of the new portBASE_TYPE definition where ever appropriate.
+
+Changes from V3.0.0
+
+       + API changes as described on the FreeRTOS.org WEB site.
+
+Changes from V3.2.4
+
+       + Removed the pxHead member of the xList structure.  This always pointed
+         to the same place so has been removed to free a few bytes of RAM.
+
+       + Introduced the xMiniListItem structure that does not include the 
+         xListItem members that are not required by the xListEnd member of a list.
+         Again this was done to reduce RAM usage.
+
+       + Changed the volatile definitions of some structure members to clean up
+         the code where the list structures are used.
+
+Changes from V4.0.4
+
+       + Optimised vListInsert() in the case when the wake time is the maximum 
+         tick count value.
+*/
+
+#include <stdlib.h>
+#include "FreeRTOS.h"
+#include "list.h"
+
+/*-----------------------------------------------------------
+ * PUBLIC LIST API documented in list.h
+ *----------------------------------------------------------*/
+
+void vListInitialise( xList *pxList )
+{
+       /* The list structure contains a list item which is used to mark the
+       end of the list.  To initialise the list the list end is inserted
+       as the only list entry. */
+       pxList->pxIndex = ( xListItem * ) &( pxList->xListEnd );
+
+       /* The list end value is the highest possible value in the list to
+       ensure it remains at the end of the list. */
+       pxList->xListEnd.xItemValue = portMAX_DELAY;
+
+       /* The list end next and previous pointers point to itself so we know
+       when the list is empty. */
+       pxList->xListEnd.pxNext = ( xListItem * ) &( pxList->xListEnd );
+       pxList->xListEnd.pxPrevious = ( xListItem * ) &( pxList->xListEnd );
+
+       pxList->uxNumberOfItems = 0;
+}
+/*-----------------------------------------------------------*/
+
+void vListInitialiseItem( xListItem *pxItem )
+{
+       /* Make sure the list item is not recorded as being on a list. */
+       pxItem->pvContainer = NULL;
+}
+/*-----------------------------------------------------------*/
+
+void vListInsertEnd( xList *pxList, xListItem *pxNewListItem )
+{
+volatile xListItem * pxIndex;
+
+       /* Insert a new list item into pxList, but rather than sort the list,
+       makes the new list item the last item to be removed by a call to
+       pvListGetOwnerOfNextEntry.  This means it has to be the item pointed to by
+       the pxIndex member. */
+       pxIndex = pxList->pxIndex;
+
+       pxNewListItem->pxNext = pxIndex->pxNext;
+       pxNewListItem->pxPrevious = pxList->pxIndex;
+       pxIndex->pxNext->pxPrevious = ( volatile xListItem * ) pxNewListItem;
+       pxIndex->pxNext = ( volatile xListItem * ) pxNewListItem;
+       pxList->pxIndex = ( volatile xListItem * ) pxNewListItem;
+
+       /* Remember which list the item is in. */
+       pxNewListItem->pvContainer = ( void * ) pxList;
+
+       ( pxList->uxNumberOfItems )++;
+}
+/*-----------------------------------------------------------*/
+
+void vListInsert( xList *pxList, xListItem *pxNewListItem )
+{
+volatile xListItem *pxIterator;
+portTickType xValueOfInsertion;
+
+       /* Insert the new list item into the list, sorted in ulListItem order. */
+       xValueOfInsertion = pxNewListItem->xItemValue;
+
+       /* If the list already contains a list item with the same item value then
+       the new list item should be placed after it.  This ensures that TCB's which
+       are stored in ready lists (all of which have the same ulListItem value)
+       get an equal share of the CPU.  However, if the xItemValue is the same as 
+       the back marker the iteration loop below will not end.  This means we need
+       to guard against this by checking the value first and modifying the 
+       algorithm slightly if necessary. */
+       if( xValueOfInsertion == portMAX_DELAY )
+       {
+               pxIterator = pxList->xListEnd.pxPrevious;
+       }
+       else
+       {
+               for( pxIterator = ( xListItem * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext )
+               {
+                       /* There is nothing to do here, we are just iterating to the
+                       wanted insertion position. */
+               }
+       }
+
+       pxNewListItem->pxNext = pxIterator->pxNext;
+       pxNewListItem->pxNext->pxPrevious = ( volatile xListItem * ) pxNewListItem;
+       pxNewListItem->pxPrevious = pxIterator;
+       pxIterator->pxNext = ( volatile xListItem * ) pxNewListItem;
+
+       /* Remember which list the item is in.  This allows fast removal of the
+       item later. */
+       pxNewListItem->pvContainer = ( void * ) pxList;
+
+       ( pxList->uxNumberOfItems )++;
+}
+/*-----------------------------------------------------------*/
+
+void vListRemove( xListItem *pxItemToRemove )
+{
+xList * pxList;
+
+       pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;
+       pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;
+       
+       /* The list item knows which list it is in.  Obtain the list from the list
+       item. */
+       pxList = ( xList * ) pxItemToRemove->pvContainer;
+
+       /* Make sure the index is left pointing to a valid item. */
+       if( pxList->pxIndex == pxItemToRemove )
+       {
+               pxList->pxIndex = pxItemToRemove->pxPrevious;
+       }
+
+       pxItemToRemove->pvContainer = NULL;
+       ( pxList->uxNumberOfItems )--;
+}
+/*-----------------------------------------------------------*/
+
diff --git a/FreeRTOS/portable/GCC/ARM7_LPC2000/Makefile b/FreeRTOS/portable/GCC/ARM7_LPC2000/Makefile
new file mode 100644 (file)
index 0000000..c8d4a89
--- /dev/null
@@ -0,0 +1,25 @@
+SRC_FILES=port.c portISR.c
+
+#
+# Define all object files.
+#
+ARM_OBJ = $(SRC_FILES:.c=.o)
+
+.PHONY: all
+all: $(ARM_OBJ)
+
+$(ARM_OBJ) : %.o : %.c Makefile .depend
+       $(CC) -c $(CFLAGS) $< -o $@
+       $(AR) r $(COMMON)/common.a $@
+
+#
+#  The .depend files contains the list of header files that the
+#  various source files depend on.  By doing this, we'll only
+#  rebuild the .o's that are affected by header files changing.
+#
+.depend:
+                       $(CC) $(CFLAGS) -M $(SRC_FILES) > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff --git a/FreeRTOS/portable/GCC/ARM7_LPC2000/port.c b/FreeRTOS/portable/GCC/ARM7_LPC2000/port.c
new file mode 100644 (file)
index 0000000..ce74e71
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+       FreeRTOS.org V4.3.1 - Copyright (C) 2003-2007 Richard Barry.
+
+       This file is part of the FreeRTOS.org distribution.
+
+       FreeRTOS.org 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 2 of the License, or
+       (at your option) any later version.
+
+       FreeRTOS.org 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 FreeRTOS.org; if not, write to the Free Software
+       Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+       A special exception to the GPL can be applied should you wish to distribute
+       a combined work that includes FreeRTOS.org, without being obliged to provide
+       the source code for any proprietary components.  See the licensing section 
+       of http://www.FreeRTOS.org for full details of how and when the exception
+       can be applied.
+
+       ***************************************************************************
+       See http://www.FreeRTOS.org for documentation, latest information, license 
+       and contact details.  Please ensure to read the configuration and relevant 
+       port sections of the online documentation.
+
+       Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along
+       with commercial development and support options.
+       ***************************************************************************
+*/
+
+
+/*-----------------------------------------------------------
+ * Implementation of functions defined in portable.h for the ARM7 port.
+ *
+ * Components that can be compiled to either ARM or THUMB mode are
+ * contained in this file.  The ISR routines, which can only be compiled
+ * to ARM mode are contained in portISR.c.
+ *----------------------------------------------------------*/
+
+/*
+       Changes from V2.5.2
+               
+       + ulCriticalNesting is now saved as part of the task context, as is 
+         therefore added to the initial task stack during pxPortInitialiseStack.
+
+       Changes from V3.2.2
+
+       + Bug fix - The prescale value for the timer setup is now written to T0_PR 
+         instead of T0_PC.  This bug would have had no effect unless a prescale 
+         value was actually used.
+*/
+
+
+/* Standard includes. */
+#include <stdlib.h>
+
+/* Scheduler includes. */
+#include "FreeRTOS.h"
+#include "task.h"
+
+/* Constants required to setup the task context. */
+#define portINITIAL_SPSR                               ( ( portSTACK_TYPE ) 0x1f ) /* System mode, ARM mode, interrupts enabled. */
+#define portTHUMB_MODE_BIT                             ( ( portSTACK_TYPE ) 0x20 )
+#define portINSTRUCTION_SIZE                   ( ( portSTACK_TYPE ) 4 )
+#define portNO_CRITICAL_SECTION_NESTING        ( ( portSTACK_TYPE ) 0 )
+
+/* Constants required to setup the tick ISR. */
+#define portENABLE_TIMER                       ( ( unsigned portCHAR ) 0x01 )
+#define portPRESCALE_VALUE                     0x00
+#define portINTERRUPT_ON_MATCH         ( ( unsigned portLONG ) 0x01 )
+#define portRESET_COUNT_ON_MATCH       ( ( unsigned portLONG ) 0x02 )
+
+/*-----------------------------------------------------------*/
+
+/* Setup the timer to generate the tick interrupts. */
+static void prvSetupTimerInterrupt( void );
+
+/* 
+ * The scheduler can only be started from ARM mode, so 
+ * vPortISRStartFirstSTask() is defined in portISR.c. 
+ */
+extern void vPortISRStartFirstTask( void );
+
+/*-----------------------------------------------------------*/
+
+/* 
+ * Initialise the stack of a task to look exactly as if a call to 
+ * portSAVE_CONTEXT had been called.
+ *
+ * See header file for description. 
+ */
+portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters )
+{
+portSTACK_TYPE *pxOriginalTOS;
+
+       pxOriginalTOS = pxTopOfStack;
+
+       /* Setup the initial stack of the task.  The stack is set exactly as 
+       expected by the portRESTORE_CONTEXT() macro. */
+
+       /* First on the stack is the return address - which in this case is the
+       start of the task.  The offset is added to make the return address appear
+       as it would within an IRQ ISR. */
+       *pxTopOfStack = ( portSTACK_TYPE ) pxCode + portINSTRUCTION_SIZE;               
+       pxTopOfStack--;
+
+       *pxTopOfStack = ( portSTACK_TYPE ) 0xaaaaaaaa;  /* R14 */
+       pxTopOfStack--; 
+       *pxTopOfStack = ( portSTACK_TYPE ) pxOriginalTOS; /* Stack used when task starts goes in R13. */
+       pxTopOfStack--;
+       *pxTopOfStack = ( portSTACK_TYPE ) 0x12121212;  /* R12 */
+       pxTopOfStack--; 
+       *pxTopOfStack = ( portSTACK_TYPE ) 0x11111111;  /* R11 */
+       pxTopOfStack--; 
+       *pxTopOfStack = ( portSTACK_TYPE ) 0x10101010;  /* R10 */
+       pxTopOfStack--; 
+       *pxTopOfStack = ( portSTACK_TYPE ) 0x09090909;  /* R9 */
+       pxTopOfStack--; 
+       *pxTopOfStack = ( portSTACK_TYPE ) 0x08080808;  /* R8 */
+       pxTopOfStack--; 
+       *pxTopOfStack = ( portSTACK_TYPE ) 0x07070707;  /* R7 */
+       pxTopOfStack--; 
+       *pxTopOfStack = ( portSTACK_TYPE ) 0x06060606;  /* R6 */
+       pxTopOfStack--; 
+       *pxTopOfStack = ( portSTACK_TYPE ) 0x05050505;  /* R5 */
+       pxTopOfStack--; 
+       *pxTopOfStack = ( portSTACK_TYPE ) 0x04040404;  /* R4 */
+       pxTopOfStack--; 
+       *pxTopOfStack = ( portSTACK_TYPE ) 0x03030303;  /* R3 */
+       pxTopOfStack--; 
+       *pxTopOfStack = ( portSTACK_TYPE ) 0x02020202;  /* R2 */
+       pxTopOfStack--; 
+       *pxTopOfStack = ( portSTACK_TYPE ) 0x01010101;  /* R1 */
+       pxTopOfStack--; 
+
+       /* When the task starts is will expect to find the function parameter in
+       R0. */
+       *pxTopOfStack = ( portSTACK_TYPE ) pvParameters; /* R0 */
+       pxTopOfStack--;
+
+       /* The last thing onto the stack is the status register, which is set for
+       system mode, with interrupts enabled. */
+       *pxTopOfStack = ( portSTACK_TYPE ) portINITIAL_SPSR;
+
+       #ifdef THUMB_INTERWORK
+       {
+               /* We want the task to start in thumb mode. */
+               *pxTopOfStack |= portTHUMB_MODE_BIT;
+       }
+       #endif
+
+       pxTopOfStack--;
+
+       /* Some optimisation levels use the stack differently to others.  This 
+       means the interrupt flags cannot always be stored on the stack and will
+       instead be stored in a variable, which is then saved as part of the
+       tasks context. */
+       *pxTopOfStack = portNO_CRITICAL_SECTION_NESTING;
+
+       return pxTopOfStack;
+}
+/*-----------------------------------------------------------*/
+
+portBASE_TYPE xPortStartScheduler( void )
+{
+       /* Start the timer that generates the tick ISR.  Interrupts are disabled
+       here already. */
+       prvSetupTimerInterrupt();
+
+       /* Start the first task. */
+       vPortISRStartFirstTask();       
+
+       /* Should not get here! */
+       return 0;
+}
+/*-----------------------------------------------------------*/
+
+void vPortEndScheduler( void )
+{
+       /* It is unlikely that the ARM port will require this function as there
+       is nothing to return to.  */
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * Setup the timer 0 to generate the tick interrupts at the required frequency.
+ */
+static void prvSetupTimerInterrupt( void )
+{
+unsigned portLONG ulCompareMatch;
+
+  SCB_PCONP |= SCB_PCONP_PCTIM0;
+
+       /* A 1ms tick does not require the use of the timer prescale.  This is
+       defaulted to zero but can be used if necessary. */
+       T0_PR = portPRESCALE_VALUE;
+
+       /* Calculate the match value required for our wanted tick rate. */
+       ulCompareMatch = configCPU_CLOCK_HZ / configTICK_RATE_HZ;
+
+       /* Protect against divide by zero.  Using an if() statement still results
+       in a warning - hence the #if. */
+       #if portPRESCALE_VALUE != 0
+       {
+               ulCompareMatch /= ( portPRESCALE_VALUE + 1 );
+       }
+       #endif
+       T0_MR0 = ulCompareMatch;
+
+       /* Generate tick with timer 0 compare match. */
+       T0_MCR = portRESET_COUNT_ON_MATCH | portINTERRUPT_ON_MATCH;
+
+       /* Setup the VIC for the timer. */
+       VIC_IntSelect &= ~VIC_IntSelect_Timer0;
+       VIC_IntEnable = VIC_IntEnable_Timer0;
+       
+       /* The ISR installed depends on whether the preemptive or cooperative
+       scheduler is being used. */
+       #if configUSE_PREEMPTION == 1
+       {
+               extern void ( vPreemptiveTick )( void );
+               VIC_VectAddr0 = ( portLONG ) vPreemptiveTick;
+       }
+       #else
+       {
+               extern void ( vNonPreemptiveTick )( void );
+               VIC_VectAddr0 = ( portLONG ) vNonPreemptiveTick;
+       }
+       #endif
+
+       VIC_VectCntl0 = VIC_VectCntl_ENABLE | VIC_Channel_Timer0;
+
+       /* Start the timer - interrupts are disabled when this function is called
+       so it is okay to do this here. */
+       T0_TCR = portENABLE_TIMER;
+}
+/*-----------------------------------------------------------*/
+
+
+
diff --git a/FreeRTOS/portable/GCC/ARM7_LPC2000/portISR.c b/FreeRTOS/portable/GCC/ARM7_LPC2000/portISR.c
new file mode 100644 (file)
index 0000000..0eed7f4
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+       FreeRTOS.org V4.3.1 - Copyright (C) 2003-2007 Richard Barry.
+
+       This file is part of the FreeRTOS.org distribution.
+
+       FreeRTOS.org 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 2 of the License, or
+       (at your option) any later version.
+
+       FreeRTOS.org 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 FreeRTOS.org; if not, write to the Free Software
+       Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+       A special exception to the GPL can be applied should you wish to distribute
+       a combined work that includes FreeRTOS.org, without being obliged to provide
+       the source code for any proprietary components.  See the licensing section 
+       of http://www.FreeRTOS.org for full details of how and when the exception
+       can be applied.
+
+       ***************************************************************************
+       See http://www.FreeRTOS.org for documentation, latest information, license 
+       and contact details.  Please ensure to read the configuration and relevant 
+       port sections of the online documentation.
+
+       Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along
+       with commercial development and support options.
+       ***************************************************************************
+*/
+
+
+/*-----------------------------------------------------------
+ * Components that can be compiled to either ARM or THUMB mode are
+ * contained in port.c  The ISR routines, which can only be compiled
+ * to ARM mode, are contained in this file.
+ *----------------------------------------------------------*/
+
+/*
+       Changes from V2.5.2
+               
+       + The critical section management functions have been changed.  These no
+         longer modify the stack and are safe to use at all optimisation levels.
+         The functions are now also the same for both ARM and THUMB modes.
+
+       Changes from V2.6.0
+
+       + Removed the 'static' from the definition of vNonPreemptiveTick() to 
+         allow the demo to link when using the cooperative scheduler.
+
+       Changes from V3.2.4
+
+       + The assembler statements are now included in a single asm block rather
+         than each line having its own asm block.
+*/
+
+
+/* Scheduler includes. */
+#include "FreeRTOS.h"
+#include "task.h"
+
+/* Constants required to handle interrupts. */
+#define portTIMER_MATCH_ISR_BIT                ( ( unsigned portCHAR ) 0x01 )
+#define portCLEAR_VIC_INTERRUPT                ( ( unsigned portLONG ) 0 )
+
+/* Constants required to handle critical sections. */
+#define portNO_CRITICAL_NESTING                ( ( unsigned portLONG ) 0 )
+volatile unsigned portLONG ulCriticalNesting = 9999UL;
+
+/*-----------------------------------------------------------*/
+
+/* ISR to handle manual context switches (from a call to taskYIELD()). */
+void vPortYieldProcessor( void ) __attribute__((interrupt("SWI"), naked));
+
+/* 
+ * The scheduler can only be started from ARM mode, hence the inclusion of this
+ * function here.
+ */
+void vPortISRStartFirstTask( void );
+/*-----------------------------------------------------------*/
+
+void vPortISRStartFirstTask( void )
+{
+       /* Simply start the scheduler.  This is included here as it can only be
+       called from ARM mode. */
+       portRESTORE_CONTEXT();
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * Called by portYIELD() or taskYIELD() to manually force a context switch.
+ *
+ * When a context switch is performed from the task level the saved task 
+ * context is made to look as if it occurred from within the tick ISR.  This
+ * way the same restore context function can be used when restoring the context
+ * saved from the ISR or that saved from a call to vPortYieldProcessor.
+ */
+void vPortYieldProcessor( void )
+{
+       /* Within an IRQ ISR the link register has an offset from the true return 
+       address, but an SWI ISR does not.  Add the offset manually so the same 
+       ISR return code can be used in both cases. */
+       asm volatile ( "ADD             LR, LR, #4" );
+
+       /* Perform the context switch.  First save the context of the current task. */
+       portSAVE_CONTEXT();
+
+       /* Find the highest priority task that is ready to run. */
+       vTaskSwitchContext();
+
+       /* Restore the context of the new task. */
+       portRESTORE_CONTEXT();  
+}
+/*-----------------------------------------------------------*/
+
+/* 
+ * The ISR used for the scheduler tick depends on whether the cooperative or
+ * the preemptive scheduler is being used.
+ */
+
+#if configUSE_PREEMPTION == 0
+
+       /* The cooperative scheduler requires a normal IRQ service routine to 
+       simply increment the system tick. */
+       void vNonPreemptiveTick( void ) __attribute__ ((interrupt ("IRQ")));
+       void vNonPreemptiveTick( void )
+       {               
+               vTaskIncrementTick();
+               T0_IR = portTIMER_MATCH_ISR_BIT;
+               VICVectAddr = portCLEAR_VIC_INTERRUPT;
+       }
+
+#else
+
+       /* The preemptive scheduler is defined as "naked" as the full context is
+       saved on entry as part of the context switch. */
+       void vPreemptiveTick( void ) __attribute__((naked));
+       void vPreemptiveTick( void )
+       {
+               /* Save the context of the interrupted task. */
+               portSAVE_CONTEXT();     
+
+               /* Increment the RTOS tick count, then look for the highest priority 
+               task that is ready to run. */
+               vTaskIncrementTick();
+               vTaskSwitchContext();
+
+               /* Ready for the next interrupt. */
+               T0_IR = portTIMER_MATCH_ISR_BIT;
+               VIC_VectAddr = portCLEAR_VIC_INTERRUPT;
+               
+               /* Restore the context of the new task. */
+               portRESTORE_CONTEXT();
+       }
+
+#endif
+/*-----------------------------------------------------------*/
+
+/*
+ * The interrupt management utilities can only be called from ARM mode.  When
+ * THUMB_INTERWORK is defined the utilities are defined as functions here to
+ * ensure a switch to ARM mode.  When THUMB_INTERWORK is not defined then
+ * the utilities are defined as macros in portmacro.h - as per other ports.
+ */
+#ifdef THUMB_INTERWORK
+
+       void vPortDisableInterruptsFromThumb( void ) __attribute__ ((naked));
+       void vPortEnableInterruptsFromThumb( void ) __attribute__ ((naked));
+
+       void vPortDisableInterruptsFromThumb( void )
+       {
+               asm volatile ( 
+                       "STMDB  SP!, {R0}               \n\t"   /* Push R0.                                                                     */
+                       "MRS    R0, CPSR                \n\t"   /* Get CPSR.                                                            */
+                       "ORR    R0, R0, #0xC0   \n\t"   /* Disable IRQ, FIQ.                                            */
+                       "MSR    CPSR, R0                \n\t"   /* Write back modified value.                           */
+                       "LDMIA  SP!, {R0}               \n\t"   /* Pop R0.                                                                      */
+                       "BX             R14" );                                 /* Return back to thumb.                                        */
+       }
+                       
+       void vPortEnableInterruptsFromThumb( void )
+       {
+               asm volatile ( 
+                       "STMDB  SP!, {R0}               \n\t"   /* Push R0.                                                                     */      
+                       "MRS    R0, CPSR                \n\t"   /* Get CPSR.                                                            */      
+                       "BIC    R0, R0, #0xC0   \n\t"   /* Enable IRQ, FIQ.                                                     */      
+                       "MSR    CPSR, R0                \n\t"   /* Write back modified value.                           */      
+                       "LDMIA  SP!, {R0}               \n\t"   /* Pop R0.                                                                      */
+                       "BX             R14" );                                 /* Return back to thumb.                                        */
+       }
+
+#endif /* THUMB_INTERWORK */
+
+/* The code generated by the GCC compiler uses the stack in different ways at
+different optimisation levels.  The interrupt flags can therefore not always
+be saved to the stack.  Instead the critical section nesting level is stored
+in a variable, which is then saved as part of the stack context. */
+void vPortEnterCritical( void )
+{
+       /* Disable interrupts as per portDISABLE_INTERRUPTS();                                                  */
+       asm volatile ( 
+               "STMDB  SP!, {R0}                       \n\t"   /* Push R0.                                                             */
+               "MRS    R0, CPSR                        \n\t"   /* Get CPSR.                                                    */
+               "ORR    R0, R0, #0xC0           \n\t"   /* Disable IRQ, FIQ.                                    */
+               "MSR    CPSR, R0                        \n\t"   /* Write back modified value.                   */
+               "LDMIA  SP!, {R0}" );                           /* Pop R0.                                                              */
+
+       /* Now interrupts are disabled ulCriticalNesting can be accessed 
+       directly.  Increment ulCriticalNesting to keep a count of how many times
+       portENTER_CRITICAL() has been called. */
+       ulCriticalNesting++;
+}
+
+void vPortExitCritical( void )
+{
+       if( ulCriticalNesting > portNO_CRITICAL_NESTING )
+       {
+               /* Decrement the nesting count as we are leaving a critical section. */
+               ulCriticalNesting--;
+
+               /* If the nesting level has reached zero then interrupts should be
+               re-enabled. */
+               if( ulCriticalNesting == portNO_CRITICAL_NESTING )
+               {
+                       /* Enable interrupts as per portEXIT_CRITICAL().                                        */
+                       asm volatile ( 
+                               "STMDB  SP!, {R0}               \n\t"   /* Push R0.                                             */      
+                               "MRS    R0, CPSR                \n\t"   /* Get CPSR.                                    */      
+                               "BIC    R0, R0, #0xC0   \n\t"   /* Enable IRQ, FIQ.                             */      
+                               "MSR    CPSR, R0                \n\t"   /* Write back modified value.   */      
+                               "LDMIA  SP!, {R0}" );                   /* Pop R0.                                              */
+               }
+       }
+}
diff --git a/FreeRTOS/portable/GCC/ARM7_LPC2000/portmacro.h b/FreeRTOS/portable/GCC/ARM7_LPC2000/portmacro.h
new file mode 100644 (file)
index 0000000..3051577
--- /dev/null
@@ -0,0 +1,267 @@
+/*
+       FreeRTOS.org V4.3.1 - Copyright (C) 2003-2007 Richard Barry.
+
+       This file is part of the FreeRTOS.org distribution.
+
+       FreeRTOS.org 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 2 of the License, or
+       (at your option) any later version.
+
+       FreeRTOS.org 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 FreeRTOS.org; if not, write to the Free Software
+       Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+       A special exception to the GPL can be applied should you wish to distribute
+       a combined work that includes FreeRTOS.org, without being obliged to provide
+       the source code for any proprietary components.  See the licensing section 
+       of http://www.FreeRTOS.org for full details of how and when the exception
+       can be applied.
+
+       ***************************************************************************
+       See http://www.FreeRTOS.org for documentation, latest information, license 
+       and contact details.  Please ensure to read the configuration and relevant 
+       port sections of the online documentation.
+
+       Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along
+       with commercial development and support options.
+       ***************************************************************************
+*/
+
+/*
+       Changes from V3.2.3
+       
+       + Modified portENTER_SWITCHING_ISR() to allow use with GCC V4.0.1.
+
+       Changes from V3.2.4
+
+       + Removed the use of the %0 parameter within the assembler macros and 
+         replaced them with hard coded registers.  This will ensure the
+         assembler does not select the link register as the temp register as
+         was occasionally happening previously.
+
+       + The assembler statements are now included in a single asm block rather
+         than each line having its own asm block.
+*/
+
+#ifndef PORTMACRO_H
+#define PORTMACRO_H
+
+/*-----------------------------------------------------------
+ * Port specific definitions.  
+ *
+ * The settings in this file configure FreeRTOS correctly for the
+ * given hardware and compiler.
+ *
+ * These settings should not be altered.
+ *-----------------------------------------------------------
+ */
+
+/* Type definitions. */
+#define portCHAR               char
+#define portFLOAT              float
+#define portDOUBLE     double
+#define portLONG               long
+#define portSHORT              short
+#define portSTACK_TYPE unsigned portLONG
+#define portBASE_TYPE  portLONG
+
+#if( configUSE_16_BIT_TICKS == 1 )
+       typedef unsigned portSHORT portTickType;
+       #define portMAX_DELAY ( portTickType ) 0xffff
+#else
+       typedef unsigned portLONG portTickType;
+       #define portMAX_DELAY ( portTickType ) 0xffffffff
+#endif
+/*-----------------------------------------------------------*/        
+
+/* Architecture specifics. */
+#define portSTACK_GROWTH                       ( -1 )
+#define portTICK_RATE_MS                       ( ( portTickType ) 1000 / configTICK_RATE_HZ )          
+#define portBYTE_ALIGNMENT                     4
+#define portNOP()                                      asm volatile ( "NOP" );
+/*-----------------------------------------------------------*/        
+
+
+/* Scheduler utilities. */
+
+/*
+ * portRESTORE_CONTEXT, portRESTORE_CONTEXT, portENTER_SWITCHING_ISR
+ * and portEXIT_SWITCHING_ISR can only be called from ARM mode, but
+ * are included here for efficiency.  An attempt to call one from
+ * THUMB mode code will result in a compile time error.
+ */
+
+#define portRESTORE_CONTEXT()                                                                                  \
+{                                                                                                                                              \
+extern volatile void * volatile pxCurrentTCB;                                                  \
+extern volatile unsigned portLONG ulCriticalNesting;                                   \
+                                                                                                                                               \
+       /* Set the LR to the task stack. */                                                                     \
+       asm volatile (                                                                                                          \
+       "LDR            R0, =pxCurrentTCB                                                               \n\t"   \
+       "LDR            R0, [R0]                                                                                \n\t"   \
+       "LDR            LR, [R0]                                                                                \n\t"   \
+                                                                                                                                               \
+       /* The critical nesting depth is the first item on the stack. */        \
+       /* Load it into the ulCriticalNesting variable. */                                      \
+       "LDR            R0, =ulCriticalNesting                                                  \n\t"   \
+       "LDMFD  LR!, {R1}                                                                                       \n\t"   \
+       "STR            R1, [R0]                                                                                \n\t"   \
+                                                                                                                                               \
+       /* Get the SPSR from the stack. */                                                                      \
+       "LDMFD  LR!, {R0}                                                                                       \n\t"   \
+       "MSR            SPSR, R0                                                                                \n\t"   \
+                                                                                                                                               \
+       /* Restore all system mode registers for the task. */                           \
+       "LDMFD  LR, {R0-R14}^                                                                           \n\t"   \
+       "NOP                                                                                                            \n\t"   \
+                                                                                                                                               \
+       /* Restore the return address. */                                                                       \
+       "LDR            LR, [LR, #+60]                                                                  \n\t"   \
+                                                                                                                                               \
+       /* And return - correcting the offset in the LR to obtain the */        \
+       /* correct address. */                                                                                          \
+       "SUBS   PC, LR, #4                                                                                      \n\t"   \
+       );                                                                                                                                      \
+       ( void ) ulCriticalNesting;                                                                                     \
+       ( void ) pxCurrentTCB;                                                                                          \
+}
+/*-----------------------------------------------------------*/
+
+#define portSAVE_CONTEXT()                                                                                             \
+{                                                                                                                                              \
+extern volatile void * volatile pxCurrentTCB;                                                  \
+extern volatile unsigned portLONG ulCriticalNesting;                                   \
+                                                                                                                                               \
+       /* Push R0 as we are going to use the register. */                                      \
+       asm volatile (                                                                                                          \
+       "STMDB  SP!, {R0}                                                                                       \n\t"   \
+                                                                                                                                               \
+       /* Set R0 to point to the task stack pointer. */                                        \
+       "STMDB  SP,{SP}^                                                                                        \n\t"   \
+       "NOP                                                                                                            \n\t"   \
+       "SUB    SP, SP, #4                                                                                      \n\t"   \
+       "LDMIA  SP!,{R0}                                                                                        \n\t"   \
+                                                                                                                                               \
+       /* Push the return address onto the stack. */                                           \
+       "STMDB  R0!, {LR}                                                                                       \n\t"   \
+                                                                                                                                               \
+       /* Now we have saved LR we can use it instead of R0. */                         \
+       "MOV    LR, R0                                                                                          \n\t"   \
+                                                                                                                                               \
+       /* Pop R0 so we can save it onto the system mode stack. */                      \
+       "LDMIA  SP!, {R0}                                                                                       \n\t"   \
+                                                                                                                                               \
+       /* Push all the system mode registers onto the task stack. */           \
+       "STMDB  LR,{R0-LR}^                                                                                     \n\t"   \
+       "NOP                                                                                                            \n\t"   \
+       "SUB    LR, LR, #60                                                                                     \n\t"   \
+                                                                                                                                               \
+       /* Push the SPSR onto the task stack. */                                                        \
+       "MRS    R0, SPSR                                                                                        \n\t"   \
+       "STMDB  LR!, {R0}                                                                                       \n\t"   \
+                                                                                                                                               \
+       "LDR    R0, =ulCriticalNesting                                                          \n\t"   \
+       "LDR    R0, [R0]                                                                                        \n\t"   \
+       "STMDB  LR!, {R0}                                                                                       \n\t"   \
+                                                                                                                                               \
+       /* Store the new top of stack for the task. */                                          \
+       "LDR    R0, =pxCurrentTCB                                                                       \n\t"   \
+       "LDR    R0, [R0]                                                                                        \n\t"   \
+       "STR    LR, [R0]                                                                                        \n\t"   \
+       );                                                                                                                                      \
+       ( void ) ulCriticalNesting;                                                                                     \
+       ( void ) pxCurrentTCB;                                                                                          \
+}
+
+
+/*-----------------------------------------------------------
+ * ISR entry and exit macros.  These are only required if a task switch
+ * is required from the ISR.
+ *----------------------------------------------------------*/
+
+
+#define portENTER_SWITCHING_ISR()                                                                              \
+       /* Save the context of the interrupted task. */                                         \
+       portSAVE_CONTEXT();                                                                                                     \
+                                                                                                                                               \
+       /* We don't know the stack requirements for the ISR, so the frame */\
+       /* pointer will be set to the top of the task stack, and the stack*/\
+       /* pointer left where it is.  The IRQ stack will get used for any */\
+       /* functions calls made by this ISR. */                                                         \
+       asm volatile ( "SUB             R11, LR, #4" );                                                 \
+       {
+
+#define portEXIT_SWITCHING_ISR( SwitchRequired )                                               \
+               /* If a switch is required then we just need to call */                 \
+               /* vTaskSwitchContext() as the context has already been */              \
+               /* saved. */                                                                                                    \
+               if( SwitchRequired )                                                                                    \
+               {                                                                                                                               \
+                       vTaskSwitchContext();                                                                           \
+               }                                                                                                                               \
+       }                                                                                                                                       \
+       /* Restore the context of which ever task is now the highest */         \
+       /* priority that is ready to run. */                                                            \
+       portRESTORE_CONTEXT();
+
+#define portYIELD()                                    asm volatile ( "SWI" ); 
+/*-----------------------------------------------------------*/
+
+
+/* Critical section management. */
+
+/*
+ * The interrupt management utilities can only be called from ARM mode.  When
+ * THUMB_INTERWORK is defined the utilities are defined as functions in 
+ * portISR.c to ensure a switch to ARM mode.  When THUMB_INTERWORK is not 
+ * defined then the utilities are defined as macros here - as per other ports.
+ */
+
+#ifdef THUMB_INTERWORK
+
+       extern void vPortDisableInterruptsFromThumb( void ) __attribute__ ((naked));
+       extern void vPortEnableInterruptsFromThumb( void ) __attribute__ ((naked));
+
+       #define portDISABLE_INTERRUPTS()        vPortDisableInterruptsFromThumb()
+       #define portENABLE_INTERRUPTS()         vPortEnableInterruptsFromThumb()
+       
+#else
+
+       #define portDISABLE_INTERRUPTS()                                                                                        \
+               asm volatile (                                                                                                                  \
+                       "STMDB  SP!, {R0}               \n\t"   /* Push R0.                                             */      \
+                       "MRS    R0, CPSR                \n\t"   /* Get CPSR.                                    */      \
+                       "ORR    R0, R0, #0xC0   \n\t"   /* Disable IRQ, FIQ.                    */      \
+                       "MSR    CPSR, R0                \n\t"   /* Write back modified value.   */      \
+                       "LDMIA  SP!, {R0}                       " )     /* Pop R0.                                              */
+                       
+       #define portENABLE_INTERRUPTS()                                                                                         \
+               asm volatile (                                                                                                                  \
+                       "STMDB  SP!, {R0}               \n\t"   /* Push R0.                                             */      \
+                       "MRS    R0, CPSR                \n\t"   /* Get CPSR.                                    */      \
+                       "BIC    R0, R0, #0xC0   \n\t"   /* Enable IRQ, FIQ.                             */      \
+                       "MSR    CPSR, R0                \n\t"   /* Write back modified value.   */      \
+                       "LDMIA  SP!, {R0}                       " )     /* Pop R0.                                              */
+
+#endif /* THUMB_INTERWORK */
+
+extern void vPortEnterCritical( void );
+extern void vPortExitCritical( void );
+
+#define portENTER_CRITICAL()           vPortEnterCritical();
+#define portEXIT_CRITICAL()                    vPortExitCritical();
+/*-----------------------------------------------------------*/
+
+/* Task function macros as described on the FreeRTOS.org WEB site. */
+#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters ) __attribute__ ((naked))
+#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )
+
+#endif /* PORTMACRO_H */
+
diff --git a/FreeRTOS/portable/GCC/Makefile b/FreeRTOS/portable/GCC/Makefile
new file mode 100644 (file)
index 0000000..0c85d6f
--- /dev/null
@@ -0,0 +1,9 @@
+#
+# Define all object files.
+#
+SUBDIRS=ARM7_LPC2000
+
+.PHONY: all
+all:
+       @for i in $(SUBDIRS); do \
+       (cd $$i; $(MAKE) $(MFLAGS) $(MYMAKEFLAGS) all); done
diff --git a/FreeRTOS/portable/Makefile b/FreeRTOS/portable/Makefile
new file mode 100644 (file)
index 0000000..b7f40b0
--- /dev/null
@@ -0,0 +1,9 @@
+#
+# Define all object files.
+#
+SUBDIRS=GCC MemMang
+
+.PHONY: all
+all:
+       @for i in $(SUBDIRS); do \
+       (cd $$i; $(MAKE) $(MFLAGS) $(MYMAKEFLAGS) all); done
diff --git a/FreeRTOS/portable/MemMang/Makefile b/FreeRTOS/portable/MemMang/Makefile
new file mode 100644 (file)
index 0000000..d77059a
--- /dev/null
@@ -0,0 +1,25 @@
+SRC_FILES=heap_2.c
+
+#
+# Define all object files.
+#
+ARM_OBJ = $(SRC_FILES:.c=.o)
+
+.PHONY: all
+all: $(ARM_OBJ)
+
+$(ARM_OBJ) : %.o : %.c Makefile .depend
+       $(CC) -c $(CFLAGS) $< -o $@
+       $(AR) r $(COMMON)/common.a $@
+
+#
+#  The .depend files contains the list of header files that the
+#  various source files depend on.  By doing this, we'll only
+#  rebuild the .o's that are affected by header files changing.
+#
+.depend:
+                       $(CC) $(CFLAGS) -M $(SRC_FILES) > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff --git a/FreeRTOS/portable/MemMang/heap_1.c b/FreeRTOS/portable/MemMang/heap_1.c
new file mode 100644 (file)
index 0000000..e65eeaa
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+       FreeRTOS.org V4.3.1 - Copyright (C) 2003-2007 Richard Barry.
+
+       This file is part of the FreeRTOS.org distribution.
+
+       FreeRTOS.org 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 2 of the License, or
+       (at your option) any later version.
+
+       FreeRTOS.org 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 FreeRTOS.org; if not, write to the Free Software
+       Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+       A special exception to the GPL can be applied should you wish to distribute
+       a combined work that includes FreeRTOS.org, without being obliged to provide
+       the source code for any proprietary components.  See the licensing section 
+       of http://www.FreeRTOS.org for full details of how and when the exception
+       can be applied.
+
+       ***************************************************************************
+       See http://www.FreeRTOS.org for documentation, latest information, license 
+       and contact details.  Please ensure to read the configuration and relevant 
+       port sections of the online documentation.
+
+       Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along
+       with commercial development and support options.
+       ***************************************************************************
+*/
+
+/* 
+
+Changes between V2.5.1 and V2.5.1
+
+       + The memory pool has been defined within a struct to ensure correct memory
+         alignment on 32bit systems.
+
+Changes between V2.6.1 and V3.0.0
+
+       + An overflow check has been added to ensure the next free byte variable 
+         does not wrap around.
+*/
+
+
+/*
+ * The simplest possible implementation of pvPortMalloc().  Note that this
+ * implementation does NOT allow allocated memory to be freed again.
+ *
+ * See heap_2.c and heap_3.c for alternative implementations, and the memory
+ * management pages of http://www.FreeRTOS.org for more information.
+ */
+#include <stdlib.h>
+#include "FreeRTOS.h"
+#include "task.h"
+
+/* Setup the correct byte alignment mask for the defined byte alignment. */
+
+#if portBYTE_ALIGNMENT == 8
+       #define heapBYTE_ALIGNMENT_MASK ( ( size_t ) 0x0007 )
+#endif
+
+#if portBYTE_ALIGNMENT == 4
+       #define heapBYTE_ALIGNMENT_MASK ( ( size_t ) 0x0003 )
+#endif
+
+#if portBYTE_ALIGNMENT == 2
+       #define heapBYTE_ALIGNMENT_MASK ( ( size_t ) 0x0001 )
+#endif
+
+#if portBYTE_ALIGNMENT == 1 
+       #define heapBYTE_ALIGNMENT_MASK ( ( size_t ) 0x0000 )
+#endif
+
+#ifndef heapBYTE_ALIGNMENT_MASK
+       #error "Invalid portBYTE_ALIGNMENT definition"
+#endif
+
+/* Allocate the memory for the heap.  The struct is used to force byte
+alignment without using any non-portable code. */
+static struct xRTOS_HEAP
+{
+       unsigned portLONG ulDummy;
+       unsigned portCHAR ucHeap[ configTOTAL_HEAP_SIZE ];
+} xHeap;
+
+static size_t xNextFreeByte = ( size_t ) 0;
+/*-----------------------------------------------------------*/
+
+void *pvPortMalloc( size_t xWantedSize )
+{
+void *pvReturn = NULL; 
+
+       /* Ensure that blocks are always aligned to the required number of bytes. */
+       #if portBYTE_ALIGNMENT != 1
+               if( xWantedSize & heapBYTE_ALIGNMENT_MASK )
+               {
+                       /* Byte alignment required. */
+                       xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & heapBYTE_ALIGNMENT_MASK ) );
+               }
+       #endif
+
+       vTaskSuspendAll();
+       {
+               /* Check there is enough room left for the allocation. */
+               if( ( ( xNextFreeByte + xWantedSize ) < configTOTAL_HEAP_SIZE ) &&
+                       ( ( xNextFreeByte + xWantedSize ) > xNextFreeByte )     )/* Check for overflow. */
+               {
+                       /* Return the next free byte then increment the index past this
+                       block. */
+                       pvReturn = &( xHeap.ucHeap[ xNextFreeByte ] );
+                       xNextFreeByte += xWantedSize;                   
+               }       
+       }
+       xTaskResumeAll();
+
+       return pvReturn;
+}
+/*-----------------------------------------------------------*/
+
+void vPortFree( void *pv )
+{
+       /* Memory cannot be freed using this scheme.  See heap_2.c and heap_3.c 
+       for alternative implementations, and the memory management pages of 
+       http://www.FreeRTOS.org for more information. */
+       ( void ) pv;
+}
+/*-----------------------------------------------------------*/
+
+void vPortInitialiseBlocks( void )
+{
+       /* Only required when static memory is not cleared. */
+       xNextFreeByte = ( size_t ) 0;
+}
+
+
diff --git a/FreeRTOS/portable/MemMang/heap_2.c b/FreeRTOS/portable/MemMang/heap_2.c
new file mode 100644 (file)
index 0000000..3d51a7c
--- /dev/null
@@ -0,0 +1,271 @@
+/*
+       FreeRTOS.org V4.3.1 - Copyright (C) 2003-2007 Richard Barry.
+
+       This file is part of the FreeRTOS.org distribution.
+
+       FreeRTOS.org 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 2 of the License, or
+       (at your option) any later version.
+
+       FreeRTOS.org 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 FreeRTOS.org; if not, write to the Free Software
+       Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+       A special exception to the GPL can be applied should you wish to distribute
+       a combined work that includes FreeRTOS.org, without being obliged to provide
+       the source code for any proprietary components.  See the licensing section
+       of http://www.FreeRTOS.org for full details of how and when the exception
+       can be applied.
+
+       ***************************************************************************
+       See http://www.FreeRTOS.org for documentation, latest information, license
+       and contact details.  Please ensure to read the configuration and relevant
+       port sections of the online documentation.
+
+       Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along
+       with commercial development and support options.
+       ***************************************************************************
+*/
+
+/*
+ * A sample implementation of pvPortMalloc() and vPortFree() that permits
+ * allocated blocks to be freed, but does not combine adjacent free blocks
+ * into a single larger block.
+ *
+ * See heap_1.c and heap_3.c for alternative implementations, and the memory
+ * management pages of http://www.FreeRTOS.org for more information.
+ */
+#include <stdlib.h>
+
+#include "FreeRTOS.h"
+#include "task.h"
+
+/* Setup the correct byte alignment mask for the defined byte alignment. */
+
+#if portBYTE_ALIGNMENT == 8
+       #define heapBYTE_ALIGNMENT_MASK ( ( size_t ) 0x0007 )
+#endif
+
+#if portBYTE_ALIGNMENT == 4
+       #define heapBYTE_ALIGNMENT_MASK ( ( size_t ) 0x0003 )
+#endif
+
+#if portBYTE_ALIGNMENT == 2
+       #define heapBYTE_ALIGNMENT_MASK ( ( size_t ) 0x0001 )
+#endif
+
+#if portBYTE_ALIGNMENT == 1
+       #define heapBYTE_ALIGNMENT_MASK ( ( size_t ) 0x0000 )
+#endif
+
+#ifndef heapBYTE_ALIGNMENT_MASK
+       #error "Invalid portBYTE_ALIGNMENT definition"
+#endif
+
+/* Allocate the memory for the heap.  The struct is used to force byte
+alignment without using any non-portable code. */
+static struct xRTOS_HEAP
+{
+       unsigned portLONG ulDummy;
+       unsigned portCHAR ucHeap[ configTOTAL_HEAP_SIZE ];
+} xHeap;
+
+/* Define the linked list structure.  This is used to link free blocks in order
+of their size. */
+typedef struct A_BLOCK_LINK
+{
+       struct A_BLOCK_LINK *pxNextFreeBlock;   /*<< The next free block in the list. */
+       size_t xBlockSize;                                              /*<< The size of the free block. */
+} xBlockLink;
+
+
+static const unsigned portSHORT  heapSTRUCT_SIZE       = ( sizeof( xBlockLink ) + ( sizeof( xBlockLink ) % portBYTE_ALIGNMENT ) );
+#define heapMINIMUM_BLOCK_SIZE ( ( size_t ) ( heapSTRUCT_SIZE * 2 ) )
+
+/* Create a couple of list links to mark the start and end of the list. */
+static xBlockLink xStart, xEnd;
+
+/* STATIC FUNCTIONS ARE DEFINED AS MACROS TO MINIMIZE THE FUNCTION CALL DEPTH. */
+
+/*
+ * Insert a block into the list of free blocks - which is ordered by size of
+ * the block.  Small blocks at the start of the list and large blocks at the end
+ * of the list.
+ */
+#define prvInsertBlockIntoFreeList( pxBlockToInsert )                                                          \
+{                                                                                                                                                                      \
+xBlockLink *pxIterator;                                                                                                                                \
+size_t xBlockSize;                                                                                                                                     \
+                                                                                                                                                                       \
+       xBlockSize = pxBlockToInsert->xBlockSize;                                                                               \
+                                                                                                                                                                       \
+       /* Iterate through the list until a block is found that has a larger size */    \
+       /* than the block we are inserting. */                                                                                  \
+       for( pxIterator = &xStart; pxIterator->pxNextFreeBlock->xBlockSize < xBlockSize; pxIterator = pxIterator->pxNextFreeBlock )     \
+       {                                                                                                                                                               \
+               /* There is nothing to do here - just iterate to the correct position. */       \
+       }                                                                                                                                                               \
+                                                                                                                                                                       \
+       /* Update the list to include the block being inserted in the correct */                \
+       /* position. */                                                                                                                                 \
+       pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock;                                 \
+       pxIterator->pxNextFreeBlock = pxBlockToInsert;                                                                  \
+}
+/*-----------------------------------------------------------*/
+
+#define prvHeapInit()                                                                                                                          \
+{                                                                                                                                                                      \
+xBlockLink *pxFirstFreeBlock;                                                                                                          \
+                                                                                                                                                                       \
+       /* xStart is used to hold a pointer to the first item in the list of free */    \
+       /* blocks.  The void cast is used to prevent compiler warnings. */                              \
+       xStart.pxNextFreeBlock = ( void * ) xHeap.ucHeap;                                                               \
+       xStart.xBlockSize = ( size_t ) 0;                                                                                               \
+                                                                                                                                                                       \
+       /* xEnd is used to mark the end of the list of free blocks. */                                  \
+       xEnd.xBlockSize = configTOTAL_HEAP_SIZE;                                                                                \
+       xEnd.pxNextFreeBlock = NULL;                                                                                                    \
+                                                                                                                                                                       \
+       /* To start with there is a single free block that is sized to take up the              \
+       entire heap space. */                                                                                                                   \
+       pxFirstFreeBlock = ( void * ) xHeap.ucHeap;                                                                             \
+       pxFirstFreeBlock->xBlockSize = configTOTAL_HEAP_SIZE;                                                   \
+       pxFirstFreeBlock->pxNextFreeBlock = &xEnd;                                                                              \
+}
+/*-----------------------------------------------------------*/
+
+#if ( INCLUDE_vPortUsedMem == 1 )
+
+void vPortUsedMem(int *bytesFree, int *bytesUsed, int *blocksFree)  
+{  
+  xBlockLink *pxBlock = &xStart;  
+
+  *bytesFree = 0;  
+  *bytesUsed = 0;  
+  *blocksFree = 0;
+
+  vTaskSuspendAll();  
+
+  while ((pxBlock) && (pxBlock != &xEnd))  
+  {  
+    *bytesFree += pxBlock->xBlockSize;  
+    pxBlock = pxBlock->pxNextFreeBlock;  
+    ++*blocksFree;
+  }  
+
+  xTaskResumeAll();  
+
+  *bytesUsed = configTOTAL_HEAP_SIZE - *bytesFree;
+}  
+
+#endif
+/*-----------------------------------------------------------*/
+
+void *pvPortMalloc( size_t xWantedSize )
+{
+  xBlockLink *pxBlock, *pxPreviousBlock, *pxNewBlockLink;
+  static portBASE_TYPE xHeapHasBeenInitialised = pdFALSE;
+  void *pvReturn = NULL;
+
+  vTaskSuspendAll();
+  {
+    /* If this is the first call to malloc then the heap will require
+       initialisation to setup the list of free blocks. */
+    if( xHeapHasBeenInitialised == pdFALSE )
+    {
+      prvHeapInit();
+      xHeapHasBeenInitialised = pdTRUE;
+    }
+
+    /* The wanted size is increased so it can contain a xBlockLink
+       structure in addition to the requested amount of bytes. */
+    if( xWantedSize > 0 )
+    {
+      xWantedSize += heapSTRUCT_SIZE;
+
+      /* Ensure that blocks are always aligned to the required number of bytes. */
+      if( xWantedSize & heapBYTE_ALIGNMENT_MASK )
+      {
+        /* Byte alignment required. */
+        xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & heapBYTE_ALIGNMENT_MASK ) );
+      }
+    }
+
+    if( ( xWantedSize > 0 ) && ( xWantedSize < configTOTAL_HEAP_SIZE ) )
+    {
+      /* Blocks are stored in byte order - traverse the list from the start
+         (smallest) block until one of adequate size is found. */
+      pxPreviousBlock = &xStart;
+      pxBlock = xStart.pxNextFreeBlock;
+      while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock ) )
+      {
+        pxPreviousBlock = pxBlock;
+        pxBlock = pxBlock->pxNextFreeBlock;
+      }
+
+      /* If we found the end marker then a block of adequate size was not found. */
+      if( pxBlock != &xEnd )
+      {
+        /* Return the memory space - jumping over the xBlockLink structure
+           at its start. */
+        pvReturn = ( void * ) ( ( ( unsigned portCHAR * ) pxPreviousBlock->pxNextFreeBlock ) + heapSTRUCT_SIZE );
+
+        /* This block is being returned for use so must be taken our of the
+           list of free blocks. */
+        pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;
+
+        /* If the block is larger than required it can be split into two. */
+        if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE )
+        {
+          /* This block is to be split into two.  Create a new block
+             following the number of bytes requested. The void cast is
+             used to prevent byte alignment warnings from the compiler. */
+          pxNewBlockLink = ( void * ) ( ( ( unsigned portCHAR * ) pxBlock ) + xWantedSize );
+
+          /* Calculate the sizes of two blocks split from the single
+             block. */
+          pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;      
+          pxBlock->xBlockSize = xWantedSize;                   
+
+          /* Insert the new block into the list of free blocks. */
+          prvInsertBlockIntoFreeList( ( pxNewBlockLink ) );
+        }
+      }
+    }
+  }
+  xTaskResumeAll();
+
+  return pvReturn;
+}
+/*-----------------------------------------------------------*/
+
+void vPortFree( void *pv )
+{
+unsigned portCHAR *puc = ( unsigned portCHAR * ) pv;
+xBlockLink *pxLink;
+
+       if( pv )
+       {
+               /* The memory being freed will have an xBlockLink structure immediately
+               before it. */
+               puc -= heapSTRUCT_SIZE;
+
+               /* This casting is to keep the compiler from issuing warnings. */
+               pxLink = ( void * ) puc;
+
+               vTaskSuspendAll();
+               {                               
+                       /* Add this block to the list of free blocks. */
+                       prvInsertBlockIntoFreeList( ( ( xBlockLink * ) pxLink ) );
+               }
+               xTaskResumeAll();
+       }
+}
+/*-----------------------------------------------------------*/
+
diff --git a/FreeRTOS/portable/MemMang/heap_3.c b/FreeRTOS/portable/MemMang/heap_3.c
new file mode 100644 (file)
index 0000000..d5b55c3
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+       FreeRTOS.org V4.3.1 - Copyright (C) 2003-2007 Richard Barry.
+
+       This file is part of the FreeRTOS.org distribution.
+
+       FreeRTOS.org 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 2 of the License, or
+       (at your option) any later version.
+
+       FreeRTOS.org 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 FreeRTOS.org; if not, write to the Free Software
+       Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+       A special exception to the GPL can be applied should you wish to distribute
+       a combined work that includes FreeRTOS.org, without being obliged to provide
+       the source code for any proprietary components.  See the licensing section 
+       of http://www.FreeRTOS.org for full details of how and when the exception
+       can be applied.
+
+       ***************************************************************************
+       See http://www.FreeRTOS.org for documentation, latest information, license 
+       and contact details.  Please ensure to read the configuration and relevant 
+       port sections of the online documentation.
+
+       Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along
+       with commercial development and support options.
+       ***************************************************************************
+*/
+
+
+/*
+ * Implementation of pvPortMalloc() and vPortFree() that relies on the
+ * compilers own malloc() and free() implementations.
+ *
+ * This file can only be used if the linker is configured to to generate
+ * a heap memory area.
+ *
+ * See heap_2.c and heap_1.c for alternative implementations, and the memory
+ * management pages of http://www.FreeRTOS.org for more information.
+ */
+
+#include <stdlib.h>
+
+#include "FreeRTOS.h"
+#include "task.h"
+
+/*-----------------------------------------------------------*/
+
+void *pvPortMalloc( size_t xWantedSize )
+{
+void *pvReturn;
+
+       vTaskSuspendAll();
+       {
+               pvReturn = malloc( xWantedSize );
+       }
+       xTaskResumeAll();
+
+       return pvReturn;
+}
+/*-----------------------------------------------------------*/
+
+void vPortFree( void *pv )
+{
+       if( pv )
+       {
+               vTaskSuspendAll();
+               {
+                       free( pv );
+               }
+               xTaskResumeAll();
+       }
+}
+
+
+
diff --git a/FreeRTOS/queue.c b/FreeRTOS/queue.c
new file mode 100644 (file)
index 0000000..ab0c13a
--- /dev/null
@@ -0,0 +1,930 @@
+/*
+       FreeRTOS.org V4.4.0 - Copyright (C) 2003-2007 Richard Barry.
+
+       This file is part of the FreeRTOS.org distribution.
+
+       FreeRTOS.org 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 2 of the License, or
+       (at your option) any later version.
+
+       FreeRTOS.org 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 FreeRTOS.org; if not, write to the Free Software
+       Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+       A special exception to the GPL can be applied should you wish to distribute
+       a combined work that includes FreeRTOS.org, without being obliged to provide
+       the source code for any proprietary components.  See the licensing section
+       of http://www.FreeRTOS.org for full details of how and when the exception
+       can be applied.
+
+       ***************************************************************************
+       See http://www.FreeRTOS.org for documentation, latest information, license
+       and contact details.  Please ensure to read the configuration and relevant
+       port sections of the online documentation.
+
+       Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along
+       with commercial development and support options.
+       ***************************************************************************
+*/
+
+/*
+Changes from V1.01
+
+       + More use of 8bit data types.
+       + Function name prefixes changed where the data type returned has changed.
+
+Changed from V2.0.0
+
+       + Added the queue locking mechanism and make more use of the scheduler
+         suspension feature to minimise the time interrupts have to be disabled
+         when accessing a queue.
+
+Changed from V2.2.0
+
+       + Explicit use of 'signed' qualifier on portCHAR types added.
+
+Changes from V3.0.0
+
+       + API changes as described on the FreeRTOS.org WEB site.
+
+Changes from V3.2.3
+
+       + Added the queue functions that can be used from co-routines.
+
+Changes from V4.0.5
+
+       + Added a loop within xQueueSend() and xQueueReceive() to prevent the
+         functions exiting when a block time remains and the function has
+         not completed.
+
+Changes from V4.1.2:
+
+       + BUG FIX:  Removed the call to prvIsQueueEmpty from within xQueueCRReceive
+         as it exited with interrupts enabled.  Thanks Paul Katz.
+
+Changes from V4.1.3:
+
+       + Modified xQueueSend() and xQueueReceive() to handle the (very unlikely) 
+       case whereby a task unblocking due to a temporal event can remove/send an 
+       item from/to a queue when a higher priority task is     still blocked on the 
+       queue.  This modification is a result of the SafeRTOS testing.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include "FreeRTOS.h"
+#include "task.h"
+#include "croutine.h"
+
+/*-----------------------------------------------------------
+ * PUBLIC LIST API documented in list.h
+ *----------------------------------------------------------*/
+
+/* Constants used with the cRxLock and cTxLock structure members. */
+#define queueUNLOCKED  ( ( signed portBASE_TYPE ) -1 )
+#define queueERRONEOUS_UNBLOCK                                 ( -1 )
+
+/*
+ * Definition of the queue used by the scheduler.
+ * Items are queued by copy, not reference.
+ */
+typedef struct QueueDefinition
+{
+       signed portCHAR *pcHead;                                /*< Points to the beginning of the queue storage area. */
+       signed portCHAR *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 portCHAR *pcWriteTo;                             /*< Points to the free next place in the storage area. */
+       signed portCHAR *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. */
+
+       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 );
+signed portBASE_TYPE xQueueSend( xQueueHandle xQueue, const void * pvItemToQueue, portTickType xTicksToWait );
+unsigned portBASE_TYPE uxQueueMessagesWaiting( xQueueHandle pxQueue );
+void vQueueDelete( xQueueHandle xQueue );
+signed portBASE_TYPE xQueueSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xTaskPreviouslyWoken );
+signed portBASE_TYPE xQueueReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait );
+signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxTaskWoken );
+
+#if configUSE_CO_ROUTINES == 1
+       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 );
+#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 );
+
+/*
+ * 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 );
+
+/*
+ * 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 );
+
+/*
+ * Macro that copies an item into the queue.  This is done by copying the item
+ * byte for byte, not by reference.  Updates the queue state to ensure it's
+ * integrity after the copy.
+ */
+#define prvCopyQueueData( pxQueue, pvItemToQueue )                                                                                             \
+{                                                                                                                                                                                              \
+       memcpy( ( void * ) pxQueue->pcWriteTo, pvItemToQueue, ( unsigned ) pxQueue->uxItemSize );       \
+       ++( pxQueue->uxMessagesWaiting );                                                                                                                       \
+       pxQueue->pcWriteTo += pxQueue->uxItemSize;                                                                                                      \
+       if( pxQueue->pcWriteTo >= pxQueue->pcTail )                                                                                                     \
+       {                                                                                                                                                                                       \
+               pxQueue->pcWriteTo = pxQueue->pcHead;                                                                                                   \
+       }                                                                                                                                                                                       \
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * Macro to mark a queue as locked.  Locking a queue prevents an ISR from
+ * accessing the queue event lists.
+ */
+#define prvLockQueue( pxQueue )                        \
+{                                                                              \
+       taskENTER_CRITICAL();                           \
+               ++( pxQueue->xRxLock );                 \
+               ++( pxQueue->xTxLock );                 \
+       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;
+
+       /* 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 portCHAR * ) 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 = 0;
+                               pxNewQueue->pcWriteTo = pxNewQueue->pcHead;
+                               pxNewQueue->pcReadFrom = pxNewQueue->pcHead + ( ( uxQueueLength - 1 ) * 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 ) );
+
+                               return  pxNewQueue;
+                       }
+                       else
+                       {
+                               vPortFree( pxNewQueue );
+                       }
+               }
+       }
+
+       /* Will only reach here if we could not allocate enough memory or no memory
+       was required. */
+       return NULL;
+}
+/*-----------------------------------------------------------*/
+
+signed portBASE_TYPE xQueueSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait )
+{
+signed portBASE_TYPE xReturn = pdPASS;
+xTimeOutType xTimeOut;
+
+       /* Make sure other tasks do not access the queue. */
+       vTaskSuspendAll();
+
+       /* Capture the current time status for future reference. */
+       vTaskSetTimeOutState( &xTimeOut );
+
+       /* It is important that this is the only thread/ISR that modifies the
+       ready or delayed lists until xTaskResumeAll() is called.  Places where
+       the ready/delayed lists are modified include:
+
+               + vTaskDelay() -  Nothing can call vTaskDelay as the scheduler is
+                 suspended, vTaskDelay() cannot be called from an ISR.
+               + vTaskPrioritySet() - Has a critical section around the access.
+               + vTaskSwitchContext() - This will not get executed while the scheduler
+                 is suspended.
+               + prvCheckDelayedTasks() - This will not get executed while the
+                 scheduler is suspended.
+               + xTaskCreate() - Has a critical section around the access.
+               + vTaskResume() - Has a critical section around the access.
+               + xTaskResumeAll() - Has a critical section around the access.
+               + xTaskRemoveFromEventList - Checks to see if the scheduler is
+                 suspended.  If so then the TCB being removed from the event is
+                 removed from the event and added to the xPendingReadyList.
+       */
+
+       /* Make sure interrupts do not access the queue event list. */
+       prvLockQueue( pxQueue );
+
+       /* It is important that interrupts to not access the event list of the
+       queue being modified here.  Places where the event list is modified
+       include:
+
+               + xQueueSendFromISR().  This checks the lock on the queue to see if
+                 it has access.  If the queue is locked then the Tx lock count is
+                 incremented to signify that a task waiting for data can be made ready
+                 once the queue lock is removed.  If the queue is not locked then
+                 a task can be moved from the event list, but will not be removed
+                 from the delayed list or placed in the ready list until the scheduler
+                 is unlocked.
+
+               + xQueueReceiveFromISR().  As per xQueueSendFromISR().
+       */
+               
+       /* If the queue is already full we may have to block. */
+       do
+       {
+               if( prvIsQueueFull( pxQueue ) )
+               {
+                       /* The queue is full - do we want to block or just leave without
+                       posting? */
+                       if( xTicksToWait > ( portTickType ) 0 )
+                       {
+                               /* We are going to place ourselves on the xTasksWaitingToSend event
+                               list, and will get woken should the delay expire, or space become
+                               available on the queue.
+                               
+                               As detailed above we do not require mutual exclusion on the event
+                               list as nothing else can modify it or the ready lists while we
+                               have the scheduler suspended and queue locked.
+                               
+                               It is possible that an ISR has removed data from the queue since we
+                               checked if any was available.  If this is the case then the data
+                               will have been copied from the queue, and the queue variables
+                               updated, but the event list will not yet have been checked to see if
+                               anything is waiting as the queue is locked. */
+                               vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait );
+       
+                               /* Force a context switch now as we are blocked.  We can do
+                               this from within a critical section as the task we are
+                               switching to has its own context.  When we return here (i.e. we
+                               unblock) we will leave the critical section as normal.
+                               
+                               It is possible that an ISR has caused an event on an unrelated and
+                               unlocked queue.  If this was the case then the event list for that
+                               queue will have been updated but the ready lists left unchanged -
+                               instead the readied task will have been added to the pending ready
+                               list. */
+                               taskENTER_CRITICAL();
+                               {
+                                       /* We can safely unlock the queue and scheduler here as
+                                       interrupts are disabled.  We must not yield with anything
+                                       locked, but we can yield from within a critical section.
+                                       
+                                       Tasks that have been placed on the pending ready list cannot
+                                       be tasks that are waiting for events on this queue.  See
+                                       in comment xTaskRemoveFromEventList(). */
+                                       prvUnlockQueue( pxQueue );
+       
+                                       /* Resuming the scheduler may cause a yield.  If so then there
+                                       is no point yielding again here. */
+                                       if( !xTaskResumeAll() )
+                                       {
+                                               taskYIELD();
+                                       }
+
+                                       /* We want to check to see if the queue is still full
+                                       before leaving the critical section.  This is to prevent
+                                       this task placing an item into the queue due to an
+                                       interrupt making space on the queue between critical
+                                       sections (when there might be a higher priority task
+                                       blocked on the queue that cannot run yet because the
+                                       scheduler gets suspended). */
+                                       if( pxQueue->uxMessagesWaiting == pxQueue->uxLength )
+                                       {
+                                               /* We unblocked but there is no space in the queue,
+                                               we probably timed out. */
+                                               xReturn = errQUEUE_FULL;
+                                       }
+       
+                                       /* Before leaving the critical section we have to ensure
+                                       exclusive access again. */
+                                       vTaskSuspendAll();
+                                       prvLockQueue( pxQueue );                                
+                               }
+                               taskEXIT_CRITICAL();
+                       }
+               }
+                       
+               /* If xReturn is errQUEUE_FULL then we unblocked when the queue
+               was still full.  Don't check it again now as it is possible that
+               an interrupt has removed an item from the queue since we left the
+               critical section and we don't want to write to the queue in case
+               there is a task of higher priority blocked waiting for space to
+               be available on the queue.  If this is the case the higher priority
+               task will execute when the scheduler is unsupended. */
+               if( xReturn != errQUEUE_FULL )
+               {
+                       /* When we are here it is possible that we unblocked as space became
+                       available on the queue.  It is also possible that an ISR posted to the
+                       queue since we left the critical section, so it may be that again there
+                       is no space.  This would only happen if a task and ISR post onto the
+                       same queue. */
+                       taskENTER_CRITICAL();
+                       {
+                               if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
+                               {
+                                       /* There is room in the queue, copy the data into the queue. */                 
+                                       prvCopyQueueData( pxQueue, pvItemToQueue );             
+                                       xReturn = pdPASS;
+               
+                                       /* Update the TxLock count so prvUnlockQueue knows to check for
+                                       tasks waiting for data to become available in the queue. */
+                                       ++( pxQueue->xTxLock );
+                               }
+                               else
+                               {
+                                       xReturn = errQUEUE_FULL;
+                               }
+                       }
+                       taskEXIT_CRITICAL();
+               }
+
+               if( xReturn == errQUEUE_FULL )
+               {
+                       if( xTicksToWait > 0 )
+                       {
+                               if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
+                               {
+                                       xReturn = queueERRONEOUS_UNBLOCK;
+                               }
+                       }
+               }
+       }
+       while( xReturn == queueERRONEOUS_UNBLOCK );
+
+       prvUnlockQueue( pxQueue );
+       xTaskResumeAll();
+
+       return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+signed portBASE_TYPE xQueueSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xTaskPreviouslyWoken )
+{
+       /* Similar to xQueueSend, 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). */
+       if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
+       {
+               prvCopyQueueData( pxQueue, pvItemToQueue );
+
+               /* 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 )
+               {
+                       /* We only want to wake one task per ISR, so check that a task has
+                       not already been woken. */
+                       if( !xTaskPreviouslyWoken )             
+                       {
+                               if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )
+                               {
+                                       if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
+                                       {
+                                               /* The task waiting has a higher priority so record that a
+                                               context switch is required. */
+                                               return pdTRUE;
+                                       }
+                               }
+                       }
+               }
+               else
+               {
+                       /* Increment the lock count so the task that unlocks the queue
+                       knows that data was posted while it was locked. */
+                       ++( pxQueue->xTxLock );
+               }
+       }
+
+       return xTaskPreviouslyWoken;
+}
+/*-----------------------------------------------------------*/
+
+signed portBASE_TYPE xQueueReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait )
+{
+signed portBASE_TYPE xReturn = pdTRUE;
+xTimeOutType xTimeOut;
+
+       /* This function is very similar to xQueueSend().  See comments within
+       xQueueSend() for a more detailed explanation.
+
+       Make sure other tasks do not access the queue. */
+       vTaskSuspendAll();
+
+       /* Capture the current time status for future reference. */
+       vTaskSetTimeOutState( &xTimeOut );
+
+       /* Make sure interrupts do not access the queue. */
+       prvLockQueue( pxQueue );
+
+       do
+       {
+               /* If there are no messages in the queue we may have to block. */
+               if( prvIsQueueEmpty( pxQueue ) )
+               {
+                       /* There are no messages in the queue, do we want to block or just
+                       leave with nothing? */                  
+                       if( xTicksToWait > ( portTickType ) 0 )
+                       {
+                               vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
+                               taskENTER_CRITICAL();
+                               {
+                                       prvUnlockQueue( pxQueue );
+                                       if( !xTaskResumeAll() )
+                                       {
+                                               taskYIELD();
+                                       }
+
+                                       if( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 )
+                                       {
+                                               /* We unblocked but the queue is empty.  We probably
+                                               timed out. */
+                                               xReturn = errQUEUE_EMPTY;
+                                       }
+       
+                                       vTaskSuspendAll();
+                                       prvLockQueue( pxQueue );
+                               }
+                               taskEXIT_CRITICAL();
+                       }
+               }
+       
+               if( xReturn != errQUEUE_EMPTY )
+               {
+                       taskENTER_CRITICAL();
+                       {
+                               if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )
+                               {
+                                       pxQueue->pcReadFrom += pxQueue->uxItemSize;
+                                       if( pxQueue->pcReadFrom >= pxQueue->pcTail )
+                                       {
+                                               pxQueue->pcReadFrom = pxQueue->pcHead;
+                                       }
+                                       --( pxQueue->uxMessagesWaiting );
+                                       memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );
+               
+                                       /* Increment the lock count so prvUnlockQueue knows to check for
+                                       tasks waiting for space to become available on the queue. */
+                                       ++( pxQueue->xRxLock );
+                                       xReturn = pdPASS;
+                               }
+                               else
+                               {
+                                       xReturn = errQUEUE_EMPTY;
+                               }
+                       }
+                       taskEXIT_CRITICAL();
+               }
+
+               if( xReturn == errQUEUE_EMPTY )
+               {
+                       if( xTicksToWait > 0 )
+                       {
+                               if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
+                               {
+                                       xReturn = queueERRONEOUS_UNBLOCK;
+                               }
+                       }
+               }
+       } while( xReturn == queueERRONEOUS_UNBLOCK );
+
+       /* We no longer require exclusive access to the queue. */
+       prvUnlockQueue( pxQueue );
+       xTaskResumeAll();
+
+       return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxTaskWoken )
+{
+signed portBASE_TYPE xReturn;
+
+       /* We cannot block from an ISR, so check there is data available. */
+       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 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 )
+               {
+                       /* We only want to wake one task per ISR, so check that a task has
+                       not already been woken. */
+                       if( !( *pxTaskWoken ) )
+                       {
+                               if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )
+                               {
+                                       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;
+       }
+
+       return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+unsigned portBASE_TYPE uxQueueMessagesWaiting( xQueueHandle pxQueue )
+{
+unsigned portBASE_TYPE uxReturn;
+
+       taskENTER_CRITICAL();
+               uxReturn = pxQueue->uxMessagesWaiting;
+       taskEXIT_CRITICAL();
+
+       return uxReturn;
+}
+/*-----------------------------------------------------------*/
+
+void vQueueDelete( xQueueHandle pxQueue )
+{
+       vPortFree( pxQueue->pcHead );
+       vPortFree( pxQueue );
+}
+/*-----------------------------------------------------------*/
+
+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();
+       {
+               --( pxQueue->xTxLock );
+
+               /* See if data was added to the queue while it was locked. */
+               if( pxQueue->xTxLock > queueUNLOCKED )
+               {
+                       pxQueue->xTxLock = queueUNLOCKED;
+
+                       /* Data was posted while the queue was locked.  Are any tasks
+                       blocked waiting for data to become available? */
+                       if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )
+                       {
+                               /* 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();
+                               }
+                       }                       
+               }
+       }
+       taskEXIT_CRITICAL();
+
+       /* Do the same for the Rx lock. */
+       taskENTER_CRITICAL();
+       {
+               --( pxQueue->xRxLock );
+
+               if( pxQueue->xRxLock > queueUNLOCKED )
+               {
+                       pxQueue->xRxLock = queueUNLOCKED;
+
+                       if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )
+                       {
+                               if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
+                               {
+                                       vTaskMissedYield();
+                               }
+                       }                       
+               }
+       }
+       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;
+}
+/*-----------------------------------------------------------*/
+
+static signed portBASE_TYPE prvIsQueueFull( const xQueueHandle pxQueue )
+{
+signed portBASE_TYPE xReturn;
+
+       taskENTER_CRITICAL();
+               xReturn = ( pxQueue->uxMessagesWaiting == pxQueue->uxLength );
+       taskEXIT_CRITICAL();
+
+       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. */                 
+                       prvCopyQueueData( pxQueue, pvItemToQueue );             
+                       xReturn = pdPASS;
+
+                       /* Were any co-routines waiting for data to become available? */
+                       if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )
+                       {
+                               /* 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 mechansim 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 ) ) )
+                       {
+                               /* 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 mechansim 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 )
+       {
+               prvCopyQueueData( pxQueue, pvItemToQueue );
+
+               /* 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 ) ) )
+                       {
+                               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 ) ) )
+                       {
+                               if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
+                               {
+                                       *pxCoRoutineWoken = pdTRUE;
+                               }
+                       }
+               }
+
+               xReturn = pdPASS;
+       }
+       else
+       {
+               xReturn = pdFAIL;
+       }
+
+       return xReturn;
+}
+#endif
+/*-----------------------------------------------------------*/
+
diff --git a/FreeRTOS/tasks.c b/FreeRTOS/tasks.c
new file mode 100644 (file)
index 0000000..3f2f067
--- /dev/null
@@ -0,0 +1,1936 @@
+/*
+       FreeRTOS.org V4.4.0 - Copyright (C) 2003-2007 Richard Barry.
+
+       This file is part of the FreeRTOS.org distribution.
+
+       FreeRTOS.org 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 2 of the License, or
+       (at your option) any later version.
+
+       FreeRTOS.org 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 FreeRTOS.org; if not, write to the Free Software
+       Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+       A special exception to the GPL can be applied should you wish to distribute
+       a combined work that includes FreeRTOS.org, without being obliged to provide
+       the source code for any proprietary components.  See the licensing section
+       of http://www.FreeRTOS.org for full details of how and when the exception
+       can be applied.
+
+       ***************************************************************************
+       See http://www.FreeRTOS.org for documentation, latest information, license
+       and contact details.  Please ensure to read the configuration and relevant
+       port sections of the online documentation.
+
+       Also see http://www.SafeRTOS.com for an IEC 61508 compliant version, along
+       with development and support options.
+       ***************************************************************************
+*/
+
+/*
+Changes from V1.00:
+       
+       + Call to portRESTORE_CONTEXT has been removed.  The first context
+         switch is now performed within sPortStartScheduler().
+
+Changes from V1.01:
+
+       + More use of 8bit data types.
+       + Function name prefixes changed where the data type returned has changed.
+       + configUSE_TRACE_FACILITY is no longer defined by default.
+
+Changes from V1.2.0
+
+       + Introduced ucTopReadyPriority.  This tracks the highest priority ready
+         queue that contains a valid TCB and thus makes the context switch
+         slightly faster.
+
+       + prvAddTaskToReadyQueue() has been made a macro.
+
+Changes from V1.2.6
+
+       + Added conditional compilation directives.
+       + Extended API.
+       + Rearranged function order.
+       + Creating a task now causes a context switch if the task being created
+         has a higher priority than the calling task - assuming the kernel is
+         running.
+       + vTaskDelete() now only causes a context switch if the calling task is
+         the task being deleted.
+
+Changes from V2.0.0
+
+       + Allow the type of the tick count to be 16 or 32 bits.
+       + Introduce xPendingReadyList feature to allow the time interrupts have to
+         be disabled to be minimised.
+       + Remove the #if( INCLUDE_vTaskSuspendAll ) statements.  vTaskSuspendAll()
+         is now always included as it is used by the scheduler itself.
+
+Changes from V2.1.0
+
+       + Bug fix - pxCurrentTCB is now initialised before the call to
+         prvInitializeTaskLists().  Previously pxCurrentTCB could be accessed
+         while null.
+
+Changed from V2.1.1
+
+       + Change to where lStackSize is declared within sTaskCreate() to prevent
+         compiler warnings with 8051 port.
+
+Changes from V2.2.0
+
+       + Explicit use of 'signed' qualifier on portCHAR types added.
+       + Changed odd calculation of initial pxTopOfStack value when
+         portSTACK_GROWTH < 0.
+       + Removed pcVersionNumber definition.
+
+Changes from V2.5.3
+
+       + cTaskResumeAll() modified to ensure it can be called prior to the task
+         lists being initialised.
+
+Changes from V2.5.5
+
+       + Added API function vTaskDelayUntil().
+       + Added INCLUDE_vTaskDelay conditional compilation.
+
+Changes from V2.6.0
+
+       + Updated the vWriteTraceToBuffer macro to always be 4 byte aligned so it
+         can be used on ARM architectures.
+       + tskMAX_TASK_NAME_LEN definition replaced with the port specific
+         configMAX_TASK_NAME_LEN definition.
+       + Removed the call to strcpy when copying across the task name into the
+         TCB.
+       + Added ucTasksDeleted variable to prevent vTaskSuspendAll() being called
+         too often in the idle task.
+
+Changes between V3.0.0 and V2.6.1
+
+       + When resuming the scheduler a yield is performed if either a tick has
+         been missed, or a task is moved from the pending ready list into a ready
+         list.  Previously a yield was not performed on this second condition.
+       + Introduced the type portBASE_TYPE.  This necessitates several API
+         changes.
+       + Removed the sUsingPreemption variable.  The constant defined in
+         portmacro.h is now used directly.
+       + The idle task can now include an optional hook function - and no longer
+         completes its time slice if other tasks with equal priority to it are
+         ready to run.
+       + See the FreeRTOS.org documentation for more information on V2.x.x to
+         V3.x.x modifications.
+
+Changes from V3.1.1
+
+       + Modified vTaskPrioritySet() and vTaskResume() to allow these functions to
+         be called while the scheduler is suspended.
+       + Corrected the task ordering within event lists.
+
+Changes from V3.2.0
+
+       + Added function xTaskGetCurrentTaskHandle().
+
+Changes from V3.2.4
+
+       + Changed the volatile declarations on some variables to reflect the 
+         changes to the list definitions.
+       + Changed the order of the TCB definition so there is commonality between
+         the task control block and a co-routine control block.
+       + Allow the scheduler to be started even if no tasks other than the idle
+         task has been created.  This allows co-routines to run even when no tasks
+         have been created.
+       + The need for a context switch is now signalled if a task woken by an 
+         event has a priority greater or equal to the currently running task.
+         Previously this was only greater than.
+
+Changes from V4.0.0
+
+       + Added the xMissedYield handling.
+
+Changes from V4.0.1
+
+       + The function vTaskList() now suspends the scheduler rather than disabling
+         interrupts during the creation of the task list.  
+       + Allow a task to delete itself by passing in its own handle.  Previously 
+         this could only be done by passing in NULL.
+       + The tick hook function is now called only within a tick isr.  Previously
+         it was also called when the tick function was called during the scheduler
+         unlocking process.
+
+Changes from V4.0.3
+
+       + Extra checks have been placed in vTaskPrioritySet() to avoid unnecessary
+         yields.
+
+Changed from V4.0.4
+
+       + Bug fix:  The 'value' of the event list item is updated when the priority
+         of a task is changed.  Previously only the priority of the TCB itself was
+         changed.
+       + When resuming a task a check is first made to see if the task is actually
+         suspended.
+       + vTaskPrioritySet() and vTaskResume() no longer use the event list item.
+         This has not been necessary since V4.0.1 when the xMissedYield handling
+         was added.
+       + Implement xTaskResumeFromISR().
+
+Changes from V4.0.5
+
+       + Added utility functions and xOverflowCount variable to facilitate the
+         queue.c changes.
+
+Changes from V4.1.2
+       
+       + Tasks that block on events with a timeout of portMAX_DELAY are now
+         blocked indefinitely if configINCLUDE_vTaskSuspend is defined. 
+         Previously portMAX_DELAY was just the longest block time possible.
+
+Changes from V4.1.3
+
+       + Very small change made to xTaskCheckForTimeout() as a result of the 
+       SafeRTOS testing.  This corrects the case where the function can return an
+       invalid value - but only in an extremely unlikely scenario.
+
+Changes since V4.3.1:
+
+       + Added xTaskGetSchedulerState() function.
+       + Added prvIsTaskSuspended() to take into account the Occurrence of
+         vTaskResume() or vTaskResumeFromISR() being called passing in the
+         handle of a task that appears in the Suspended list only because it
+         is blocked on an event without a timeout being specified.
+       + Updated xTaskCheckForTimeout() to take into account that tasks blocked
+         using the Suspended list should never time out.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "FreeRTOS.h"
+#include "task.h"
+
+/*
+ * Macro to define the amount of stack available to the idle task.
+ */
+#define tskIDLE_STACK_SIZE     configMINIMAL_STACK_SIZE
+
+
+/*
+ * Default a definitions for backwards compatibility with old
+ * portmacro.h files.
+ */
+#ifndef configMAX_TASK_NAME_LEN
+       #define configMAX_TASK_NAME_LEN 16
+#endif
+
+#ifndef INCLUDE_xTaskGetCurrentTaskHandle
+       #define INCLUDE_xTaskGetCurrentTaskHandle 0
+#endif
+
+#ifndef configIDLE_SHOULD_YIELD
+       #define configIDLE_SHOULD_YIELD         1
+#endif
+
+#if configMAX_TASK_NAME_LEN < 1
+       #undef configMAX_TASK_NAME_LEN
+       #define configMAX_TASK_NAME_LEN 1
+#endif
+
+#ifndef INCLUDE_xTaskResumeFromISR
+       #define INCLUDE_xTaskResumeFromISR 1
+#endif
+
+#ifndef INCLUDE_xTaskGetSchedulerState
+       #define INCLUDE_xTaskGetSchedulerState 0
+#endif
+
+/*
+ * 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. */
+       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. */
+       unsigned portBASE_TYPE  uxTCBNumber;            /*< This is used for tracing the scheduler and making debugging easier only. */
+       signed portCHAR                 pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created.  Facilitates debugging only. */
+       unsigned portSHORT              usStackDepth;           /*< Total depth of the stack (when empty).  This is defined as the number of variables the stack can hold, not the number of bytes. */
+} tskTCB;
+
+/*lint -e956 */
+
+tskTCB * volatile pxCurrentTCB = NULL;                                 
+
+/* Lists for ready and blocked tasks. --------------------*/
+
+static xList pxReadyTasksLists[ configMAX_PRIORITIES ];        /*< Prioritised ready tasks. */
+static xList xDelayedTaskList1;                                                        /*< Delayed tasks. */
+static xList xDelayedTaskList2;                                                        /*< Delayed tasks (two lists are used - one for delays that have overflowed the current tick count. */
+static xList * volatile pxDelayedTaskList;                             /*< Points to the delayed task list currently being used. */
+static xList * volatile pxOverflowDelayedTaskList;             /*< Points to the delayed task list currently being used to hold tasks that have overflowed the current tick count. */
+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 )
+
+       static volatile xList xTasksWaitingTermination;         /*< Tasks that have been deleted - but the their memory not yet freed. */
+       static volatile unsigned portBASE_TYPE uxTasksDeleted = ( unsigned portBASE_TYPE ) 0;
+
+#endif
+
+#if ( INCLUDE_vTaskSuspend == 1 )
+
+       static xList xSuspendedTaskList;                                        /*< Tasks that are currently suspended. */
+
+#endif
+
+/* File private variables. --------------------------------*/
+static volatile unsigned portBASE_TYPE uxCurrentNumberOfTasks  = ( unsigned portBASE_TYPE ) 0;
+static volatile portTickType xTickCount                                                        = ( portTickType ) 0;
+static unsigned portBASE_TYPE uxTopUsedPriority                                        = tskIDLE_PRIORITY;
+static volatile unsigned portBASE_TYPE uxTopReadyPriority              = tskIDLE_PRIORITY;
+static volatile signed portBASE_TYPE xSchedulerRunning                 = pdFALSE;
+static volatile unsigned portBASE_TYPE uxSchedulerSuspended            = ( unsigned portBASE_TYPE ) pdFALSE;
+static volatile unsigned portBASE_TYPE uxMissedTicks                   = ( unsigned portBASE_TYPE ) 0;
+static volatile portBASE_TYPE xMissedYield                                             = ( portBASE_TYPE ) pdFALSE;
+static volatile portBASE_TYPE xNumOfOverflows                                  = ( portBASE_TYPE ) 0;
+/* 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     ( 0xa5 )
+
+/*
+ * Macros used by vListTask to indicate which state a task is in.
+ */
+#define tskBLOCKED_CHAR                ( ( signed portCHAR ) 'B' )
+#define tskREADY_CHAR          ( ( signed portCHAR ) 'R' )
+#define tskDELETED_CHAR                ( ( signed portCHAR ) 'D' )
+#define tskSUSPENDED_CHAR      ( ( signed portCHAR ) 'S' )
+
+/*
+ * Macros and private variables used by the trace facility.
+ */
+#if ( configUSE_TRACE_FACILITY == 1 )
+
+       #define tskSIZE_OF_EACH_TRACE_LINE                      ( ( unsigned portLONG ) ( sizeof( unsigned portLONG ) + sizeof( unsigned portLONG ) ) )
+       static volatile signed portCHAR * volatile pcTraceBuffer;
+       static signed portCHAR *pcTraceBufferStart;
+       static signed portCHAR *pcTraceBufferEnd;
+       static signed portBASE_TYPE xTracing = pdFALSE;
+
+#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 )                                                                                                                                                          \
+               {                                                                                                                                                                                       \
+                       static unsigned portBASE_TYPE uxPreviousTask = 255;                                                                             \
+                                                                                                                                                                                                       \
+                       if( uxPreviousTask != pxCurrentTCB->uxTCBNumber )                                                                               \
+                       {                                                                                                                                                                               \
+                               if( ( pcTraceBuffer + tskSIZE_OF_EACH_TRACE_LINE ) < pcTraceBufferEnd )                         \
+                               {                                                                                                                                                                       \
+                                       uxPreviousTask = pxCurrentTCB->uxTCBNumber;                                                                             \
+                                       *( unsigned portLONG * ) pcTraceBuffer = ( unsigned portLONG ) xTickCount;              \
+                                       pcTraceBuffer += sizeof( unsigned portLONG );                                                                   \
+                                       *( unsigned portLONG * ) pcTraceBuffer = ( unsigned portLONG ) uxPreviousTask;  \
+                                       pcTraceBuffer += sizeof( unsigned portLONG );                                                                   \
+                               }                                                                                                                                                                       \
+                               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()                                                                                                                                                                         \
+{                                                                                                                                                                                                                                      \
+register tskTCB *pxTCB;                                                                                                                                                                                                \
+                                                                                                                                                                                                                                       \
+       while( ( pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ) ) != NULL )                                              \
+       {                                                                                                                                                                                                                               \
+               if( xTickCount < listGET_LIST_ITEM_VALUE( &( pxTCB->xGenericListItem ) ) )                                                                      \
+               {                                                                                                                                                                                                                       \
+                       break;                                                                                                                                                                                                  \
+               }                                                                                                                                                                                                                       \
+               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 )
+
+
+/* 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, unsigned portSHORT usStackDepth, const signed portCHAR * const pcName, unsigned portBASE_TYPE uxPriority );
+
+/*
+ * 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 );
+
+/*
+ * 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 );
+#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 );
+
+/*
+ * Allocates memory from the heap for a TCB and associated stack.  Checks the
+ * allocation was successful.
+ */
+static tskTCB *prvAllocateTCBAndStack( unsigned portSHORT usStackDepth );
+
+/*
+ * 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( signed portCHAR *pcWriteBuffer, xList *pxList, signed portCHAR cStatus );
+
+#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 )
+
+       unsigned portSHORT usTaskCheckFreeStackSpace( const unsigned portCHAR *pucStackByte );
+
+#endif
+
+/*
+ * Checks that a task being resumed (unsuspended) is actually in the Suspended
+ * state.
+ */
+#if ( INCLUDE_vTaskSuspend == 1 )
+
+       static portBASE_TYPE prvIsTaskSuspended( const tskTCB * const pxTCB );  
+
+#endif
+
+/*lint +e956 */
+
+
+
+
+
+/*-----------------------------------------------------------
+ * TASK CREATION API documented in task.h
+ *----------------------------------------------------------*/
+
+signed portBASE_TYPE xTaskCreate( pdTASK_CODE pvTaskCode, const signed portCHAR * const pcName, unsigned portSHORT usStackDepth, void *pvParameters, unsigned portBASE_TYPE uxPriority, xTaskHandle *pxCreatedTask )
+{
+signed portBASE_TYPE xReturn;
+tskTCB * pxNewTCB;
+static unsigned portBASE_TYPE uxTaskNumber = 0; /*lint !e956 Static is deliberate - this is guarded before use. */
+
+       /* Allocate the memory required by the TCB and stack for the new task.
+       checking that the allocation was successful. */
+       pxNewTCB = prvAllocateTCBAndStack( usStackDepth );
+
+       if( pxNewTCB != NULL )
+       {               
+               portSTACK_TYPE *pxTopOfStack;
+
+               /* Setup the newly allocated TCB with the initial state of the task. */
+               prvInitialiseTCBVariables( pxNewTCB, usStackDepth, pcName, uxPriority );
+
+               /* 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 + ( pxNewTCB->usStackDepth - 1 );
+               }
+               #else
+               {
+                       pxTopOfStack = pxNewTCB->pxStack;       
+               }
+               #endif
+
+               /* 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. */
+               pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pvTaskCode, pvParameters );
+
+               /* We are going to manipulate the task queues to add this task to a
+               ready list, so must make sure no interrupts occur. */
+               portENTER_CRITICAL();
+               {
+                       uxCurrentNumberOfTasks++;
+                       if( uxCurrentNumberOfTasks == ( unsigned portBASE_TYPE ) 1 )
+                       {
+                               /* As this is the first task it must also be the current task. */
+                               pxCurrentTCB =  pxNewTCB;
+
+                               /* 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;
+                       }
+
+                       /* Add a counter into the TCB for tracing only. */
+                       pxNewTCB->uxTCBNumber = uxTaskNumber;
+                       uxTaskNumber++;
+
+                       prvAddTaskToReadyQueue( pxNewTCB );
+
+                       xReturn = pdPASS;
+               }
+               portEXIT_CRITICAL();
+       }
+       else
+       {
+               xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
+       }
+
+       if( xReturn == pdPASS )
+       {
+               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;
+               }
+
+               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 )
+                       {
+                               taskYIELD();
+                       }
+               }
+       }
+
+       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;
+               }
+               taskEXIT_CRITICAL();
+
+               /* Force a reschedule if we have just deleted the current task. */
+               if( xSchedulerRunning != pdFALSE ) 
+               {
+                       if( ( void * ) pxTaskToDelete == NULL )
+                       {
+                               taskYIELD();
+                       }
+               }
+       }
+
+#endif
+
+
+
+
+
+
+/*-----------------------------------------------------------
+ * TASK CONTROL API documented in task.h
+ *----------------------------------------------------------*/
+
+#if ( INCLUDE_vTaskDelayUntil == 1 )
+
+       void vTaskDelayUntil( portTickType *pxPreviousWakeTime, portTickType xTimeIncrement )
+       {
+       portTickType xTimeToWake;
+       portBASE_TYPE xAlreadyYielded, xShouldDelay = pdFALSE;
+
+               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 )
+                       {
+                               /* 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 ) );
+
+                               /* 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 ) );
+                               }
+                       }
+               }
+               xAlreadyYielded = xTaskResumeAll();
+
+               /* Force a reschedule if xTaskResumeAll has not already done so, we may
+               have put ourselves to sleep. */
+               if( !xAlreadyYielded )
+               {
+                       taskYIELD();
+               }
+       }       
+       
+#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();
+                       {
+                               /* 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 ) );
+
+                               /* 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 ) );
+                               }
+                       }
+                       xAlreadyYielded = xTaskResumeAll();
+               }
+               
+               /* Force a reschedule if xTaskResumeAll has not already done so, we may
+               have put ourselves to sleep. */
+               if( !xAlreadyYielded )
+               {
+                       taskYIELD();
+               }
+       }
+       
+#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, xYieldRequired = pdFALSE;
+
+               /* Ensure the new priority is valid. */
+               if( uxNewPriority >= configMAX_PRIORITIES )
+               {
+                       uxNewPriority = configMAX_PRIORITIES - 1;
+               }
+
+               taskENTER_CRITICAL();
+               {
+                       /* If null is passed in here then we are changing the
+                       priority of the calling function. */
+                       pxTCB = prvGetTCBFromHandle( pxTask );
+                       uxCurrentPriority = pxTCB->uxPriority;
+
+                       if( uxCurrentPriority != uxNewPriority )
+                       {
+                               /* The priority change may have readied a task of higher
+                               priority than the calling task. */
+                               if( uxNewPriority > pxCurrentTCB->uxPriority ) 
+                               {
+                                       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;
+                               }
+                       
+                               pxTCB->uxPriority = uxNewPriority;
+                               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 )
+                               {
+                                       taskYIELD();
+                               }                               
+                       }
+               }
+               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 );
+
+                       /* 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();
+
+               /* We may have just suspended the current task. */
+               if( ( void * ) pxTaskToSuspend == NULL )
+               {
+                       taskYIELD();
+               }
+       }
+
+#endif
+/*-----------------------------------------------------------*/
+
+#if ( INCLUDE_vTaskSuspend == 1 )
+
+       static portBASE_TYPE prvIsTaskSuspended( const tskTCB * const pxTCB )
+       {
+       portBASE_TYPE xReturn = pdFALSE;
+
+               /* 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;
+
+               /* 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 )
+               {
+                       taskENTER_CRITICAL();
+                       {
+                               if( prvIsTaskSuspended( pxTCB ) == pdTRUE )
+                               {
+                                       /* 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. */
+                                               taskYIELD();
+                                       }
+                               }
+                       }
+                       taskEXIT_CRITICAL();
+               }
+       }
+
+#endif
+
+/*-----------------------------------------------------------*/
+
+#if ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )
+
+       portBASE_TYPE xTaskResumeFromISR( xTaskHandle pxTaskToResume )
+       {
+       portBASE_TYPE xYieldRequired = pdFALSE;
+       tskTCB *pxTCB;
+
+               pxTCB = ( tskTCB * ) pxTaskToResume;
+
+               if( prvIsTaskSuspended( pxTCB ) == pdTRUE )
+               {
+                       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 preformed 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 portCHAR * ) "IDLE", tskIDLE_STACK_SIZE, ( void * ) NULL, tskIDLE_PRIORITY, ( xTaskHandle * ) NULL );
+
+       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;
+
+               /* 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(). */
+               }
+       }
+}
+/*-----------------------------------------------------------*/
+
+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 )
+{
+       portENTER_CRITICAL();
+               ++uxSchedulerSuspended;
+       portEXIT_CRITICAL();
+}
+/*----------------------------------------------------------*/
+
+signed portBASE_TYPE xTaskResumeAll( void )
+{
+register tskTCB *pxTCB;
+signed portBASE_TYPE xAlreadyYielded = pdFALSE;
+
+       /* 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. */
+       portENTER_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( ( pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY(  ( ( xList * ) &xPendingReadyList ) ) ) != NULL )
+                               {
+                                       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. */
+                                       xYieldRequired = pdTRUE;
+                               }
+                               
+                               if( ( xYieldRequired == pdTRUE ) || ( xMissedYield == pdTRUE ) )
+                               {
+                                       xAlreadyYielded = pdTRUE;
+                                       xMissedYield = pdFALSE;
+                                       taskYIELD();
+                               }
+                       }
+               }
+       }
+       portEXIT_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;
+}
+/*-----------------------------------------------------------*/
+
+unsigned portBASE_TYPE uxTaskGetNumberOfTasks( void )
+{
+unsigned portBASE_TYPE uxNumberOfTasks;
+
+       taskENTER_CRITICAL();
+               uxNumberOfTasks = uxCurrentNumberOfTasks;
+       taskEXIT_CRITICAL();
+
+       return uxNumberOfTasks;
+}
+/*-----------------------------------------------------------*/
+
+#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_vTaskDelete == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )
+
+       void vTaskList( signed portCHAR *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[ 0 ] = ( signed portCHAR ) 0x00;
+                       strcat( ( portCHAR * ) pcWriteBuffer, ( const portCHAR * ) "\r\n" );
+
+                       uxQueue = uxTopUsedPriority + 1;
+
+                       do
+                       {
+                               uxQueue--;
+
+                               if( !listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxQueue ] ) ) )
+                               {
+                                       prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &( pxReadyTasksLists[ uxQueue ] ), tskREADY_CHAR );                     
+                               }
+                       }while( uxQueue > ( unsigned portSHORT ) tskIDLE_PRIORITY );
+
+                       if( !listLIST_IS_EMPTY( pxDelayedTaskList ) )
+                       {
+                               prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) pxDelayedTaskList, tskBLOCKED_CHAR );
+                       }
+
+                       if( !listLIST_IS_EMPTY( pxOverflowDelayedTaskList ) )
+                       {
+                               prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) pxOverflowDelayedTaskList, tskBLOCKED_CHAR );
+                       }
+
+                       if( !listLIST_IS_EMPTY( &xTasksWaitingTermination ) )
+                       {
+                               prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &xTasksWaitingTermination, tskDELETED_CHAR );
+                       }
+
+                       if( !listLIST_IS_EMPTY( &xSuspendedTaskList ) )
+                       {
+                               prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &xSuspendedTaskList, tskSUSPENDED_CHAR );
+                       }
+               }
+        xTaskResumeAll();
+       }
+
+#endif
+/*----------------------------------------------------------*/
+
+#if ( configUSE_TRACE_FACILITY == 1 )
+
+       void vTaskStartTrace( signed portCHAR * pcBuffer, unsigned portLONG ulBufferSize )
+       {
+               portENTER_CRITICAL();
+               {
+                       pcTraceBuffer = ( volatile signed portCHAR * volatile )pcBuffer;
+                       pcTraceBufferStart = pcBuffer;
+                       pcTraceBufferEnd = pcBuffer + ( ulBufferSize - tskSIZE_OF_EACH_TRACE_LINE );
+                       xTracing = pdTRUE;
+               }
+               portEXIT_CRITICAL();
+       }
+
+#endif
+/*----------------------------------------------------------*/
+
+#if ( configUSE_TRACE_FACILITY == 1 )
+
+       unsigned portLONG ulTaskEndTrace( void )
+       {
+       unsigned portLONG ulBufferLength;
+
+               portENTER_CRITICAL();
+                       xTracing = pdFALSE;
+               portEXIT_CRITICAL();
+
+               ulBufferLength = ( unsigned portLONG ) ( pcTraceBuffer - pcTraceBufferStart );
+
+               return ulBufferLength;
+       }
+
+#endif
+
+
+
+/*-----------------------------------------------------------
+ * SCHEDULER INTERNALS AVAILABLE FOR PORTING PURPOSES
+ * documented in task.h
+ *----------------------------------------------------------*/
+
+
+inline void vTaskIncrementTick( void )
+{
+       /* 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! */
+                       pxTemp = pxDelayedTaskList;
+                       pxDelayedTaskList = pxOverflowDelayedTaskList;
+                       pxOverflowDelayedTaskList = pxTemp;
+            xNumOfOverflows++;
+               }
+
+               /* 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 )
+               {
+                       extern void vApplicationTickHook( void );
+
+                       vApplicationTickHook();
+               }
+               #endif
+       }
+
+       #if ( configUSE_TICK_HOOK == 1 )
+       {
+               extern void vApplicationTickHook( void );
+
+               /* Guard against the tick hook being called when the missed tick
+               count is being unwound (when the scheduler is being unlocked. */
+               if( uxMissedTicks == 0 )
+               {
+                       vApplicationTickHook();
+               }
+       }
+       #endif
+}
+/*-----------------------------------------------------------*/
+
+#if ( ( INCLUDE_vTaskCleanUpResources == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )
+
+       void vTaskCleanUpResources( void )
+       {
+       unsigned portSHORT usQueue;
+       volatile tskTCB *pxTCB;
+
+               usQueue = ( unsigned portSHORT ) uxTopUsedPriority + ( unsigned portSHORT ) 1;
+
+               /* Remove any TCB's from the ready queues. */
+               do
+               {
+                       usQueue--;
+
+                       while( !listLIST_IS_EMPTY( &( pxReadyTasksLists[ usQueue ] ) ) )
+                       {
+                               listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &( pxReadyTasksLists[ usQueue ] ) );
+                               vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
+
+                               prvDeleteTCB( ( tskTCB * ) pxTCB );
+                       }
+               }while( usQueue > ( unsigned portSHORT ) tskIDLE_PRIORITY );
+
+               /* Remove any TCB's from the delayed queue. */
+               while( !listLIST_IS_EMPTY( &xDelayedTaskList1 ) )
+               {
+                       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 ) )
+               {
+                       listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &xDelayedTaskList2 );
+                       vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
+
+                       prvDeleteTCB( ( tskTCB * ) pxTCB );
+               }
+
+               while( !listLIST_IS_EMPTY( &xSuspendedTaskList ) )
+               {
+                       listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &xSuspendedTaskList );
+                       vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
+
+                       prvDeleteTCB( ( tskTCB * ) pxTCB );
+               }               
+       }
+
+#endif
+/*-----------------------------------------------------------*/
+
+void vTaskSwitchContext( void )
+{
+       if( uxSchedulerSuspended != ( unsigned portBASE_TYPE ) pdFALSE )
+       {
+               /* The scheduler is currently suspended - do not allow a context
+               switch. */
+               xMissedYield = pdTRUE;
+               return;
+       }
+
+       /* Find the highest priority queue that contains ready tasks. */
+       while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ 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 ] ) );
+       vWriteTraceToBuffer();
+}
+/*-----------------------------------------------------------*/
+
+void vTaskPlaceOnEventList( xList *pxEventList, portTickType xTicksToWait )
+{
+portTickType xTimeToWake;
+
+       /* 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;
+               
+                       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 ) );
+                       }
+               }
+       }
+       #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;
+               
+                       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 ) );
+                       }
+       }
+       #endif
+}
+/*-----------------------------------------------------------*/
+
+signed portBASE_TYPE xTaskRemoveFromEventList( const xList *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. */
+       pxUnblockedTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList );
+       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 *pxTimeOut )
+{
+    pxTimeOut->xOverflowCount = xNumOfOverflows;
+    pxTimeOut->xTimeOnEntering = xTickCount;
+}
+/*-----------------------------------------------------------*/
+
+portBASE_TYPE xTaskCheckForTimeOut( xTimeOutType *pxTimeOut, portTickType * const pxTicksToWait )
+{
+portBASE_TYPE xReturn;
+
+       #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 ) && ( xTickCount >= 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( ( xTickCount - pxTimeOut->xTimeOnEntering ) < *pxTicksToWait )
+    {
+        /* Not a genuine timeout. Adjust parameters for time remaining. */
+        *pxTicksToWait -= ( xTickCount - pxTimeOut->xTimeOnEntering );
+        vTaskSetTimeOutState( pxTimeOut );
+        xReturn = pdFALSE;
+    }
+    else
+    {
+        xReturn = pdTRUE;
+    }
+
+    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, unsigned portSHORT usStackDepth, const signed portCHAR * const pcName, unsigned portBASE_TYPE uxPriority )
+{
+       pxTCB->usStackDepth = usStackDepth;
+
+       /* Store the function name in the TCB. */
+       strncpy( ( char * ) pxTCB->pcTaskName, ( const char * ) pcName, ( unsigned portSHORT ) configMAX_TASK_NAME_LEN );
+       pxTCB->pcTaskName[ ( unsigned portSHORT ) configMAX_TASK_NAME_LEN - ( unsigned portSHORT ) 1 ] = '\0';
+
+       /* This is used as an array index so must ensure it's not too large. */
+       if( uxPriority >= configMAX_PRIORITIES )
+       {
+               uxPriority = configMAX_PRIORITIES - 1;
+       }
+
+       pxTCB->uxPriority = uxPriority;
+
+       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 );
+}
+/*-----------------------------------------------------------*/
+
+static void prvInitialiseTaskLists( void )
+{
+unsigned portBASE_TYPE uxPriority;
+
+       for( uxPriority = 0; 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 )
+                       {
+                               tskTCB *pxTCB;
+
+                               portENTER_CRITICAL();
+                               {                       
+                                       pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( ( ( xList * ) &xTasksWaitingTermination ) );
+                                       vListRemove( &( pxTCB->xGenericListItem ) );
+                                       --uxCurrentNumberOfTasks;
+                                       --uxTasksDeleted;
+                               }
+                               portEXIT_CRITICAL();
+
+                               prvDeleteTCB( pxTCB );
+                       }
+               }
+       }
+       #endif
+}
+/*-----------------------------------------------------------*/
+
+static tskTCB *prvAllocateTCBAndStack( unsigned portSHORT usStackDepth )
+{
+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 * ) pvPortMalloc( ( ( size_t )usStackDepth ) * sizeof( portSTACK_TYPE ) );
+
+               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( signed portCHAR *pcWriteBuffer, xList *pxList, signed portCHAR cStatus )
+       {
+       volatile tskTCB *pxNextTCB, *pxFirstTCB;
+       static portCHAR pcStatusString[ 50 ];
+       unsigned portSHORT 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 );
+                       usStackRemaining = usTaskCheckFreeStackSpace( ( unsigned portCHAR * ) pxNextTCB->pxStack );
+                       sprintf( pcStatusString, ( portCHAR * ) "%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( ( portCHAR * ) pcWriteBuffer, ( portCHAR * ) pcStatusString );
+
+               } while( pxNextTCB != pxFirstTCB );
+       }
+
+#endif
+/*-----------------------------------------------------------*/
+
+#if ( configUSE_TRACE_FACILITY == 1 )
+       unsigned portSHORT usTaskCheckFreeStackSpace( const unsigned portCHAR *pucStackByte )
+       {
+       register unsigned portSHORT usCount = 0;
+
+               while( *pucStackByte == tskSTACK_FILL_BYTE )
+               {
+                       pucStackByte -= portSTACK_GROWTH;
+                       usCount++;
+               }
+
+               usCount /= sizeof( portSTACK_TYPE );
+
+               return usCount;
+       }
+#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. */
+               vPortFree( pxTCB->pxStack );
+               vPortFree( pxTCB );
+       }
+
+#endif
+
+
+/*-----------------------------------------------------------*/
+
+#if ( INCLUDE_xTaskGetCurrentTaskHandle == 1 )
+
+       xTaskHandle xTaskGetCurrentTaskHandle( void )
+       {
+       xTaskHandle xReturn;
+
+               portENTER_CRITICAL();
+               {
+                       xReturn = ( xTaskHandle ) pxCurrentTCB;
+               }
+               portEXIT_CRITICAL();
+
+               return xReturn;
+       }
+
+#endif
+
+/*-----------------------------------------------------------*/
+
+#if ( INCLUDE_xTaskGetSchedulerState == 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
+
+
diff --git a/FreeRTOSConfig.h b/FreeRTOSConfig.h
new file mode 100644 (file)
index 0000000..30c5bfa
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+       FreeRTOS.org V4.3.1 - Copyright (C) 2003-2007 Richard Barry.
+
+       This file is part of the FreeRTOS.org distribution.
+
+       FreeRTOS.org 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 2 of the License, or
+       (at your option) any later version.
+
+       FreeRTOS.org 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 FreeRTOS.org; if not, write to the Free Software
+       Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+       A special exception to the GPL can be applied should you wish to distribute
+       a combined work that includes FreeRTOS.org, without being obliged to provide
+       the source code for any proprietary components.  See the licensing section 
+       of http://www.FreeRTOS.org for full details of how and when the exception
+       can be applied.
+
+       ***************************************************************************
+       See http://www.FreeRTOS.org for documentation, latest information, license 
+       and contact details.  Please ensure to read the configuration and relevant 
+       port sections of the online documentation.
+
+       Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along
+       with commercial development and support options.
+       ***************************************************************************
+*/
+
+#ifndef FREERTOS_CONFIG_H
+#define FREERTOS_CONFIG_H
+
+#include <lpc210x.h>
+
+//
+// Application specific definitions.
+//
+#define configUSE_PREEMPTION             1
+#define configUSE_IDLE_HOOK                      0
+#define configUSE_TICK_HOOK                      0
+#define configCPU_CLOCK_HZ                       ((unsigned portLONG) 48000000)        // =12.0000MHz xtal multiplied by 4 using the PLL.
+#define configTICK_RATE_HZ                       ((portTickType) 100)
+#define configMAX_PRIORITIES             ((unsigned portBASE_TYPE) 4)
+#define configMINIMAL_STACK_SIZE       ((unsigned portSHORT) 128)
+#define configTOTAL_HEAP_SIZE            ((size_t) (18 * 1024))
+#define configMAX_TASK_NAME_LEN                (8)
+#define configUSE_TRACE_FACILITY       1
+#define configUSE_16_BIT_TICKS         0
+#define configIDLE_SHOULD_YIELD                1
+
+//
+//  Co-routine definitions
+//
+#define configUSE_CO_ROUTINES                0
+#define configMAX_CO_ROUTINE_PRIORITIES (2)
+
+//
+// Set the following definitions to 1 to include the API function, or zero
+// to exclude the API function.
+//
+#define INCLUDE_vTaskPrioritySet                 1
+#define INCLUDE_uxTaskPriorityGet                1
+#define INCLUDE_vTaskDelete                                1
+#define INCLUDE_vTaskCleanUpResources  0
+#define INCLUDE_vTaskSuspend                       1
+#define INCLUDE_vTaskDelayUntil                          1
+#define INCLUDE_vTaskDelay                                 1
+#define INCLUDE_vPortUsedMem          1
+
+#endif /* FREERTOS_CONFIG_H */
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..28b15e1
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,81 @@
+.SILENT: 
+
+#
+#  -D CFG_CONSOLE_USB   for console on USB
+#  -D CFG_CONSOLE_UART0 for console on UART0
+#  -D CFG_CONSOLE_UART1 for console on UART1 instead of USB (disables GPS task, baud rate set to 115200)
+#  -D CFG_USB_MSC       to use SD/MMC as a mass storage class device over USB
+#
+export LPC2148DEMO_OPTS=-D CFG_CONSOLE_USB
+
+#
+#  These shouldn't need to be changed
+#
+export CC=arm-elf-gcc
+export AR=arm-elf-ar
+export OBJCOPY=arm-elf-objcopy
+export OBJDUMP=arm-elf-objdump
+export CRT0=boot.s
+export WARNINGS=-Wall -Wextra -Wshadow -Wpointer-arith -Wbad-function-cast -Wcast-align -Wsign-compare -Waggregate-return -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wunused
+export CFLAGS=$(WARNINGS) -D RUN_MODE=RUN_FROM_ROM -D GCC_ARM7 $(INCLUDES) $(BASEINCLUDE) -mcpu=arm7tdmi -T$(LDSCRIPT) -g -O3 -fomit-frame-pointer $(LPC2148DEMO_OPTS)
+export LDSCRIPT=lpc2148-rom.ld
+export LINKER_FLAGS=$(COMMON)/common.a -Xlinker -olpc2148.elf -Xlinker -M -Xlinker -Map=lpc2148.map
+export ROOT=$(shell pwd)
+export BASEINCLUDE=-I$(ROOT) -I$(ROOT)/FreeRTOS/include
+export COMMON=$(ROOT)/common
+
+#
+#  Project sub-directories
+#
+SUBDIRS=FreeRTOS adc cpu dac eints fatfs fiq gps i2c iap leds monitor newlib rtc sensors swi uart usb usbmass usbser
+
+SRC_FILES = main.c
+
+ARM_OBJ = $(SRC_FILES:.c=.o)
+
+.PHONY: all
+all : 
+       @for i in $(SUBDIRS); do \
+       (cd $$i; $(MAKE) $(MFLAGS) $(MYMAKEFLAGS) all); done
+       make lpc2148.hex
+
+lpc2148.hex : .depend Makefile lpc2148.elf
+       $(OBJCOPY) lpc2148.elf -O ihex lpc2148.hex
+       @echo "Length is " `grep __"end_of_text__ = ." *.map | cut -b 17-35` "bytes"
+
+lpc2148.elf : .depend Makefile $(ARM_OBJ) $(COMMON)/common.a $(CRT0) $(LDSCRIPT)
+       $(CC) $(CFLAGS) $(ARM_OBJ) -nostartfiles $(CRT0) $(LINKER_FLAGS)
+       $(OBJDUMP) -d -S lpc2148.elf >lpc2148.lst
+$(ARM_OBJ) : %.o : %.c Makefile .depend
+       $(CC) -c $(CFLAGS) $< -o $@
+
+#
+#  The .depend files contains the list of header files that the
+#  various source files depend on.  By doing this, we'll only
+#  rebuild the .o's that are affected by header files changing.
+#
+.depend:
+       $(CC) $(CFLAGS) -M $(SRC_FILES) > .depend
+
+#
+#  Utility targets
+#
+.PHONY: tags
+tags :
+       @rm -f ctags
+       find . -name \*.c -exec ctags -a {} \;
+       find . -name \*.h -exec ctags -a {} \;
+
+.PHONEY: clean
+clean :
+       find . -name \*.o -exec rm -f {} \;
+       find . -name .depend -exec rm -f {} \;
+       rm -f *.map *.lst *.elf *.hex .depend $(COMMON)/common.a
+
+#
+#
+#
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..1a34a80
--- /dev/null
+++ b/README
@@ -0,0 +1,741 @@
+  J.C. Wren
+  2007/07/22
+  jcwren@jcwren.com
+
+  The most recent version of this package may be found at http://jcwren.com/arm
+
+  I'm changing the format of how updates are documented.  Rather than including
+  it in the body of the text, they will be appended to the front, with a date.  
+
+  2007/07/22, version 1.20:
+
+    Added interrupt driven I2C master transmit and receive code.  I'm pretty
+    confident that all the cases are handled correctly, but I don't have any
+    way to introduce certain errors for testing.  There are now two files in
+    the ./i2c directory, "i2cInt.c" and "i2cPolled.c".  Edit the ./i2c/Makefile
+    to select interrupt drive or polled I2C handling.  There is some support
+    for debugging I2C the interrupt drive routines.  As interrupts occur, the
+    various state changes are recorded, and the 'i2c dump' command will display
+    them.  This is disabled by default, but can be enabled by editing the
+    ./i2c/i2cInt.c file and defining I2C_DEBUG.
+
+    Added raw I2C support.  The 'i2c' commands allow directly reading and
+    writing an I2C device (as opposed to using the LM75 wrapper for LM75's, or
+    the EEPROM wrapper for EEPROMs).  See 'i2c help' for a list of commands.
+    Note that when reading from an I2C device via the raw commands, a maximum
+    of 16 bytes may be read or written.  If you need more, change the buffer
+    sizes in the appropriate commands in ./monitor/monitor.c, and also the
+    maximum number of arguments in the command dispatch table (commandListI2C).
+
+    Added EEPROM support.  The 'ee' subset of commands allow reading and
+    writing of a 24Cxxx series type EEPROM.  The code is currently targeted at
+    an Atmel 24C1024 128x8 part (I had some laying around).  It should be
+    pretty easy to rework them for any smaller part.  See 'ee help' for a list
+    of supported commands.
+
+    Fixed the LM75 support to allow writing the config, TOS and THYST
+    registers.  The previous versions allowed reading the registers, but I
+    forgot to write code to allow changing them.  Oops.
+
+    Moved 'date' and 'setdate' commands into the 'rtc' sub-menu as 'get' and
+    'set', respectively.  Added 'alarm' command that allows setting an alarm
+    date/time, or disabling it.  When an alarm fires, 'ALARM -- YYYY/MM/DD
+    HH:MM:SS' is printed to the console.  Also added 'periodic', which when
+    enabled, prints 'PERIODIC -- YYYY/MM/DD HH:MM:SS' to the console at the top
+    of every minute.  The RTC also demonstrates using the default vector
+    address functionality of the non-vectored IRQs in the VIC (alternatively,
+    by un-defining RTC_NONVECTOREDIRQ in the ./rtc/rtc.h file, a regular
+    vectored IRQ can be used).
+
+    Note on the RTC alarm and periodic output: It's really gross.  Console
+    input is handled by a libc read() call.  This is a blocking call,
+    implemented by doing a FreeRTOS xQueueReceive in the console device code
+    (UART 0, UART 1, or USB).  So the only way to get the read() to return so
+    the CCI can output the message is to reserve the special characters 0xfe
+    and 0xff (something a user can usually never type).  When the CCI getline
+    routine sees either of those characters, it immediately returns.  These
+    characters are then checked for by the CCI command parser, and either an
+    alarm or periodic message output.  If the user is in the process of typing
+    in a command, the input will be lost.  Without totally rewriting the CCI
+    into a queue based message passing architecture, I couldn't find a more
+    elegant way to handle this.  So basically, the RTC interrupt sends a 0xfe
+    or 0xff into the input buffer for the console device, which then returns
+    the character, which is then processed by the CCI code.
+
+    Changed the 'task' command to a 'mem' sub-command.  Added the 'map'
+    command, which shows how memory is allocated.  Overview: The .txt section
+    contains the program code, the initialization values for static data in RAM
+    (statements like 'static int i = 172;'), and the glue section (I believe
+    this is where ARM/THUMB inter-networking code is placed).  The .data section 
+    is the area of RAM that gets initialized from the constants in FLASH at 
+    startup (so that i == 172).  The .bss section is all static data that is 
+    zero length (statements like 'static int foo [12]').  The 'map' command 
+    prints out the starting and ending address of each area (size calulation is 
+    left to the user).  Also included is the starting and ending addresses for 
+    the various stacks (undefined, abort, FIQ, IRQ, service), the start of heap,
+    and the current heap end.  The scheduler executes in supervisor mode, tasks 
+    execute in system mode.
+
+    Added FIQ demo.  Timer 1 is set up to interrupt at 8hz (8 times a second,
+    or every 125 milliseconds), and is configured as a fast interrupt.  The
+    interrupt handler does nothing more than increment a counter.  The 'fiq on'
+    command will enable the timer, 'fiq off' will disable it, 'fiq count' will
+    print the counter value, and 'fiq clear' will reset the counter to 0.  As
+    long as the FIQ is enabled, it should be merrily counting along.  NOTE: the
+    actual FIQ vector is in ./boot.s.  Also in this file is the FIQ stack size.
+    I've set it to 32 bytes (8 words).  This was derived empirically by
+    examining the lpc2148.lst file, and seeing how many registers were pushed
+    by the fiqISR code.  Only 3 registers are pushed, so 8 words was deemed
+    enough space.  An interrupt that actually does anything substantial will
+    require more stack space, and the FIQ_STACK_SIZE should be adjusted
+    accordingly.  The FIQ in the CPSR is enabled by FreeRTOS when it starts the
+    scheduler, just like the IRQ.
+
+    The stacks have been tuned down pretty small to allow a larger heap area.
+    Many boot.s files allocate 1K for the supervisor stack, and another 1K for
+    the IRQ stack.  I've tried to exercise all the functions in the demo to get
+    a feel for stack usage, and both of those stacks have been tuned down to
+    256 bytes each.  There shouldn't be any issue with using a lot of stack in
+    any code prior to the call to vTaskStartScheduler(), since the supervisor
+    stack will overflow into system/user stack space.  Once tasks are running,
+    they have their own private stack spaces inside the FreeRTOS allocated
+    memory.  If the interrupt routines are modified to use more dynamic space,
+    then the interrupt stack may need to be increased.  So far, I've seen less
+    than 50% utilization.  The FIQ stack is very small, as it does nothing more
+    than increment a counter.  More complex FIQ routines will need more space.
+
+    Fixed problem with CCI 'mv' command failing.  Default compiliation options
+    for newlib for ARM don't define HAVE_RENAME, so the newlib rename() was
+    trying to do the link/unlink method of rename a file.  FatFS (and FAT file
+    systems) don't support links, so this was always failing, since link()
+    returns -1.  Provided our own rename() in newlib/syscalls.c to override the
+    newlib rename().
+
+    Added a data abort, prefetch abort and undefined instruction handler.   The
+    abort handler works by saving the state of the CPU to a block of memory,
+    then enabling the watchdog to force a reset.  This method was used instead
+    of printing directly to the serial port, as some people are using the USB
+    as the console port, and there's no gaurantee that the system is still
+    stable enough for USB to work.  So instead, the state is saved, the reset
+    is forced, and the user can then use the 'abort' set of commands to examine
+    the system state.  The 'regs' command will display the registers at the
+    time of the abort, and print the opcode of the instruction that failed
+    (except for prefetch abort).  The 'clear' command sets the memory used by
+    the abort handler to 0's.  The 'dirty' command sets the sigil used to
+    indicate if the abort memory contains valid data.  'dabort', 'pabort' and
+    'undef' force each of the types of aborts.  To try it, start the system,
+    type 'abort clear', then 'abort regs'.  All registers should be 0.  Now
+    type 'abort dabort'.  This forces an access to location 0x40008000, which
+    does not exist.  After the LPC2148 has reset, type 'abort regs'.  Examine
+    the PC value, open the lpc2148.lst file in an editor, and search for that
+    address.  You should find that the abort occurred in the monitorAbortDabort
+    code, at the 'ldrb' instruction.  Note that if the PC is showing somewhere
+    in the boot.s code area, it's likely a double abort is occuring.  Most
+    likely the stack pointer was already corrupted at the time of the abort,
+    and when the stack is being copied, it's reading from memory that will
+    cause a data abort.  After an abort, you'll want to do a 'wdt clear' to
+    clear the WDMOD.WDTOF flag, otherwise you'll be unable to re-enter ISP mode
+    without a power cycle.
+
+    Added 'misc' menu, which right now consists of the 'sizeof' command.  This
+    displays the size of the common C data types (just in case you weren't sure
+    a void * is 4 byes).  I'll add others here later, like when FreeRTOS starts 
+    exposing structure sizes in a future release.
+
+    Updated FreeRTOS to version 4.4.0
+
+    CURRENTLY BROKE, WAITING FOR JTAG DONGLE (feel free to submit a fix).
+    Added USB mass storage capability.  If CFG_USB_MSC is defined in the
+    Makefile, USB serial support will be disabled, and mass storage enabled.
+    This allows the MMC/SD card to be mounted like a disk drive.  DANGER!  The
+    CCI commands for file management remain enabled.  This means you can create
+    a file on the Windows (or Linux) mounted device, and see the changes from
+    the CCI.  HOWEVER: The SPI routines that read/write the MMC/SD card are not
+    thread-safe, so a USB request to read/write the disk can interrupt a CCI
+    command.  It's crazy dangerous to actually use the CCI file commands while
+    the MMC/SD card is mounted under Windows or Linux.  What you can do is
+    mount the MMC/SD card, copy files to/from it, unmount it, then use the CCI
+    commands to see that things really changed.  A later revision of the demo
+    package will likely at least protect the SPI I/O from being interrupted
+    (although this defeats the 'Real' in RTOS to do so).
+
+
+Overview:
+
+  This package demonstrates using LPCUSB and FatFS under FreeRTOS on the Olimex
+  LPC2148 board, using GCC and newlib.  Examples include FreeRTOS queues and
+  semaphores, LPC2148 analog to digital converters (ADCs), external interrupts,
+  the real-time clock (RTC), general purpose IO (GPIO), serial ports (UARTs),
+  and USB.   Also included is a newlib syscalls.c that almost completely
+  implements all syscalls.c functions.
+
+  The package (as built, .hex file included) presents the USB port as a virtual
+  comm port.  The virtualized port is used to talk to the console command
+  interpeter (CCI), that allows various functions to be exercised.
+  Alternatively, the package can re-compiled to use UART0 as the console port. 
+
+  If a GPS with NMEA output at 4800 baud is connected to UART1, one of the
+  tasks will parse the NMEA input stream, and display a position report.  In
+  addition, the RTC may be set from the GPS time/date.
+
+  FatFS support is included, and the CCI has several Unix-y commands to
+  manipulate files (mkfs, df, ls, mkdir, rmdir, rm, mv, cp, chmod, and sync).
+  There is also a command that allows through-put testing on the MMC/SD card. 
+
+  This package exists because I wanted to familiarize myself with the LPC2148,
+  FreeRTOS, FatFS and LPCUSB for a personal project, using GCC and newlib (who
+  can afford those commercial packages?  Not I).  By slightly modifying the
+  resulting framework, I was able to produce a package that others may possibly
+  find useful.
+
+
+Software tools:
+
+  The package compiles using the arm-elf GCC package.  Gentoo users can
+  install this by emerging the 'crossdev' package, then 'crossdev -t arm-elf'.
+  Once the arm-elf verison of GCC is installed, the package can be rebuilt with
+  'make'.    
+
+  To program the board, the Philips LPC2000 Flash Utility v2.2.3 Windows tool
+  was used.  There are Linux based tools for programming the LPC21xx parts, any
+  of which support the LPC2148 should be suitable.  It may be normal, but I
+  couldn't get the board to program at speeds other than 19200 and 38400.
+
+  ProComm was used to talk to the console port on UART0, and HyperTerm to talk
+  to the console port when using USB (Don't get me started on how crappy
+  HyperTerm is.  I *DESPISE* this abortion, and figure that Hilgraeve must have
+  pictures of Gates with a goat or something.  We can argue about MS quality
+  all day long, but HT has all the "quality" of a 6 year olds first programming
+  project in QBASIC.  The only reason it was used was because ProComm can't
+  talk to COM18, which is what the virtual serial port appears as).
+
+  If using the USB virtual comm port under Windows, the 'usbser.sys' and
+  'usbser.inf' files may be needed.  Often, these files are already on the
+  drive somewhere, and Start->Search->Files can be used to located them.  If
+  not present, they are included in the ./Windows directory in the package.
+
+  Under Linux, 'minicom' should be able to talk to both the serial port and the
+  virtual comm port the USB port appears as.  Bertrik's wiki, located at
+  "http://wiki.sikken.nl/index.php?title=LPCUSB", has a note about using LPCUSB
+  under Linux.
+
+  The default baud rate for UART0 is 115200.  The baud rate selected for the
+  USB virtual comm port is irrelevant, and may be any speed.
+
+
+Rebuilding it:
+
+  Simply typing 'make' should build the entire package.  The FreeRTOS modules
+  will emit several warnings about type punned references, which can (safely?)
+  be ignored.  
+
+  If you wish to use UART0 for the console port, edit ./monitor/monitor.c, jump
+  to near line 938, and change the "#if 1' to '#if 0', then recompile.
+
+  If you wish to change the baud rates for UART0 or UART1, edit ./main.c, jump
+  to near line 62, and change the rates.  Any standard baud rate should produce
+  usable results.
+
+  'make clean' will clean the project, removing the ./*.hex, ./*.lst, ./*.map,
+  ./*.elf files, and ./common/common.a, along with all *.o and .depend files in
+  any sub-directories.
+
+  'make tags' will rebuild the ctags file for 'vi' (and no doubt emacs, if
+  you're one of "them").
+
+
+Hardware (required and optional):
+
+  Olimex LPC-P2148 board (required)
+  USB cable (optional)
+  Serial cable (optional)
+  GPS with NMEA output and serial cable (optional)
+
+
+Using it (Windows):
+
+  For the purposes of these instructions, it will be assumed that COM1 is the
+  serial port on the host PC, a USB cable is connected to the LPC-P2148 board
+  and the PC, and that the Philips LPC2000 Flash Utility V2.2.3 will be used
+  for programming.  Please note that Windows 2000 was used, and that dialogs
+  for Windows XP are probably slightly different.  If you're using Vista, I'm
+  surprised it can stay up long enough for you to read this document...
+
+  Connect the RS232_0/ICSP DB-9 on the LPC-P2148 board to the comm port on the
+  PC, using a straight-thru serial cable.  Set both the ICSP slide switches
+  (located near the RS232_0/ICSP DB-9 connector) to the 'on' position (towards
+  the DB-9 connector), then press the reset button (located next to the ICSP
+  switches).  
+
+  Configure the Philips utility for COM1, 38400 baud.  Click the 'Read Device
+  ID' button.  LPC2148 should appear in the 'Device' text field.  Note that the
+  device ID has to be read to set the value, as there's a nasty bug in the
+  utility that prevents selecting it from the drop down list.
+
+  Click the "..." button in the 'Flash Programming' block, then locate and
+  select the 'lpc2148.hex' file, followed by clicking the 'Upload to Flash'
+  button.  At this point, the flash image should start being programmed.
+
+  When it completes, set the two ISCP slide switches to 'off', and press the
+  reset button.  The 'LED1' LED should start flashing.  
+
+  If Windows already does not already have the 'usbser.sys' driver installed, a
+  dialog will appear regarding the discovery of new hardware.  (I don't
+  remember how the dialog goes, so you'll have to infer your way through this
+  process).  When prompted for the driver, navigate to the ./Windows directory,
+  and select 'usbser.inf'.  This should install the driver for the virtual comm
+  port that will support the USB port.
+
+  Right-click on the 'My Computer' icon on the Windows desktop, select
+  Properties, then the Hardware tab, followed by 'Device Manager'.  Click the
+  '+' on the 'Ports (COM & LPT), and there should be an entry for "USB CDC
+  serial port emulation (COMxx)" (where 'xx' will be a number).  Note the COM
+  port for use with HyperTerm (see previous rant).
+  
+  Start HyperTerm (Start->Programs->Accessories->Communications->HyperTerm)
+  (see previous rant).  When the dialog appears, type a name for the connection
+  (The COMxx name is a good choice).  Click the drop-down box under 'Connect
+  using'.  Select the COMxx port name from the drop-down list.  Click 'OK',
+  followed by File->Save.  Now click the third icon from the left, which looks
+  like a telephone with the handset on the hook.
+
+  If all went well, typing 'help<return>' should show a list of commands
+  supported by the CCI.  If so, congratulations!  You can now play with various
+  commands.  If not, there's not much advice that can be offered at this point.
+
+  Baldur Gislason informed me that the Philips Flash Utility has been replaced
+  by by Flash Magic (http://www.flashmagictool.com).  I gave this a try, and it
+  worked well enough.  It's a nicer interface, but it seems a tad slower.
+  Rather than go into detail how to use it, I'll just say that I set the devce
+  to LPC2148, interface to 'None (ISP)', the oscillator frequency to 12.00000,
+  and checked the 'Erase blocks used by Hex File', and it just worked.
+
+
+Using it (Linux):
+
+  Eeek!  This needs to be written.
+
+  (Richard T. Stofer says that Debian plays nicely with the LPCUSB code.  with
+  the virtualized comm port appearing as ACM0.  'minicom' can talk to this
+  port).
+
+
+Hardware thingies:
+
+  The two pushy buttons on the LPC-P2148 board (B1 and B2) enable and disable
+  LED2.  Pressing B1 should light LED2, pressing B2 should extinguish it.
+  These buttons are connected to the EINT2 and EINT0 lines, respectively.  The
+  associated code demonstrates handling an external interrupt, and toggling an
+  I/O pin in the interrupt service routine (ISR).
+
+  The potentiometer, AN_TR, is connected to ADC0, channel 3.  The 'sensors'
+  task checks the value every 100 milliseconds.  The software divides the pot
+  into 4 zones, each covering about 1/4 of the range the pot may be rotated.
+  When the pot is fully counter-clockwise, LED1 will be on for 200 milliseconds
+  and off for 800.  When the pot is moved to the 2nd zone, the on/off times
+  become 400ms/600ms.  The 3rd zone has on/off times of 600ms/400ms, and fully
+  clockwise is 800ms on, 200ms off.
+
+  LED1 is controlled by the LED task.  This is a lower priority task.  Each
+  time a single on/off cycle has completed, it's message queue is checked to
+  see if the blink ratio times should be changed due to the AN_TR pot changing
+  zones.
+
+  LED2 is controlled by the B1 and B2 pushy buttons, as mentioned above.
+
+  The DAC output on the AOUT pin changes every 100 milliseconds by 1/64 of the
+  range of the DAC (0.0515625 volts).  The generates a sine wave with a period
+  of 12.8 seconds, or 0.078125 Hertz.  Hang a 'scope or DVM on the AOUT pin to
+  see the change.
+
+  The I2C routines are setup to talk to a LM75 temperature sensor.  These can
+  often be found on old PC motherboards, or as samples from National.  The I2C
+  demo code is a simple polled approach, and does not take advantage of either
+  interrupts or the I2C state machine.  The 'lm75' CCI command allows reading
+  and writing of the configuration, THYST and TOS registers, and reading of the
+  temperature register.  The 'lm75 mode' command determines if the registers
+  are read using an I2C repeated start sequence instead of an I2C stop then I2C
+  start.  Repeated starts are faster, and allow for holding the I2C bus in a
+  multi-master environment.  The default is repeated starts (mode 0).  There is
+  one potential spot for the code to hang.  If the I2C bus fails to release SCL
+  (if the I2C device is powered down, perhaps), it will hang waiting for the
+  status interrupt bit to change.  Any hard while loops should be wrapped in a
+  counter or timer check.
+
+  Demo now includes watchdog timer example.  'wdt test' enables the watchdog.
+  If no command is typed for 10 seconds, the system will reset.  'wdt status'
+  can be used to examine the current watchdog state and the RSIR register
+  (which allows determination of why a reset occurred).  Use 'wdt clear' to
+  clear the RSIR status.
+
+
+Sort of hardware thingies:
+
+  The SWI demo code is taken from several different projects, and culled down
+  into something I felt was more readable, and better for explanations.  The
+  CCI 'swi' commands allow setting the state of, turning on, turning off and
+  toggling LED2.  The commands starting with 'a' use the assembly interface
+  (assembly sequences are used to affect LED2), whereas the commands starting
+  with 'c' manage LED2 in C.  Note that the pushy-buttons also toggle LED2, so
+  there can be some interaction.
+
+
+CCI commands:
+
+  If you're a Linux user, most of the file commands are fairly self
+  explanatory.  If you're not a Linux user, you should be, because it's better
+  on our side of the fence.  The file commands require that a MMC/SD card be
+  installed in the MMC/SD slot.  BEFORE USING THE FILE COMMANDS, USE THE
+  'mount' COMMAND TO MOUNT THE MMC/SD CARD.  Note that the first partition on
+  the MMC/SD card will be mounted, and this is the only one supported.  It must
+  be a FAT12, FAT16 or FAT32 partition.
+
+  If the MMC/SD card is not formatted with a FAT12/FAT16/FAT32 file system, you
+  can use the 'mkfs' command to create it.  If anything already exists on the
+  card, 'mkfs' will wipe it out.  
+
+  Note that while a fairly good success rate has been obtained with the cards
+  on hand, one Sandisk 64MB MMC card did not work.  Not sure why, but the MMC
+  drivers are probably not handling something quite right.
+
+  'cpcon <filename>' allows a text file to be created from the CCI.  Enter text
+  until you're bored, then type ctrl-d save and exit.  Note that whatever
+  characters are typed are saved into the file verbatim.  This means that
+  characters like backspace are actually put into the file (feel free to
+  improve that code...)
+
+  Before creating any files, you may wish to set the system date, so that files
+  are date/time stamped properly.  If a GPS with NMEA output is connected to
+  RS232_1, you can use the 'gps' command to verify the serial connection, that
+  NMEA data is being parsed, and that the GPS has acquired (required for the
+  date/time to be set).  If you have no GPS attached, you may enter the date
+  and time as parameters.  'settime 2007/07/08 22:51:25' will set the date and
+  time to July 8th, 10:51pm and 25 seconds.  No timezone info is applied, so
+  date/times acquired from the GPS are UTC.  Date/times set manually may be set
+  to local time or UTC (or something completely random, if you're into that).
+
+  The 'thruput' command allows measuring MMC/SD read and write performance.
+  Eight file sizes are used: 1K, 8K, 16K, 64K, 128K, 512K, 1MB, and 2MB.  A
+  temporary file is created on the MMC/SD card.  Measurements can be done one
+  of four ways:  'noints' (fastest, but disables all tasking), 'normal' (CCI
+  task priority is not changed, no tasks are suspended), 'suspendall' (all
+  tasks are suspended, no context switches made, but 10ms interrupts still
+  runs), and 'high' (CCI task is elevated to highest priority for duration of
+  test).  Oddly, writes are faster than reads when not using the 'noints' mode.
+  I have not yet researched why.  Leaving interrupts enabled *seriously*
+  impacts the file system performance, nominally by a factor of 20.
+
+  Richard T. Stofer noticed that this slow down only appears when using the
+  'usbser.sys' drivers under Windows.  When using the Linux ACM drivers, or
+  when using UART0 as the console port with the USB cable disconnected, this
+  problem does not occur.  We can only assume that the Windows driver sends
+  lots of (needless) packets (yet another reason to switch to Linux!)
+
+  The 'date' command will report the current date/time from the RTC.  If you
+  have an external 3V battery plugged into the BAT connector, the RTC will
+  preserve it's values across power-downs.  Regardless of the battery presence,
+  date/time will be preserved across resets (as long as power is not removed).
+
+  The 'sensors' commands reports very little useful information.  The sensors
+  task executes every 100ms, and samples the ADC connected to the AN_TR
+  potentiometer.  Every time the task runs, the sensors counter is increment by
+  one.  If the AN_TR pot is adjusted far enough to change the zone, the ADC
+  changed value will increment.  See the section above on the pot.  The
+  associated code demonstrates running a high priority task with a constant
+  execution frequency, sampling an ADC, and sending a message to another task.
+
+  The 'mem' command displays the various tasks running, and the amount of
+  unused stack available to each task, along with the task priority and such.
+  The associated code demonstrates the 'vTaskList' RTOS call.  Note that in a
+  'real' system, leaving the task trace code enabled (configUSE_TRACE_FACILITY)
+  imposes a slight penalty on context switches, which may be undesirable.
+  
+  The 'iap' commands allow experimenting with the In-Application Programming
+  (IAP) code.  The demo code demonstrates preparing, erasing, writing, blank
+  checking, and retrieving processor ID and boot loader version numbers.  IAP
+  deals with primarily with sectors.  In the LPC2148 (which has 512K of flash),
+  there are 4K and 32K sectors.  The CCI will not allow selecting sectors that
+  are used for code.  The 'fss' command will find a safe sector to use with the
+  'iap' commands.  Once a safe sector is known, you can erase and fill this
+  sector.  The blank checking will work on any valid sector (there are 27 in
+  the LPC2148).  The IAP_COPYRAMTOFLASH (writing to flash) is demonstrated
+  by the fill command.  Whatever size the sector selected is, the 'fill'
+  command will fill the entire contents with the supplied byte value.  The 'md'
+  command can be used to dump the sector contents to see the effects of 'erase'
+  and 'fill'.  The 'stoa' command is used to convert a sector number to an
+  address for 'md'.  It is strongly recommended that you become familiar with
+  the section on IAP in the LPC2148 datasheet before using these commands.  The
+  IAP prepare and compare functions are not CCI accessible.  These are handled
+  internally by the erase and fill code.
+
+
+MMC/SD notes:
+
+  As mentioned above, I have a Sandisk 64MB MMC card that the MMC drivers can't
+  seem to recognize.  I have 4 other cards that work fine, one of which is an
+  MMC, the other three which are SD.  I'd like to resolve this issue.  
+
+  During the 'thruput' test, when interrupts are left enabled, I have on rare
+  occasions seen a read or write error occur.  I believe this is because a
+  context switch is taking place during some time critical code.  
+
+  Ideally, interrupts would be disabled.  However, disabling interrupts makes
+  an RTOS merely an OS.  The 'real-time' part means predictable response to
+  interrupts, and the executing time-critical tasks on-time.  In this code, the
+  MMC/SD code is non-reentrant (only one task may read/write the card), and not
+  time critical.   If multiple tasks have to write to disk, this would
+  currently have to be handled by creating a task that communicates through
+  queues to other tasks, and manages the MMC/SD card.
+
+  Note that if a GPS is connected, a message that a NMEA checksum could not be
+  found may occasionally appear.  While the actual test is being run, the GPS
+  task is not processing messages, and the serial buffer overruns.  When the
+  task is allowed to run again (between tests), partial NMEA messages that
+  cannot be parsed may be present, resulting in the error message.
+
+
+GCC notes:
+
+  This code was compiled with -O3.  This results in code that's about 16K
+  larger than -Os, but has a measurable impact on the MMC/SD card throughput
+  (not large, but it can be seen).  I went with -O3 because with 512K of FLASH,
+  and 144K or so used, there's plenty of room.
+
+  I'm not sure what the compiliation options for newlib are.  'crossdev'
+  compiled those, and I suspect it was with -Os, since embedded systems
+  generally tend to consider size over speed.
+
+  GCC is an amazing package.  I'm used to running into compiler issues with
+  many of the micros that I work with (SCCS, Microchips C18, etc).  It's so
+  nice to have a compiler that produces code without problems, and doesn't have
+  idiot front-ends that can't even get the sign on an enum correct (at least
+  Microchip got it right for the dsPIC and PIC24 parts, which used GCC.  C18...
+  Don't go there...)
+
+  There's a trick to writing Makefiles, and I don't have it.  It's an arcane
+  art, and involves the slaughtering of goats, black candles, and full moons.
+  The Makefiles I did write are very basic, and use recursion ('Recursive make
+  considered harmful!'.  Foo on that.  Worked for me).  
+
+  I tried a couple of approaches, and either everything built anyway, or
+  nothing built at all.  To make the linking work, as files are compiled,
+  they're dumped in to ./common/common.a, and main.c is linked against that.
+  So far, the expected bite on the butt for doing it this way has not happened.
+
+  It would be really neat to have Makefiles done right.  Alas, I don't know how
+  to do it right.  So if the common.a approach looks really ugly to you, that
+  means you probably know how to write Makefiles that handle sub-directories
+  correctly, and you can tell me how it should be done :)  (With examples!)
+
+
+Notes on newlib:
+
+  I wasn't happy with the newlib syscalls.c that was included in the original
+  LPC2148 port.  I more or less completely rewrote this, with the exception of
+  _sbrk().  _open() can open the serial ports, USB port, and FatFS files.  All
+  supporting functions except _fstat() work (see FatFS complaint at bottom).
+
+  Newlibs method of converting a file descriptor (as returned by _open()) to a
+  slot (which points to assorted info for that fd) uses a loop.  As this is
+  done on EVERY read and write call, unnecessary overhead is added.  I fixed
+  the find_slot() code to cache the last fd, and if it's the same on a
+  subsequent call, the search is skipped.
+
+  _open() is VERY suspect, in that remapping of FatFS f_open flags don't
+  correspond cleanly to Unix's open() call.  I handle the four common cases
+  correctly, but lesser used ones may result in a EINVAL errno on open.  
+
+  Opening FatFS files is expensive, RAM space-wise.  Each open file uses a
+  FatFS FIL structure which contains a 512 byte buffer, plus some additional
+  space.  With 32K on a LPC2148, and 20K being used for the FreeRTOS heap, that
+  leaves 12K that has to be used for the stack, heap, printf(), etc.  Don't go
+  wild opening files, and be sure to close unused files to free the space.  Use
+  open() instead of fopen() whenever possible, as the FILE structure has it's
+  own set of buffers.
+
+  There may be a way to figure out how much heap and stack have been used under
+  newlib.  If there is, I haven't figured it out yet.  I'd really like to be
+  able to make a newlib or system call that returns total space available, heap
+  used and stack used. 
+
+  Since stdout and stderr point to same place, it's wise to close stderr and
+  set stderr to stdout.  Only functions like assert() use stderr, so
+  intermixing stderr and stdout shouldn't be a problem.  Especially since
+  there's no redirection of I/O...
+
+
+Header file for LPC2148 (lpc210x.h):
+
+  The original LPC2148 header file was very lacking.  Not only were individual
+  bit fields generally not defined, major peripherials weren't defined.  As a
+  result, FreeRTOS, LPCUSB, FatFS and newlib all used local defines.  Worse,
+  some of these were simply "SOMEREG = (1<<31)".  Great.  What does bit 31 do?
+
+  Personally, I feel the best way is to define structures AND #defines.  It's
+  good that a structure has an element called 'CLK', but setting CLK to 0
+  doesn't give a hint as to what clock mode is being set.  A #define for
+  XXX_YYY_CLK_BIPHASE, then saying XXX_YYY_bits.ClkMode=XXX_YYY_CLK_BIPHASE is
+  a lot clearer.
+
+  I defined a mess of #defines, with the majority matching the names in the
+  datasheet.  There were few that become triplely redundant, such as
+  WD_WDFEED_WDFEED1.  This was reduced to WD_FEED_FEED1.  The characters prior
+  to the first underscore define the module, with the next set the defining the
+  register name.  Subsequent fields define the bit field name, and then
+  possible variations.
+
+  What I don't like about using #defines to define the registers is that the
+  programmer needs to know if the bits being affected need to be AND'ed or
+  OR'ed.  Structures neatly solve this problem, but defining all the structures
+  takes a lot of work (yea, IAR has already done that, but it's not legal to
+  just swipe their nice headers).
+
+  With one exception I'm aware of (in the TODO section), I rewrote all the code
+  that sets registers to use the values in the lpc210x.h file.  
+
+  While I doubt it makes the code more portable (will NXP change block
+  addresses, but leave bits the same?  Probably not), it does make it more
+  readable.  
+
+  One of the last major areas to be completed is to pull the USB protocol
+  engine #defines into lpc210x.h.  These are currently defined in one of the
+  USB header files, and have poor name scoping (does "ACK_STAT" tell you what
+  module or register it applies to?  No.)
+
+
+Software notes:
+
+  All copyrights are by their respective authors.  FreeRTOS is by Richard
+  Barry.  LPCUSB is by Bertrik Sikken.  FatFS is by ChaN, with sections by Joel
+  Winarske.  Other sections of code may have come from the intarweb, and have
+  respective copyrights, indicated or not.  Any code that I personally authored
+  is free for public consumption, unemcumbered by any copyrights, etc (that
+  crap is just too confusing.  BSD? LPGL? GPL3?  Who the hell knows...)
+
+  I've re-formatted a good deal of code in LPCUSB and FatFS.  Some portions
+  were re-written, others simply re-formatted to my coding style (which I
+  jokingly refer to as JC1).  I have occasionally whacked comment blocks that I
+  didn't really think indicated what the code did, or was redundant.  I
+  probably whacked some text with copyrights in the process.  This in no way
+  reflects an attempt to claim the work as my own, or to otherwise dishonor the
+  original authors.  As Isaac Newton (more or less) said, "If I have seen a
+  little further it is by standing on the shoulders of Giants."  Without the
+  work of these most excellent people, this code would not exist.  
+
+  Most of the reason for my re-formatting is my way of understanding the code,
+  going through it section by section.  It's good because I have a better
+  understanding of it, worse because it makes drop-in replacement with updates
+  from the authors more difficult.
+
+  The most affected area is the SPI handling in the FatFS code.  Originally
+  named 'mm_llc_spi1.c', I felt this was not cleanly integrated, so I rewrote
+  it.  Maybe it's not better, but it is different :)
+
+  The FreeRTOS code is almost completely untouched, except for moving an #if
+  around that allowed compiling the trace code (configUSE_TRACE_FACILITY)
+  without requiring the task suspend code (INCLUDE_vTaskSuspend).  In the end,
+  this was probably irrelevant, since I compiled the task suspend code in
+  anyway.
+
+
+Things I wish were different:
+
+  A collection of random little thoughts of things I wish were different.
+  These are just MY opinions, based on the way I do things.  It's not to say
+  the original authors were wrong.  It's just the way I'd make things, if I
+  were smart enough to write this stuff from scratch.  Most people probably
+  shouldn't even read the following list...
+
+  While FreeRTOS attempts to isolate the user from system data structures, it's
+  a little *too* aggressive.  These typedef'ed structures should be in a header
+  file, so applications can at least use sizeof() to help determine memory
+  allocation.  Everything is done through recasted void* pointers.
+
+  It would be neat if FreeRTOS had a xDelayTaskUntil() that also took one or
+  more queues as a blocking item.  I want to run a task every 'n' milliseconds,
+  but if something shows up in a queue, process it early.  Perhaps this could
+  work like Unix's select().  Or perhaps a variadic function that takes
+  xQueueHandles as parameters.
+
+  I dont' care for FreeRTOS's use of portBLAH typedefs for portable types.  The
+  world is pretty used to U8, U16, N32, and BOOL for unsigned char, unsigned
+  short, signed int, etc.  FreeRTOS also seems to require declaring too many
+  things as 'signed', which should be a default.  I'm sure this is done for
+  portability, but I find the types are not as intuitive as they could be.  
+
+  Another minor itch is that all function names and types start with 'x'.  I
+  would have preferred 'freertos', or better, a user-definable one, via a
+  #define macro.  I think programmers forget that their package may be
+  integrated into a larger system, and while their naming convention works well
+  for their purpose, it may not scale well.  FatFS and LPCUSB are guilty of
+  this as well.
+
+  FreeRTOS has a couple errors in several of the modules regarding type
+  punning.  I understand what type punning is, but I don't know how to fix it
+  safely.  Perhaps RB will fix those up in the next release.
+
+  FatFS changes return types too often, particularly for errors.  There's the
+  errors from the SPI routines, the MMC routines, the disk routines, and the
+  top layer FatFS code.  There should be unified errors for everything, so that
+  errors can be cleanly communicated up the stack.
+
+  FatFS can't go from file descriptor to filename.  I haven't figured out a
+  clean and reliable way to map a fd back to a filename (FatFS f_stat() needs a
+  file name).  I thought about malloc()'ing space in the openFiles_t structure
+  and copying the filename when the file is opened.  However, paths can get up
+  to 128 characters, and only _fstat() needs that information.  This seems very
+  wasteful.
+
+  FatFS wants the user to provid the get_fattime() function.  FatFS should
+  really have a file for locally provided functions.  It's already specific to
+  the SPI or IDE port implementation.  As such, it should be stubbed out to
+  return 0 if the function isn't provided, or allow the user to implement in
+  the platform specific file (basically, an equivalent of syscalls.c, but
+  internal to FatFS).
+
+  FatFS has naming conventions that I don't like.  It exposes too many internal
+  function names that should be declared static.  Structure names like 'FIL'
+  are ambiguous, and too likely to collide with other libraries.  Functions
+  should be preceed by the supporting module or library.  All FatFS functions
+  should be in the form of fatfsOpen, fatfsClose, etc.  
+
+  LPCUSB is not organized quite the way I'd do it.  The USB protocol engine
+  defines need to have their names modified and moved into the lpc210x.h. 
+
+  Newlib lacks certain calls on the ARM7 platform.  sync() and chmod() do not
+  exist, while mkdir() does, but wit no corresponding _mkdir() support in
+  syscalls.c.  Returning ENOSYS is easy enough, and doesn't take but a few
+  instructions.  Providing support for a wider range of calls would be good,
+  taking into mind things like FatFS that provide file system support, etc.
+
+  The Olimex board COMPLETELY lacks documentation (at least, that I've been
+  able to find).  It's up to the user to guess what the slide switches are for,
+  etc.  It's probably pretty obvious to someone who's used the LPC2000 parts
+  before, but if you're buying a board to get started, you have to waste time
+  figuring out how to use it.  Even a simple Xerox'ed sheet would have been
+  sufficient.
+
+  The Olimex board also lacks the ability to control the BSL line from the
+  serial port.  Reset works, but without being able to flip the BSL switch,
+  it has little value.
+
+  The buzzer on the Olimex board is useless.  Had it been connected to one of
+  the PWM outputs, some simple sound synthesis would have been possible.  At
+  best, it demostrates you can toggle I/O pins fast enough to make noise.
+  However, unless you want clicks in the output, you have to disable
+  interrupts.  And why *two* port pins?  One would have been sufficient.  I
+  would have preferred to have two more LEDs, rather than the buzzer.
+
+
+TODO:
+
+  ./FreeRTOS/portable/GCC/ARM7_LPC2000/port.c uses local defines for timer control
+  Finish rest of syscalls.c functions (fstat ())
+  Some modules (USB) still have local #defines for hardware (protocol engine)
+  Add VIC software interrupt demo (?)
+  Add data abort demo
+  Frequency measurement?
+  Add fast GPIO (beep speaker)
+  Fix SPI code to be thread safe
+  Fix I2C using polled mode for EEPROM
+  Add firmware update from file system
diff --git a/Windows/usbser.inf b/Windows/usbser.inf
new file mode 100644 (file)
index 0000000..4267aaf
--- /dev/null
@@ -0,0 +1,45 @@
+[Version]
+Signature="$Windows NT$"
+Class=Ports
+ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318}
+Provider=%LINUX%
+DriverVer=08/17/2004,0.0.2.0
+; Copyright (C) 2004 Al Borchers (alborchers@steinerpoint.com)
+; released under GNU General Public License
+
+[Manufacturer]
+%LINUX%=GSerialDeviceList
+
+[GSerialDeviceList]
+%GSERIAL%=GSerialInstall, USB\VID_FFFF&PID_0005
+
+[DestinationDirs]
+DefaultDestDir=10,System32\Drivers
+
+[GSerialInstall]
+CopyFiles=GSerialCopyFiles
+AddReg=GSerialAddReg
+
+[GSerialCopyFiles]
+usbser.sys
+
+[GSerialAddReg]
+HKR,,DevLoader,,*ntkern
+HKR,,NTMPDriver,,usbser.sys
+HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider"
+
+[GSerialInstall.Services]
+AddService = usbser,0x0002,GSerialService
+
+[GSerialService]
+DisplayName = %GSERIAL_DISPLAY_NAME%
+ServiceType = 1                  ; SERVICE_KERNEL_DRIVER
+StartType = 3                    ; SERVICE_DEMAND_START
+ErrorControl = 1                 ; SERVICE_ERROR_NORMAL
+ServiceBinary = %10%\System32\Drivers\usbser.sys
+LoadOrderGroup = Base
+
+[Strings]
+LINUX = "Linux"
+GSERIAL = "USB CDC serial port emulation"
+GSERIAL_DISPLAY_NAME = "USB CDC serial port emulation"
\ No newline at end of file
diff --git a/Windows/usbser.sys b/Windows/usbser.sys
new file mode 100755 (executable)
index 0000000..b390c36
Binary files /dev/null and b/Windows/usbser.sys differ
diff --git a/adc/Makefile b/adc/Makefile
new file mode 100644 (file)
index 0000000..497476b
--- /dev/null
@@ -0,0 +1,25 @@
+SRC_FILES=adc.c
+
+#
+# Define all object files.
+#
+ARM_OBJ = $(SRC_FILES:.c=.o)
+
+.PHONY: all
+all: $(ARM_OBJ)
+
+$(ARM_OBJ) : %.o : %.c Makefile .depend
+       $(CC) -c $(CFLAGS) $< -o $@
+       $(AR) r $(COMMON)/common.a $@
+
+#
+#  The .depend files contains the list of header files that the
+#  various source files depend on.  By doing this, we'll only
+#  rebuild the .o's that are affected by header files changing.
+#
+.depend:
+                       $(CC) $(CFLAGS) -M $(SRC_FILES) > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff --git a/adc/adc.c b/adc/adc.c
new file mode 100644 (file)
index 0000000..358a18d
--- /dev/null
+++ b/adc/adc.c
@@ -0,0 +1,28 @@
+#include "FreeRTOS.h"
+
+#include "adc.h"
+
+//
+//
+//
+int adcRead0_3 (void)
+{
+  AD0_CR |= AD_CR_START_NOW;
+
+  while (!(AD0_DR3 & AD_DR_DONE))
+    ;
+
+  return ((AD0_DR3 & AD_DR_RESULTMASK) >> AD_DR_RESULTSHIFT);
+}
+
+//
+//  Assumes PCLK == 48Mhz
+//
+void adcInit (void)
+{
+  SCB_PCONP |= SCB_PCONP_PCAD0;
+
+  PCB_PINSEL1 |= PCB_PINSEL1_P030_AD03;
+
+  AD0_CR = AD_CR_CLKS10 | AD_CR_PDN | ((11 - 1) << AD_CR_CLKDIVSHIFT) | AD_CR_SEL3;
+}
diff --git a/adc/adc.h b/adc/adc.h
new file mode 100644 (file)
index 0000000..a17bf8d
--- /dev/null
+++ b/adc/adc.h
@@ -0,0 +1,7 @@
+#ifndef _ADC_H_
+#define _ADC_H_
+
+int adcRead0_3 (void);
+void adcInit (void);
+
+#endif
diff --git a/boot.s b/boot.s
new file mode 100644 (file)
index 0000000..814c178
--- /dev/null
+++ b/boot.s
@@ -0,0 +1,367 @@
+@
+@  Sample initialization file 
+@
+        .extern main
+        .extern exit
+
+        .text
+        .code 32
+
+        .align  0
+
+        .extern __bss_beg__
+        .extern __bss_end__
+        .extern __stack_end__
+        .extern __data_beg__
+        .extern __data_end__
+        .extern __data+beg_src__
+
+        .global start
+        .global endless_loop
+
+@ 
+@  Stack sizes.  These have been determined empirically.  If your interrupt
+@  routines become more complex or use a lot of dynamically allocated space,
+@  the IRQ and/or FIQ stacks may been be grown.  The supervisor stack may 
+@  overflow into the system/user stack as the system is going any initialization,
+@  before starting the FreeRTOS scheduler.  The scheduler itself needs a small
+@  amount of supervisor stack space, once it's running.
+@
+        .set  UND_STACK_SIZE, 0x00000004
+        .set  ABT_STACK_SIZE, 0x00000004
+        .set  FIQ_STACK_SIZE, 0x00000020
+        .set  IRQ_STACK_SIZE, 0X00000100
+        .set  SVC_STACK_SIZE, 0x00000100
+
+@
+@  Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs 
+@
+        .set  MODE_USR, 0x10            @ User Mode 
+        .set  MODE_FIQ, 0x11            @ FIQ Mode 
+        .set  MODE_IRQ, 0x12            @ IRQ Mode 
+        .set  MODE_SVC, 0x13            @ Supervisor Mode 
+        .set  MODE_ABT, 0x17            @ Abort Mode 
+        .set  MODE_UND, 0x1B            @ Undefined Mode 
+        .set  MODE_SYS, 0x1F            @ System Mode 
+
+        .equ  I_BIT, 0x80               @ when I bit is set, IRQ is disabled 
+        .equ  F_BIT, 0x40               @ when F bit is set, FIQ is disabled 
+        .equ  T_BIT, 0x20               @ when T bit is set, THUMB mode is active
+
+start:
+_start:
+_mainCRTStartup:
+@
+@  Clear all of memory to 0xe5e5e5e5.  We use this value later to determine
+@  stack highwater usage.
+@
+        ldr     r1, .LC3                @ __data_beg__ is start of RAM 
+        ldr     r3, .LC6                @ __stack_end__ is end of RAM
+        sub     r3, r3, r1              @ Length of RAM to set
+        ldr     r2, =0xe5e5e5e5         @ Fill value
+
+.init_loop:
+        str     r2, [r1], #4            @ Store fill value, r1 += 4
+        subs    r3, r3, #4              @ Length -= 4
+        bgt     .init_loop              @ >= 0, go again
+
+.end_init_loop:
+
+@
+@  Clear BSS. 
+@
+        ldr     r1, .LC1                @ Start of memory block 
+        ldr     r3, .LC2                @ End of memory block 
+        subs    r3, r3, r1              @ Calculate length of block 
+        beq     .end_clear_loop         @ If 0, nothing to do
+        mov     r2, #0                  @ Fill value
+
+.clear_loop:
+        strb    r2, [r1], #1            @ Store byte, r1++
+        subs    r3, r3, #1              @ Decrement counter
+        bgt     .clear_loop             @ >= 0, go again
+
+.end_clear_loop:
+
+@
+@  Initialize data.
+@
+        ldr     r1, .LC3                @ Destination (.data in RAM)
+        ldr     r2, .LC4                @ Source (.data in FLASH)
+        ldr     r3, .LC5                @ End of .data in RAM
+        subs    r3, r3, r1              @ Calculate length of block 
+        beq     .end_set_loop           @ If 0, nothing to do
+
+.set_loop:
+        ldrb    r4, [r2], #1            @ Get byte from source, r2++
+        strb    r4, [r1], #1            @ Store byte to destination, r1++
+        subs    r3, r3, #1              @ Decrement loop counter
+        bgt     .set_loop               @ >= 0, go again
+
+.end_set_loop:
+
+@
+@  Setup a stack for each mode - note that this only sets up a usable stack
+@  for system/user, SWI and IRQ modes.   Also each mode is setup with
+@  interrupts initially disabled. 
+@
+        ldr   r1, .LC7                      @ Pointer to various values we update
+        ldr   r0, .LC6                      @ Get top of stack space
+        msr   CPSR_c, #MODE_UND|I_BIT|F_BIT @ Undefined Instruction Mode
+        mov   sp, r0                        @ Set undef mode SP
+        str   r0, [r1, #0]                  @ Store this so 'mem map' knows
+
+        sub   r0, r0, #UND_STACK_SIZE       @ Subtract undef stack size for abort stack start
+        msr   CPSR_c, #MODE_ABT|I_BIT|F_BIT @ Abort Mode 
+        mov   sp, r0                        @ Set abort mode SP
+        str   r0, [r1, #4]                  @ Store this so 'mem map' knows
+        str   r0, [r1, #8]                  @ Store this so 'mem map' knows
+
+        sub   r0, r0, #ABT_STACK_SIZE       @ Subtract abort stack size for FIQ stack start
+        msr   CPSR_c, #MODE_FIQ|I_BIT|F_BIT @ FIQ Mode 
+        mov   sp, r0                        @ Set FIQ mode SP
+        str   r0, [r1, #12]                 @ Store this so 'mem map' knows
+        str   r0, [r1, #16]                 @ Store this so 'mem map' knows
+
+        sub   r0, r0, #FIQ_STACK_SIZE       @ Subtract FIQ stack size for IRQ stack start
+        msr   CPSR_c, #MODE_IRQ|I_BIT|F_BIT @ IRQ Mode 
+        mov   sp, r0                        @ Set IRQ mode SP
+        str   r0, [r1, #20]                 @ Store this so 'mem map' knows
+        str   r0, [r1, #24]                 @ Store this so 'mem map' knows
+
+        sub   r0, r0, #IRQ_STACK_SIZE       @ Subtract IRQ stack size for SVC stack start
+        msr   CPSR_c, #MODE_SVC|I_BIT|F_BIT @ Supervisor Mode 
+        mov   sp, r0                        @ Set supervisor mode SP
+        str   r0, [r1, #28]                 @ Store this so 'mem map' knows
+        str   r0, [r1, #32]                 @ Store this so 'mem map' knows
+        sub   r2, r0, #256                  @ MAGIC! FreeRTOS only uses a few bytes of supervisor stack...
+        str   r2, [r1, #48]                 @ ...so tell _sbrk() where heap ends when FreeRTOS running
+
+        sub   r0, r0, #SVC_STACK_SIZE       @ Subtract supervisor stack size for system/user stack start
+        msr   CPSR_c, #MODE_SYS|I_BIT|F_BIT @ System Mode 
+        mov   sp, r0                        @ Set system/user mode SP
+        str   r0, [r1, #36]                 @ Store this so 'mem map' knows
+        str   r0, [r1, #40]                 @ Store this so 'mem map' knows
+
+@
+@  We want to start in supervisor mode (probably always, but FreeRTOS demands it)
+@
+        msr   CPSR_c, #MODE_SVC|I_BIT|F_BIT
+
+@
+@  Set argc & argv, initialize newlib, and jump to main
+@
+        mov     r0, #0                  @ No arguments  
+        mov     r1, #0                  @ No argv either 
+
+        bl      syscallsInit            @ Initialize ./newlib/syscalls.c
+        bl      main                    @ And call good ol' main()
+        b       .                       @ In case main() ever returns
+
+@
+@  Indirect words
+@
+        .align  0
+.LC1:   .word   __bss_beg__
+.LC2:   .word   __bss_end__
+.LC3:   .word   __data_beg__
+.LC4:   .word   __data_beg_src__
+.LC5:   .word   __data_end__
+.LC6:   .word   __stack_end__
+.LC7:   .word   __stack_beg_und
+
+@
+@  Setup vector table.  
+@
+.section .startup,"ax"
+         .code 32
+         .align 0
+
+        b       _start                  @ reset - _start               
+        ldr     pc, _undf               @ undefined - _undf            
+        ldr     pc, _swi                @ SWI - _swi                   
+        ldr     pc, _pabt               @ program abort - _pabt        
+        ldr     pc, _dabt               @ data abort - _dabt           
+        nop                             @ reserved                     
+        ldr     pc, [pc, #-0xff0]       @ IRQ - read the VIC           
+        ldr     pc, _fiq                @ FIQ - _fiq                   
+
+_undf:  .word   __undf                  @ undefined                    
+_swi:   .word   swiDispatch             @ SWI                          
+_pabt:  .word   __pabt                  @ program abort                
+_dabt:  .word   __dabt                  @ data abort                   
+_fiq:   .word   fiqISR                  @ FIQ                          
+
+@
+@  Handlers for undef, program abort and data abort.  They all update
+@  their respective registers, then reset the system by timing out
+@  the watchdog (only apparent way to force a hardware reset)
+@
+__undf: 
+        ldr     sp, =(__abort_mem+5*4)  @ Set sp_abt to data array with offset (restore later)
+        stmia   sp, {r0-r12}            @ Save first dataset in r0-r12 to array
+        sub     r0, lr, #4              @ Calculate PC value of undef instruction
+        mov     r1, #0                  @ Abort type
+        b       .abtstore               @ Save info, reset system
+
+__pabt: 
+        ldr     sp, =(__abort_mem+5*4)  @ Set sp_abt to data array with offset (restore later)
+        stmia   sp, {r0-r12}            @ Save first dataset in r0-r12 to array
+        sub     r0, lr, #4              @ Calculate PC value of undef instruction
+        mov     r1, #1                  @ Abort type
+        b       .abtstore               @ Save info, reset system
+
+__dabt: 
+        ldr     sp, =(__abort_mem+5*4)  @ Set sp_abt to data array with offset (restore later)
+        stmia   sp, {r0-r12}            @ Save first dataset in r0-r12 to array
+        sub     r0, lr, #8              @ Calculate PC value of undef instruction
+        mov     r1, #2                  @ Abort type
+        b       .abtstore               @ Save info, reset system
+
+@
+@  Store the abort type.  Then see if the sigil value is set, and if not,
+@  reset the abort counter to 0.
+@
+.abtstore:
+        ldr     r2, =__abort_typ        @ Abort type
+        str     r1, [r2]                @ Store it
+
+        ldr     r2, =__abort_sig        @ Get the sigil address
+        ldr     r4, =ABORT_SIGIL        @ Load sigil value
+        ldr     r3, [r2]                @ Get sigil contents
+        cmp     r3, r4                  @ Sigil set?
+
+        strne   r4, [r2]                @ No, store sigil value
+        ldrne   r2, =__abort_cnt        @ No, load address of abort counter
+        movne   r4, #0                  @ No, Zero for store
+        strne   r4, [r2]                @ No, Clear counter
+
+@
+@  Now build up structure of registers and stack (r0 = abort address, r1 = 
+@  abort type).  This code is based heavily on the work of Roger Lynx, from 
+@  http://www.embedded.com/shared/printableArticle.jhtml?articleID=192202641
+@
+        mrs     r5, cpsr                @ Save current mode to R5 for mode switching
+        mrs     r6, spsr                @ spsr_abt = CPSR of dabt originating mode, save to r6 for mode switching
+        mov     r2, r6                  @ Building second dataset: r2 = CPSR of exception
+        tst     r6, #0x0f               @ Test mode of the raised exception
+        orreq   r6, r6, #0x0f           @ If 0, elevate from user mode to system mode
+        msr     cpsr_c, r6              @ Switch out from mode 0x17 (abort) to ...
+        mov     r3, lr                  @ ... dabt generating mode and state
+        mov     r4, sp                  @ ... Get lr (=r3) and sp (=r4)
+        msr     cpsr_c, r5              @ Switch back to mode 0x17 (abort)
+        cmp     r1, #1                  @ Test for prefetch abort
+        moveq   r1, #0                  @ Can't fetch instruction at the abort address
+        ldrne   r1, [r0]                @ r1 = [pc] (dabt)
+        ldr     sp, =__abort_mem        @ Reset sp to arrays starting address
+        stmia   sp, {r0-r4}             @ Save second dataset from r0 to r4
+
+        ldr     r1, =__abort_stk        @ Space where we'll store abort stack
+        mov     r2,#8                   @ Copy 8 stack entries
+.abtcopy:
+        ldr     r0, [r4], #4            @ Get byte from source, r4 += 4
+        str     r0, [r1], #4            @ Store byte to destination, r1 += 4
+        subs    r2, r2, #1              @ Decrement loop counter
+        bgt     .abtcopy                @ >= 0, go again
+
+        b       .sysreset               @ And reset
+
+@
+@  Force a system reset with ye olde watch dogge
+@
+        .set    SCB_RSIR_MASK, 0x0000000f
+        .set    SCB_RSIR,      0xe01fc180
+        .set    WD_MOD,        0xe0000000
+        .set    WD_TC,         0xe0000004
+        .set    WD_FEED,       0xe0000008
+        .set    WD_MOD_WDEN,   0x00000001
+        .set    WD_MOD_RESET,  0x00000002
+        .set    WD_MOD_TOF,    0x00000004
+        .set    WD_MOD_INT,    0x00000008
+        .set    WD_MOD_MASK,   0x0000000f
+        .set    WD_FEED_FEED1, 0x000000aa
+        .set    WD_FEED_FEED2, 0x00000055
+        .set    ABORT_SIGIL,   0xdeadc0de
+
+.sysreset:
+        ldr     r1, =__abort_cnt        @ Get the abort counter address
+        ldr     r0, [r1]                @ Load it
+        add     r0, r0, #1              @ Add 1
+        str     r0, [r1]                @ Store it back
+
+@
+@  Now enable the watch dog, and go into a loop waiting for a timeout
+@
+        ldr     r0, =SCB_RSIR_MASK
+        ldr     r1, =SCB_RSIR
+        str     r0, [r1]
+        ldr     r0, =WD_MOD_WDEN | WD_MOD_RESET
+        ldr     r1, =WD_MOD
+        str     r0, [r1]
+        ldr     r0, =120000
+        ldr     r1, =WD_TC
+        str     r0, [r1]
+        ldr     r0, =WD_FEED_FEED1
+        ldr     r1, =WD_FEED
+        str     r0, [r1]
+        ldr     r0, =WD_FEED_FEED2
+        ldr     r1, =WD_FEED
+        str     r0, [r1]
+        b       .
+
+@
+@  These are in the .protected space in RAM to make sure that initialization 
+@  code doesn't overwrite them.  When a data abort or an undefined instruction
+@  exception occurs, the handlers update the respective locations below.  ORDER
+@  IS IMPORTANT, THESE ARE MAPPED INTO THE C STRUCTURE abortDat_t in monitor.c
+@
+        .global __abort_dat
+        .section .protected
+        .align  0
+
+__abort_dat:  .word 0                   @ Dummy, not used
+__abort_sig:  .word 0                   @ Sigil to indicate data validity
+__abort_cnt:  .word 0                   @ Number of times we've aborted
+__abort_typ:  .word 0                   @ Type of abort (0=undef,1=pabort,2=dabort)
+__abort_mem:  .space (18 * 4), 0        @ Registers from abort state
+__abort_stk:  .space (8 * 4), 0         @ 8 stack entries from abort state
+
+@
+@  Define globals so application can figure out what stacks are where.
+@  Keep these in order!  The stack setup code expects it.
+@
+        .global __stack_beg_und
+        .global __stack_end_und
+        .global __stack_beg_abt
+        .global __stack_end_abt
+        .global __stack_beg_fiq
+        .global __stack_end_fiq
+        .global __stack_beg_irq
+        .global __stack_end_irq
+        .global __stack_beg_svc
+        .global __stack_end_svc
+        .global __stack_beg_sys
+        .global __stack_end_sys
+        .global __heap_max
+        .global __heap_beg
+        .global __heap_end
+        .data
+        .align  0
+
+__stack_beg_und: .word 0                @ 0
+__stack_end_und: .word 0                @ 4
+__stack_beg_abt: .word 0                @ 8
+__stack_end_abt: .word 0                @ 12
+__stack_beg_fiq: .word 0                @ 16
+__stack_end_fiq: .word 0                @ 20
+__stack_beg_irq: .word 0                @ 24
+__stack_end_irq: .word 0                @ 28
+__stack_beg_svc: .word 0                @ 32
+__stack_end_svc: .word 0                @ 36
+__stack_beg_sys: .word 0                @ 40
+__stack_end_sys: .word 0                @ 44
+__heap_max:      .word 0                @ 48
+__heap_beg:      .word __heap_beg__
+__heap_end:      .word __heap_end__
+
+        .end
diff --git a/cpu/Makefile b/cpu/Makefile
new file mode 100644 (file)
index 0000000..98b90ca
--- /dev/null
@@ -0,0 +1,25 @@
+SRC_FILES=cpu.c
+
+#
+# Define all object files.
+#
+ARM_OBJ = $(SRC_FILES:.c=.o)
+
+.PHONY: all
+all: $(ARM_OBJ)
+
+$(ARM_OBJ) : %.o : %.c Makefile .depend
+       $(CC) -c $(CFLAGS) $< -o $@
+       $(AR) r $(COMMON)/common.a $@
+
+#
+#  The .depend files contains the list of header files that the
+#  various source files depend on.  By doing this, we'll only
+#  rebuild the .o's that are affected by header files changing.
+#
+.depend:
+                       $(CC) $(CFLAGS) -M $(SRC_FILES) > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff --git a/cpu/cpu.c b/cpu/cpu.c
new file mode 100644 (file)
index 0000000..fc2d51f
--- /dev/null
+++ b/cpu/cpu.c
@@ -0,0 +1,132 @@
+#include "FreeRTOS.h"
+#include "cpu/cpu.h"
+
+//
+//  Olimex board specific.  LEDs are on P0.10, P0.11
+//
+#define partstFIRST_IO                   ((unsigned portLONG) 0x400)
+#define partstNUM_LEDS                   (2)
+#define partstALL_OUTPUTS_OFF  ((unsigned portLONG) 0xffffffff)
+
+//
+//
+//
+void cpuSetupHardware (void)
+{
+#ifdef RUN_FROM_RAM
+  //
+  //  Remap the interrupt vectors to RAM if we are are running from RAM
+  //
+  SCB_MEMMAP = SCB_MEMMAP_URM;
+#endif
+
+  //
+  //  Configure the RS2332 pins.  All other pins remain at their default of 0
+  //
+  PCB_PINSEL0 |= (PCB_PINSEL0_P00_TXD0 | PCB_PINSEL0_P01_RXD0 | PCB_PINSEL0_P08_TXD1 | PCB_PINSEL0_P09_RXD1);
+
+  //
+  //  Set all GPIO to output other than the P0.14 (BSL), and the JTAG pins.  
+  //  The JTAG pins are left as input as I'm not sure what will happen if the 
+  //  Wiggler is connected after powerup - not that it would be a good idea to
+  //  do that anyway.
+  //
+  GPIO0_IODIR = ~(GPIO_IO_P14 | GPIO_IO_P15 | GPIO_IO_P15);
+  GPIO1_IODIR = ~GPIO_IO_JTAG;
+
+  //
+  //  Setup the PLL to multiply the 12Mhz XTAL input by 4, divide by 1
+  //
+  SCB_PLLCFG = (SCB_PLLCFG_MUL4 | SCB_PLLCFG_DIV1);
+
+  //
+  //  Activate the PLL by turning it on then feeding the correct sequence of bytes
+  //
+  SCB_PLLCON  = SCB_PLLCON_PLLE;
+  SCB_PLLFEED = SCB_PLLFEED_FEED1;
+  SCB_PLLFEED = SCB_PLLFEED_FEED2;
+
+  //
+  //  Wait for the PLL to lock...
+  //
+  while (!(SCB_PLLSTAT & SCB_PLLSTAT_PLOCK))
+    ;
+
+  //
+  //  ...before connecting it using the feed sequence again
+  //
+  SCB_PLLCON  = SCB_PLLCON_PLLC | SCB_PLLCON_PLLE;
+  SCB_PLLFEED = SCB_PLLFEED_FEED1;
+  SCB_PLLFEED = SCB_PLLFEED_FEED2;
+
+  //
+  //  Setup and turn on the MAM.  Three cycle access is used due to the fast
+  //  PLL used.  It is possible faster overall performance could be obtained by
+  //  tuning the MAM and PLL settings.
+  //
+  MAM_TIM = MAM_TIM_3;
+  MAM_CR = MAM_CR_FULL;
+
+  //
+  //  Setup the peripheral bus to be the same as the PLL output (48Mhz)
+  //
+  SCB_VPBDIV = SCB_VPBDIV_100;
+
+  //
+  //  Disable power to all modules
+  //
+  SCB_PCONP = 0x0000;
+
+  //
+  //
+  //
+  cpuGPIOInitialize ();
+}
+
+//
+//
+//
+void cpuPLLDisable (void)
+{
+  SCB_PLLCON  = 0;
+  SCB_PLLFEED = SCB_PLLFEED_FEED1;
+  SCB_PLLFEED = SCB_PLLFEED_FEED2;
+  SCB_PLLCFG =  0;
+}
+
+//
+//
+//
+void cpuT1Disable (void)
+{
+  T1_TCR = 0;
+  T1_PR = 0;
+  T1_MCR = 0;
+  T1_CCR = 0;
+  T1_EMR = 0;
+  T1_CTCR = 0;
+  T1_IR = 0;
+}
+
+//
+//
+//
+void cpuGPIOInitialize (void)
+{
+       GPIO0_IOSET = partstALL_OUTPUTS_OFF;
+}
+
+void cpuToggleLED (unsigned portBASE_TYPE uxLED)
+{
+  unsigned portLONG ulLED = partstFIRST_IO;
+
+  if (uxLED < partstNUM_LEDS)
+  {
+    ulLED <<= (unsigned portLONG) uxLED;
+
+    if (GPIO0_IOPIN & ulLED)
+      GPIO0_IOCLR = ulLED;
+    else
+      GPIO0_IOSET = ulLED;                     
+  }    
+}
diff --git a/cpu/cpu.h b/cpu/cpu.h
new file mode 100644 (file)
index 0000000..ff086b0
--- /dev/null
+++ b/cpu/cpu.h
@@ -0,0 +1,10 @@
+#ifndef _CPU_H_
+#define _CPU_H_
+
+void cpuSetupHardware (void);
+void cpuPLLDisable (void);
+void cpuT1Disable (void);
+void cpuGPIOInitialize (void);
+void cpuToggleLED (unsigned portBASE_TYPE uxLED);
+
+#endif
diff --git a/dac/Makefile b/dac/Makefile
new file mode 100644 (file)
index 0000000..b41b0cc
--- /dev/null
@@ -0,0 +1,25 @@
+SRC_FILES=dac.c
+
+#
+# Define all object files.
+#
+ARM_OBJ = $(SRC_FILES:.c=.o)
+
+.PHONY: all
+all: $(ARM_OBJ)
+
+$(ARM_OBJ) : %.o : %.c Makefile .depend
+       $(CC) -c $(CFLAGS) $< -o $@
+       $(AR) r $(COMMON)/common.a $@
+
+#
+#  The .depend files contains the list of header files that the
+#  various source files depend on.  By doing this, we'll only
+#  rebuild the .o's that are affected by header files changing.
+#
+.depend:
+                       $(CC) $(CFLAGS) -M $(SRC_FILES) > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff --git a/dac/dac.c b/dac/dac.c
new file mode 100644 (file)
index 0000000..f981624
--- /dev/null
+++ b/dac/dac.c
@@ -0,0 +1,26 @@
+#include "FreeRTOS.h"
+
+#include "dac.h"
+
+//
+//
+//
+void dacInit (void)
+{
+  PCB_PINSEL1 |= PCB_PINSEL1_P025_AOUT;
+
+  DAC_CR = 0;
+}
+
+unsigned int dacSet (unsigned int newValue)
+{
+  unsigned int dacCR;
+  unsigned int dacCurrentValue;
+
+  dacCR = DAC_CR;
+  dacCurrentValue = (dacCR & DAC_CR_VALUEMASK) >> DAC_CR_VALUESHIFT;
+  dacCR = (dacCR & ~DAC_CR_VALUEMASK) | ((newValue << DAC_CR_VALUESHIFT) & DAC_CR_VALUEMASK);
+  DAC_CR = dacCR;
+
+  return dacCurrentValue;
+}
diff --git a/dac/dac.h b/dac/dac.h
new file mode 100644 (file)
index 0000000..cd91a9d
--- /dev/null
+++ b/dac/dac.h
@@ -0,0 +1,7 @@
+#ifndef _DAC_H_
+#define _DAC_H_
+
+void dacInit (void);
+unsigned int dacSet (unsigned int newValue);
+
+#endif
diff --git a/eints/Makefile b/eints/Makefile
new file mode 100644 (file)
index 0000000..d9c4aae
--- /dev/null
@@ -0,0 +1,25 @@
+SRC_FILES=eints.c eintsISR.c
+
+#
+# Define all object files.
+#
+ARM_OBJ = $(SRC_FILES:.c=.o)
+
+.PHONY: all
+all: $(ARM_OBJ)
+
+$(ARM_OBJ) : %.o : %.c Makefile .depend
+       $(CC) -c $(CFLAGS) $< -o $@
+       $(AR) r $(COMMON)/common.a $@
+
+#
+#  The .depend files contains the list of header files that the
+#  various source files depend on.  By doing this, we'll only
+#  rebuild the .o's that are affected by header files changing.
+#
+.depend:
+                       $(CC) $(CFLAGS) -M $(SRC_FILES) > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff --git a/eints/eints.c b/eints/eints.c
new file mode 100644 (file)
index 0000000..85f9b8e
--- /dev/null
@@ -0,0 +1,30 @@
+#include "FreeRTOS.h"
+#include "task.h"
+#include "queue.h"
+
+#include "eints.h"
+#include "eintsISR.h"
+
+//
+//
+//
+void eintsInit (void)
+{
+  portENTER_CRITICAL ();
+
+  PCB_PINSEL1 |= PCB_PINSEL1_P016_EINT0;
+  PCB_PINSEL0 |= PCB_PINSEL0_P015_EINT2;
+
+  SCB_EXTPOLAR &= ~(SCB_EXTPOLAR_EINT0 | SCB_EXTPOLAR_EINT2);
+  SCB_EXTMODE  |=  (SCB_EXTMODE_EINT0  | SCB_EXTMODE_EINT2);
+  SCB_EXTINT   |=  (SCB_EXTINT_EINT0   | SCB_EXTINT_EINT2);
+
+  VIC_IntSelect &= ~(VIC_IntSelect_EINT0 | VIC_IntSelect_EINT2);
+  VIC_VectAddr4 = (portLONG) eintsISR_EINT0;
+  VIC_VectCntl4 = VIC_VectCntl_ENABLE | VIC_Channel_EINT0;
+  VIC_VectAddr5 = (portLONG) eintsISR_EINT2;
+  VIC_VectCntl5 = VIC_VectCntl_ENABLE | VIC_Channel_EINT2;
+  VIC_IntEnable = VIC_IntEnable_EINT0 | VIC_IntEnable_EINT2;
+
+  portEXIT_CRITICAL ();
+}
diff --git a/eints/eints.h b/eints/eints.h
new file mode 100644 (file)
index 0000000..649699c
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef _EINTS_H_
+#define _EINTS_H_
+
+void eintsInit (void);
+
+#endif
diff --git a/eints/eintsISR.c b/eints/eintsISR.c
new file mode 100644 (file)
index 0000000..e801d58
--- /dev/null
@@ -0,0 +1,42 @@
+//
+//
+//
+#include "FreeRTOS.h"
+#include "task.h"
+
+#include "eintsISR.h"
+
+//
+//
+//
+void eintsISR_EINT0 (void) __attribute__ ((naked));
+void eintsISR_EINT2 (void) __attribute__ ((naked));
+
+//
+//
+//
+void eintsISR_EINT0 (void)
+{
+       portENTER_SWITCHING_ISR ();
+
+  SCB_EXTINT |= SCB_EXTINT_EINT0;
+
+  GPIO0_IOSET = GPIO_IO_P11;
+
+       VIC_VectAddr = (unsigned portLONG) 0;
+
+       portEXIT_SWITCHING_ISR (0);
+}
+
+void eintsISR_EINT2 (void)
+{
+       portENTER_SWITCHING_ISR ();
+
+  SCB_EXTINT |= SCB_EXTINT_EINT1;
+
+  GPIO0_IOCLR = GPIO_IO_P11;
+
+       VIC_VectAddr = (unsigned portLONG) 0;
+
+       portEXIT_SWITCHING_ISR (0);
+}
diff --git a/eints/eintsISR.h b/eints/eintsISR.h
new file mode 100644 (file)
index 0000000..fdfbed1
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef _EINTSISR_H_
+#define _EINTSISR_H_
+
+void eintsISR_EINT0 (void);
+void eintsISR_EINT2 (void);
+
+#endif
diff --git a/fatfs/Makefile b/fatfs/Makefile
new file mode 100644 (file)
index 0000000..2a5432e
--- /dev/null
@@ -0,0 +1,25 @@
+SRC_FILES=ff.c mmc.c spi.c
+
+#
+# Define all object files.
+#
+ARM_OBJ = $(SRC_FILES:.c=.o)
+
+.PHONY: all
+all: $(ARM_OBJ)
+
+$(ARM_OBJ) : %.o : %.c Makefile .depend
+       $(CC) -c $(CFLAGS) $< -o $@
+       $(AR) r $(COMMON)/common.a $@
+
+#
+#  The .depend files contains the list of header files that the
+#  various source files depend on.  By doing this, we'll only
+#  rebuild the .o's that are affected by header files changing.
+#
+.depend:
+                       $(CC) $(CFLAGS) -M $(SRC_FILES) > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff --git a/fatfs/disk.h b/fatfs/disk.h
new file mode 100644 (file)
index 0000000..013ef6b
--- /dev/null
@@ -0,0 +1,73 @@
+/*************************************************************************
+ *
+ *    Used with ICCARM and AARM.
+ *
+ *    (c) Copyright IAR Systems 2005
+ *
+ *    File name   : disk.h
+ *    Description : Disk common definitions module
+ *
+ *    History :
+ *    1. Data        : November 15, 2005
+ *       Author      : Stanimir Bonev
+ *       Description : Create
+ *
+ *    $Revision: 1.4 $
+**************************************************************************/
+#ifndef _DISK_H_
+#define _DISK_H_
+
+#include "sysdefs.h"
+
+typedef enum
+{
+  DiskCommandPass = 0, 
+  DiskNotReady, 
+  DiskNotPresent,
+  DiskParametersError, 
+  DiskMiscompareError, 
+  DiskChanged,
+  DiskUknowError,
+} 
+DiskStatusCode_t;
+
+typedef enum
+{
+  DiskWrite = 0, 
+  DiskRead, 
+  DiskVerify,
+} 
+DiskIoRequest_t;
+
+typedef enum
+{
+  DiskInquiry = 0, 
+  DiskFormatCapacity,
+} 
+DiskInfoType_t;
+
+typedef enum
+{
+  DiskMMC, 
+  DiskSD, 
+  DiskUnknow,
+} 
+DiskType_t;
+
+typedef struct
+{
+  U32  BlockNumb;
+  U32  BlockSize;
+  DiskStatusCode_t DiskStatus;
+  DiskType_t DiskType;
+  BOOL WriteProtect;
+  BOOL MediaChanged;
+} 
+/* __attribute__ ((packed)) */ DiskStatus_t, *pDiskStatus_t;
+
+typedef void             (* DiskInitFpnt_t) (void);
+typedef U32              (* DiskInfoFpnt_t) (U8 *, DiskInfoType_t);
+typedef pDiskStatus_t    (* DiskStatusFpnt_t) (void);
+typedef DiskStatusCode_t (* DiskIoFpnt_t) (U8 *, U32, U32, DiskIoRequest_t);
+
+#endif
diff --git a/fatfs/diskio.h b/fatfs/diskio.h
new file mode 100644 (file)
index 0000000..610a4e2
--- /dev/null
@@ -0,0 +1,61 @@
+/*-----------------------------------------------------------------------
+/  Low level disk interface modlue include file  R0.04a   (C)ChaN, 2007
+/-----------------------------------------------------------------------*/
+
+#ifndef _DISKIO_H_
+#define _DISKIO_H_
+
+//
+//  Status of Disk Functions 
+//
+typedef U8 DSTATUS;
+
+//
+//  Results of Disk Functions 
+//
+typedef enum 
+{
+       RES_OK = 0,             /* 0: Successful */
+       RES_ERROR,              /* 1: R/W Error */
+       RES_WRPRT,              /* 2: Write Protected */
+       RES_NOTRDY,             /* 3: Not Ready */
+       RES_PARERR              /* 4: Invalid Parameter */
+} 
+DRESULT;
+
+//
+//  Disk Status Bits (DSTATUS)
+//
+#define STA_NOINIT             0x01    /* Drive not initialized */
+#define STA_NODISK             0x02    /* No medium in the drive */
+#define STA_PROTECT            0x04    /* Write protected */
+
+//
+//  Command code for disk_ioctl() 
+//
+#define GET_SECTOR_COUNT       1
+#define GET_SECTOR_SIZE                2
+#define CTRL_SYNC                          3
+#define CTRL_POWER                       4
+#define CTRL_LOCK                          5
+#define CTRL_EJECT                       6
+#define MMC_GET_CSD                     10
+#define MMC_GET_CID                     11
+#define MMC_GET_OCR                     12
+#define ATA_GET_REV                     20
+#define ATA_GET_MODEL           21
+#define ATA_GET_SN                      22
+
+//
+//
+//
+DSTATUS diskInitialize (U8);
+DSTATUS diskShutdown (void);
+DSTATUS diskStatus (U8);
+DRESULT diskRead (U8, U8 *, U32, U8);
+#if _FS_READONLY == 0
+DRESULT diskWrite (U8, const U8 *, U32, U8);
+#endif
+DRESULT diskIoctl (U8, U8, void *);
+
+#endif
diff --git a/fatfs/ff.c b/fatfs/ff.c
new file mode 100644 (file)
index 0000000..9d98d53
--- /dev/null
@@ -0,0 +1,1841 @@
+/*--------------------------------------------------------------------------/
+  /  FatFs - FAT file system module  R0.04b                    (C)ChaN, 2007
+  /---------------------------------------------------------------------------/
+  / The FatFs module is an experimenal project to implement FAT file system to
+  / cheap microcontrollers. This is a free software and is opened for education,
+  / research and development under license policy of following trems.
+  /
+  /  Copyright (C) 2007, ChaN, all right reserved.
+  /
+  / * The FatFs module is a free software and there is no warranty.
+  / * You can use, modify and/or redistribute it for personal, non-profit or
+  /   profit use without any restriction under your responsibility.
+  / * Redistributions of source code must retain the above copyright notice.
+  /
+  /---------------------------------------------------------------------------/
+  /  Feb 26, 2006  R0.00  Prototype.
+  /  Apr 29, 2006  R0.01  First stable version.
+  /  Jun 01, 2006  R0.02  Added FAT12 support.
+  /                       Removed unbuffered mode.
+  /                       Fixed a problem on small (<32M) patition.
+  /  Jun 10, 2006  R0.02a Added a configuration option (_FS_MINIMUM).
+  /  Sep 22, 2006  R0.03  Added f_rename().
+  /                       Changed option _FS_MINIMUM to _FS_MINIMIZE.
+  /  Dec 11, 2006  R0.03a Improved cluster scan algolithm to write files fast.
+  /                       Fixed f_mkdir() creates incorrect directory on FAT32.
+  /  Feb 04, 2007  R0.04  Supported multiple drive system.
+  /                       Changed some interfaces for multiple drive system.
+  /                       Changed f_mountdrv() to f_mount().
+  /                       Added f_mkfs().
+  /  Apr 01, 2007  R0.04a Supported multiple partitions on a plysical drive.
+  /                       Added a capability of extending file size to f_lseek().
+  /                       Added minimization level 3.
+  /                       Fixed an endian sensitive code in f_mkfs().
+  /  May 05, 2007  R0.04b Added a configuration option _USE_NTFLAG.
+  /                       Added FSInfo support.
+  /                       Fixed DBCS name can result FR_INVALID_NAME.
+  /                       Fixed short seek (<= csize) collapses the file object.
+  /---------------------------------------------------------------------------*/
+#include <stdio.h> // ###
+#include <string.h>
+#include "ff.h"                        /* FatFs declarations */
+#include "diskio.h"            /* Include file for user provided disk functions */
+
+
+/*--------------------------------------------------------------------------
+
+  Module Private Functions
+
+  ---------------------------------------------------------------------------*/
+
+static FATFS *FatFs[_DRIVES];  /* Pointer to the file system objects (logical drives) */
+static U16 fsid;                               /* File system mount ID */
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Change window offset                                                  */
+/*-----------------------------------------------------------------------*/
+
+static
+BOOL move_window (             /* TRUE: successful, FALSE: failed */
+    FATFS *fs,                 /* File system object */
+    U32 sector         /* Sector number to make apperance in the fs->win[] */
+    )                                          /* Move to zero only writes back dirty window */
+{
+  U32 wsect;
+
+
+  wsect = fs->winsect;
+  if (wsect != sector) {       /* Changed current window */
+#if _FS_READONLY == 0
+    U8 n;
+    if (fs->winflag) { /* Write back dirty window if needed */
+      if (diskWrite(fs->drive, fs->win, wsect, 1) != RES_OK)
+        return FALSE;
+      fs->winflag = 0;
+      if (wsect < (fs->fatbase + fs->sects_fat)) {     /* In FAT area */
+        for (n = fs->n_fats; n >= 2; n--) {    /* Refrect the change to FAT copy */
+          wsect += fs->sects_fat;
+          diskWrite(fs->drive, fs->win, wsect, 1);
+        }
+      }
+    }
+#endif
+    if (sector) {
+      if (diskRead(fs->drive, fs->win, sector, 1) != RES_OK)
+        return FALSE;
+      fs->winsect = sector;
+    }
+  }
+  return TRUE;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Clean-up cached data                                                  */
+/*-----------------------------------------------------------------------*/
+
+#if _FS_READONLY == 0
+static
+FRESULT sync (                 /* FR_OK: successful, FR_RW_ERROR: failed */
+    FATFS *fs                  /* File system object */
+    )
+{
+  fs->winflag = 1;
+  if (!move_window(fs, 0)) return FR_RW_ERROR;
+#if _USE_FSINFO
+  if (fs->fs_type == FS_FAT32 && fs->fsi_flag) {               /* Update FSInfo sector if needed */
+    fs->winsect = 0;
+    memset(fs->win, 0, 512);
+    ST_U16(&fs->win[BS_55AA], 0xAA55);
+    ST_U32(&fs->win[FSI_LeadSig], 0x41615252);
+    ST_U32(&fs->win[FSI_StrucSig], 0x61417272);
+    ST_U32(&fs->win[FSI_Free_Count], fs->free_clust);
+    ST_U32(&fs->win[FSI_Nxt_Free], fs->last_clust);
+    diskWrite(0, fs->win, fs->fsi_sector, 1);
+    fs->fsi_flag = 0;
+  }
+#endif
+  if (diskIoctl(fs->drive, CTRL_SYNC, NULL) != RES_OK) return FR_RW_ERROR;
+  return FR_OK;
+}
+#endif
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Get a cluster status                                                  */
+/*-----------------------------------------------------------------------*/
+
+static
+U32 get_cluster (              /* 0,>=2: successful, 1: failed */
+    FATFS *fs,                 /* File system object */
+    U32 clust                  /* Cluster# to get the link information */
+    )
+{
+  U16 wc, bc;
+  U32 fatsect;
+
+
+  if (clust >= 2 && clust < fs->max_clust) {           /* Valid cluster# */
+    fatsect = fs->fatbase;
+    switch (fs->fs_type) {
+      case FS_FAT12 :
+        bc = (U16)clust * 3 / 2;
+        if (!move_window(fs, fatsect + (bc / S_SIZ))) break;
+        wc = fs->win[bc & (S_SIZ - 1)]; bc++;
+        if (!move_window(fs, fatsect + (bc / S_SIZ))) break;
+        wc |= (U16)fs->win[bc & (S_SIZ - 1)] << 8;
+        return (clust & 1) ? (wc >> 4) : (wc & 0xFFF);
+
+      case FS_FAT16 :
+        if (!move_window(fs, fatsect + (clust / (S_SIZ / 2)))) break;
+        return LD_U16(&fs->win[((U16)clust * 2) & (S_SIZ - 1)]);
+
+      case FS_FAT32 :
+        if (!move_window(fs, fatsect + (clust / (S_SIZ / 4)))) break;
+        return LD_U32(&fs->win[((U16)clust * 4) & (S_SIZ - 1)]) & 0x0FFFFFFF;
+    }
+  }
+
+  return 1;    /* There is no cluster information, or an error occured */
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Change a cluster status                                               */
+/*-----------------------------------------------------------------------*/
+
+#if _FS_READONLY == 0
+static
+BOOL put_cluster (             /* TRUE: successful, FALSE: failed */
+    FATFS *fs,                 /* File system object */
+    U32 clust,         /* Cluster# to change */
+    U32 val                    /* New value to mark the cluster */
+    )
+{
+  U16 bc;
+  U8 *p;
+  U32 fatsect;
+
+
+  fatsect = fs->fatbase;
+  switch (fs->fs_type) {
+    case FS_FAT12 :
+      bc = (U16)clust * 3 / 2;
+      if (!move_window(fs, fatsect + (bc / S_SIZ))) return FALSE;
+      p = &fs->win[bc & (S_SIZ - 1)];
+      *p = (clust & 1) ? ((*p & 0x0F) | ((U8)val << 4)) : (U8)val;
+      bc++;
+      fs->winflag = 1; 
+      if (!move_window(fs, fatsect + (bc / S_SIZ))) return FALSE;
+      p = &fs->win[bc & (S_SIZ - 1)];
+      *p = (clust & 1) ? (U8)(val >> 4) : ((*p & 0xF0) | ((U8)(val >> 8) & 0x0F));
+      break;
+
+    case FS_FAT16 :
+      if (!move_window(fs, fatsect + (clust / (S_SIZ / 2)))) return FALSE;
+      ST_U16(&fs->win[((U16)clust * 2) & (S_SIZ - 1)], (U16)val);
+      break;
+
+    case FS_FAT32 :
+      if (!move_window(fs, fatsect + (clust / (S_SIZ / 4)))) return FALSE;
+      ST_U32(&fs->win[((U16)clust * 4) & (S_SIZ - 1)], val);
+      break;
+
+    default :
+      return FALSE;
+  }
+  fs->winflag = 1;
+  return TRUE;
+}
+#endif /* !_FS_READONLY */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Remove a cluster chain                                                */
+/*-----------------------------------------------------------------------*/
+
+#if _FS_READONLY == 0
+static
+BOOL remove_chain (            /* TRUE: successful, FALSE: failed */
+    FATFS *fs,                 /* File system object */
+    U32 clust                  /* Cluster# to remove chain from */
+    )
+{
+  U32 nxt;
+
+
+  while (clust >= 2 && clust < fs->max_clust) {
+    nxt = get_cluster(fs, clust);
+    if (nxt == 1) return FALSE;
+    if (!put_cluster(fs, clust, 0)) return FALSE;
+    if (fs->free_clust != 0xFFFFFFFF) {
+      fs->free_clust++;
+#if _USE_FSINFO
+      fs->fsi_flag = 1;
+#endif
+    }
+    clust = nxt;
+  }
+  return TRUE;
+}
+#endif
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Stretch or create a cluster chain                                     */
+/*-----------------------------------------------------------------------*/
+
+#if _FS_READONLY == 0
+static
+U32 create_chain (     /* 0: no free cluster, 1: error, >=2: new cluster number */
+    FATFS *fs,                 /* File system object */
+    U32 clust                  /* Cluster# to stretch, 0 means create new */
+    )
+{
+  U32 cstat, ncl, scl, mcl = fs->max_clust;
+
+
+  if (clust == 0) {            /* Create new chain */
+    scl = fs->last_clust;                      /* Get suggested start point */
+    if (scl == 0 || scl >= mcl) scl = 1;
+  }
+  else {                                       /* Stretch existing chain */
+    cstat = get_cluster(fs, clust);    /* Check the cluster status */
+    if (cstat < 2) return 1;           /* It is an invalid cluster */
+    if (cstat < mcl) return cstat;     /* It is already followed by next cluster */
+    scl = clust;
+  }
+
+  ncl = scl;                           /* Start cluster */
+  for (;;) {
+    ncl++;                                                     /* Next cluster */
+    if (ncl >= mcl) {                          /* Wrap around */
+      ncl = 2;
+      if (ncl > scl) return 0; /* No free custer */
+    }
+    cstat = get_cluster(fs, ncl);      /* Get the cluster status */
+    if (cstat == 0) break;                     /* Found a free cluster */
+    if (cstat == 1) return 1;          /* Any error occured */
+    if (ncl == scl) return 0;          /* No free custer */
+  }
+
+  if (!put_cluster(fs, ncl, 0x0FFFFFFF)) return 1;             /* Mark the new cluster "in use" */
+  if (clust && !put_cluster(fs, clust, ncl)) return 1; /* Link it to previous one if needed */
+
+  fs->last_clust = ncl;                                /* Update fsinfo */
+  if (fs->free_clust != 0xFFFFFFFF) {
+    fs->free_clust--;
+#if _USE_FSINFO
+    fs->fsi_flag = 1;
+#endif
+  }
+
+  return ncl;          /* Return new cluster number */
+}
+#endif /* !_FS_READONLY */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Get sector# from cluster#                                             */
+/*-----------------------------------------------------------------------*/
+
+static
+U32 clust2sect (       /* !=0: sector number, 0: failed - invalid cluster# */
+    FATFS *fs,         /* File system object */
+    U32 clust          /* Cluster# to be converted */
+    )
+{
+  clust -= 2;
+  if (clust >= (fs->max_clust - 2)) return 0;          /* Invalid cluster# */
+  return clust * fs->sects_clust + fs->database;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Move directory pointer to next                                        */
+/*-----------------------------------------------------------------------*/
+
+static
+BOOL next_dir_entry (  /* TRUE: successful, FALSE: could not move next */
+    DIR *dirobj                        /* Pointer to directory object */
+    )
+{
+  U32 clust;
+  U16 idx;
+  FATFS *fs = dirobj->fs;
+
+
+  idx = dirobj->index + 1;
+  if ((idx & ((S_SIZ - 1) / 32)) == 0) {               /* Table sector changed? */
+    dirobj->sect++;                    /* Next sector */
+    if (!dirobj->clust) {              /* In static table */
+      if (idx >= fs->n_rootdir) return FALSE;  /* Reached to end of table */
+    } else {                                   /* In dynamic table */
+      if (((idx / (S_SIZ / 32)) & (fs->sects_clust - 1)) == 0) {       /* Cluster changed? */
+        clust = get_cluster(fs, dirobj->clust);                /* Get next cluster */
+        if (clust < 2 || clust >= fs->max_clust)       /* Reached to end of table */
+          return FALSE;
+        dirobj->clust = clust;                         /* Initialize for new cluster */
+        dirobj->sect = clust2sect(fs, clust);
+      }
+    }
+  }
+  dirobj->index = idx; /* Lower 4 bit of dirobj->index indicates offset in dirobj->sect */
+  return TRUE;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Get file status from directory entry                                  */
+/*-----------------------------------------------------------------------*/
+
+#if _FS_MINIMIZE <= 1
+static
+void get_fileinfo (            /* No return code */
+    FILINFO *finfo,    /* Ptr to store the file information */
+    const U8 *dir              /* Ptr to the directory entry */
+    )
+{
+  U8 n, c, a;
+  char *p;
+
+
+  p = &finfo->fname[0];
+  a = _USE_NTFLAG ? dir[DIR_NTres] : 0;                /* NT flag */
+  for (n = 0; n < 8; n++) {    /* Convert file name (body) */
+    c = dir[n];
+    if (c == ' ') break;
+    if (c == 0x05) c = 0xE5;
+    if (a & 0x08 && c >= 'A' && c <= 'Z') c += 0x20;
+    *p++ = c;
+  }
+  if (dir[8] != ' ') {         /* Convert file name (extension) */
+    *p++ = '.';
+    for (n = 8; n < 11; n++) {
+      c = dir[n];
+      if (c == ' ') break;
+      if (a & 0x10 && c >= 'A' && c <= 'Z') c += 0x20;
+      *p++ = c;
+    }
+  }
+  *p = '\0';
+
+  finfo->fattrib = dir[DIR_Attr];                                      /* Attribute */
+  finfo->fsize = LD_U32(&dir[DIR_FileSize]);   /* Size */
+  finfo->fdate = LD_U16(&dir[DIR_WrtDate]);            /* Date */
+  finfo->ftime = LD_U16(&dir[DIR_WrtTime]);            /* Time */
+}
+#endif /* _FS_MINIMIZE <= 1 */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Pick a paragraph and create the name in format of directory entry     */
+/*-----------------------------------------------------------------------*/
+
+static
+char make_dirfile (                    /* 1: error - detected an invalid format, '\0'or'/': next character */
+    const char **path,         /* Pointer to the file path pointer */
+    char *dirname                      /* Pointer to directory name buffer {Name(8), Ext(3), NT flag(1)} */
+    )
+{
+  U8 n, t, c, a, b;
+
+  memset(dirname, ' ', 8+3);   /* Fill buffer with spaces */
+  a = 0; b = 0x18;             /* NT flag */
+  n = 0; t = 8;
+
+  for (;;) {
+
+    c = *(*path)++;
+
+    if (c == '\0' || c == '/') {               /* Reached to end of str or directory separator */
+      if (n == 0) break;
+      dirname[11] = _USE_NTFLAG ? (a & b) : 0;
+      return c;
+    }
+    if (c <= ' ' || c == 0x7F) break;          /* Reject invisible chars */
+    if (c == '.') {
+      if (!(a & 1) && n >= 1 && n <= 8) {      /* Enter extension part */
+        n = 8; t = 11; continue;
+      }
+      break;
+    }
+    if (_USE_SJIS &&
+        ((c >= 0x81 && c <= 0x9F) ||   /* Accept S-JIS code */
+         (c >= 0xE0 && c <= 0xFC))) {
+      if (n == 0 && c == 0xE5)         /* Change heading \xE5 to \x05 */
+        c = 0x05;
+      a ^= 1; goto md_l2;
+    }
+    if (c == '"') break;                               /* Reject " */
+    if (c <= ')') goto md_l1;                  /* Accept ! # $ % & ' ( ) */
+    if (c <= ',') break;                               /* Reject * + , */
+    if (c <= '9') goto md_l1;                  /* Accept - 0-9 */
+    if (c <= '?') break;                               /* Reject : ; < = > ? */
+    if (!(a & 1)) {    /* These checks are not applied to S-JIS 2nd byte */
+      if (c == '|') break;                     /* Reject | */
+      if (c >= '[' && c <= ']') break;/* Reject [ \ ] */
+      if (_USE_NTFLAG && c >= 'A' && c <= 'Z')
+        (t == 8) ? (b &= ~0x08) : (b &= ~0x10);
+      if (c >= 'a' && c <= 'z') {              /* Convert to upper case */
+        c -= 0x20;
+        if (_USE_NTFLAG) (t == 8) ? (a |= 0x08) : (a |= 0x10);
+      }
+    }
+md_l1:
+    a &= ~1;
+md_l2:
+    if (n >= t) break;
+    dirname[n++] = c;
+  }
+  return 1;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Trace a file path                                                     */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT trace_path (   /* FR_OK(0): successful, !=0: error code */
+    DIR *dirobj,               /* Pointer to directory object to return last directory */
+    char *fn,                  /* Pointer to last segment name to return {file(8),ext(3),attr(1)} */
+    const char *path,  /* Full-path string to trace a file or directory */
+    U8 **dir                   /* Directory pointer in Win[] to retutn */
+    )
+{
+  U32 clust;
+  char ds;
+  U8 *dptr = NULL;
+  FATFS *fs = dirobj->fs;      /* Get logical drive from the given DIR structure */
+
+
+  /* Initialize directory object */
+  clust = fs->dirbase;
+  if (fs->fs_type == FS_FAT32) {
+    dirobj->clust = dirobj->sclust = clust;
+    dirobj->sect = clust2sect(fs, clust);
+  } else {
+    dirobj->clust = dirobj->sclust = 0;
+    dirobj->sect = clust;
+  }
+  dirobj->index = 0;
+
+  if (*path == '\0') {                                 /* Null path means the root directory */
+    *dir = NULL; return FR_OK;
+  }
+
+  for (;;) {
+    ds = make_dirfile(&path, fn);                      /* Get a paragraph into fn[] */
+    if (ds == 1) return FR_INVALID_NAME;
+    for (;;) {
+      if (!move_window(fs, dirobj->sect)) return FR_RW_ERROR;
+      dptr = &fs->win[(dirobj->index & ((S_SIZ - 1) / 32)) * 32];      /* Pointer to the directory entry */
+      if (dptr[DIR_Name] == 0)                                         /* Has it reached to end of dir? */
+        return !ds ? FR_NO_FILE : FR_NO_PATH;
+      if (dptr[DIR_Name] != 0xE5                                               /* Matched? */
+          && !(dptr[DIR_Attr] & AM_VOL)
+          && !memcmp(&dptr[DIR_Name], fn, 8+3) ) break;
+      if (!next_dir_entry(dirobj))                                     /* Next directory pointer */
+        return !ds ? FR_NO_FILE : FR_NO_PATH;
+    }
+    if (!ds) { *dir = dptr; return FR_OK; }                            /* Matched with end of path */
+    if (!(dptr[DIR_Attr] & AM_DIR)) return FR_NO_PATH; /* Cannot trace because it is a file */
+    clust = ((U32)LD_U16(&dptr[DIR_FstClusHI]) << 16) | LD_U16(&dptr[DIR_FstClusLO]); /* Get cluster# of the directory */
+    dirobj->clust = dirobj->sclust = clust;                            /* Restart scanning at the new directory */
+    dirobj->sect = clust2sect(fs, clust);
+    dirobj->index = 2;
+  }
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Reserve a directory entry                                             */
+/*-----------------------------------------------------------------------*/
+
+#if !_FS_READONLY
+static
+FRESULT reserve_direntry (     /* FR_OK: successful, FR_DENIED: no free entry, FR_RW_ERROR: a disk error occured */
+    DIR *dirobj,                       /* Target directory to create new entry */
+    U8 **dir                           /* Pointer to pointer to created entry to retutn */
+    )
+{
+  U32 clust, sector;
+  U8 c, n, *dptr;
+  FATFS *fs = dirobj->fs;
+
+
+  /* Re-initialize directory object */
+  clust = dirobj->sclust;
+  if (clust) { /* Dyanmic directory table */
+    dirobj->clust = clust;
+    dirobj->sect = clust2sect(fs, clust);
+  } else {             /* Static directory table */
+    dirobj->sect = fs->dirbase;
+  }
+  dirobj->index = 0;
+
+  do {
+    if (!move_window(fs, dirobj->sect)) return FR_RW_ERROR;
+    dptr = &fs->win[(dirobj->index & ((S_SIZ - 1) / 32)) * 32];        /* Pointer to the directory entry */
+    c = dptr[DIR_Name];
+    if (c == 0 || c == 0xE5) {                 /* Found an empty entry! */
+      *dir = dptr; return FR_OK;
+    }
+  } while (next_dir_entry(dirobj));                            /* Next directory pointer */
+  /* Reached to end of the directory table */
+
+  /* Abort when static table or could not stretch dynamic table */
+  if (!clust || !(clust = create_chain(fs, dirobj->clust))) return FR_DENIED;
+  if (clust == 1 || !move_window(fs, 0)) return FR_RW_ERROR;
+
+  fs->winsect = sector = clust2sect(fs, clust);                /* Cleanup the expanded table */
+  memset(fs->win, 0, S_SIZ);
+  for (n = fs->sects_clust; n; n--) {
+    if (diskWrite(fs->drive, fs->win, sector, 1) != RES_OK)
+      return FR_RW_ERROR;
+    sector++;
+  }
+  fs->winflag = 1;
+  *dir = fs->win;
+  return FR_OK;
+}
+#endif /* !_FS_READONLY */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Load boot record and check if it is a FAT boot record                 */
+/*-----------------------------------------------------------------------*/
+
+static
+U8 check_fs (          /* 0:The FAT boot record, 1:Valid boot record but not an FAT, 2:Not a boot record or error */
+    FATFS *fs,         /* File system object */
+    U32 sect           /* Sector# (lba) to check if it is a FAT boot record or not */
+    )
+{
+  if (diskRead(fs->drive, fs->win, sect, 1) != RES_OK) /* Load boot record */
+    return 2;
+  if (LD_U16(&fs->win[BS_55AA]) != 0xAA55)                             /* Check record signature (always offset 510) */
+    return 2;
+
+  if (!memcmp(&fs->win[BS_FilSysType], "FAT", 3))                      /* Check FAT signature */
+    return 0;
+  if (!memcmp(&fs->win[BS_FilSysType32], "FAT32", 5) && !(fs->win[BPB_ExtFlags] & 0x80))
+    return 0;
+
+  return 1;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Make sure that the file system is valid                               */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT auto_mount (           /* FR_OK(0): successful, !=0: any error occured */
+    const char **path,         /* Pointer to pointer to the path name (drive number) */
+    FATFS **rfs,                       /* Pointer to pointer to the found file system object */
+    U8 chk_wp                          /* !=0: Check media write protection for wrinting fuctions */
+    )
+{
+  U8 drv, fmt, *tbl;
+  DSTATUS stat;
+  U32 bootsect, fatsize, totalsect, maxclust;
+  const char *p = *path;
+  FATFS *fs;
+
+
+  /* Get drive number from the path name */
+  while (*p == ' ') p++;               /* Strip leading spaces */
+  drv = p[0] - '0';                    /* Is there a drive number? */
+  if (drv <= 9 && p[1] == ':')
+    p += 2;                    /* Found a drive number, get and strip it */
+  else
+    drv = 0;           /* No drive number is given, select drive 0 in default */
+  if (*p == '/') p++;  /* Strip heading slash */
+  *path = p;                   /* Return pointer to the path name */
+
+  /* Check if the drive number is valid or not */
+  if (drv >= _DRIVES) return FR_INVALID_DRIVE; /* Is the drive number valid? */
+  if (!(fs = FatFs[drv])) return FR_NOT_ENABLED;       /* Is the file system object registered? */
+  *rfs = fs;                   /* Returen pointer to the corresponding file system object */
+
+  /* Check if the logical drive has been mounted or not */
+  if (fs->fs_type) {
+    stat = diskStatus(fs->drive);
+    if (!(stat & STA_NOINIT)) {                                /* If the physical drive is kept initialized */
+#if !_FS_READONLY
+      if (chk_wp && (stat & STA_PROTECT))      /* Check write protection if needed */
+        return FR_WRITE_PROTECTED;
+#endif
+      return FR_OK;                                            /* The file system object is valid */
+    }
+  }
+
+  /* The logical drive has not been mounted, following code attempts to mount the logical drive */
+
+  memset(fs, 0, sizeof(FATFS));                /* Clean-up the file system object */
+  fs->drive = LD2PD(drv);                              /* Bind the logical drive and a physical drive */
+  stat = diskInitialize (fs->drive);   /* Initialize low level disk I/O layer */
+  if (stat & STA_NOINIT)                               /* Check if the drive is ready */
+    return FR_NOT_READY;
+#if S_MAX_SIZ > 512                                            /* Check disk sector size */
+  if (diskIoctl(drv, GET_SECTOR_SIZE, &S_SIZ) != RES_OK || S_SIZ > S_MAX_SIZ)
+    return FR_NO_FILESYSTEM;
+#endif
+#if !_FS_READONLY
+  if (chk_wp && (stat & STA_PROTECT))  /* Check write protection if needed */
+    return FR_WRITE_PROTECTED;
+#endif
+  /* Search FAT partition on the drive */
+  fmt = check_fs(fs, bootsect = 0);    /* Check sector 0 as an SFD format */
+  if (fmt == 1) {                                              /* Not a FAT boot record, it may be patitioned */
+    /* Check a partition listed in top of the partition table */
+    tbl = &fs->win[MBR_Table + LD2PT(drv) * 16];       /* Partition table */
+    if (tbl[4]) {                                                              /* Is the partition existing? */
+      bootsect = LD_U32(&tbl[8]);                      /* Partition offset in LBA */
+      fmt = check_fs(fs, bootsect);                    /* Check the partition */
+    }
+  }
+  if (fmt || LD_U16(&fs->win[BPB_BytsPerSec]) != S_SIZ)        /* No valid FAT patition is found */
+    return FR_NO_FILESYSTEM;
+
+  /* Initialize the file system object */
+  fatsize = LD_U16(&fs->win[BPB_FATSz16]);                     /* Number of sectors per FAT */
+  if (!fatsize) fatsize = LD_U32(&fs->win[BPB_FATSz32]);
+  fs->sects_fat = fatsize;
+  fs->n_fats = fs->win[BPB_NumFATs];                                   /* Number of FAT copies */
+  fatsize *= fs->n_fats;                                                               /* (Number of sectors in FAT area) */
+  fs->fatbase = bootsect + LD_U16(&fs->win[BPB_RsvdSecCnt]); /* FAT start sector (lba) */
+  fs->sects_clust = fs->win[BPB_SecPerClus];                   /* Number of sectors per cluster */
+  fs->n_rootdir = LD_U16(&fs->win[BPB_RootEntCnt]);    /* Nmuber of root directory entries */
+  totalsect = LD_U16(&fs->win[BPB_TotSec16]);          /* Number of sectors on the file system */
+  if (!totalsect) totalsect = LD_U32(&fs->win[BPB_TotSec32]);
+  fs->max_clust = maxclust = (totalsect                                /* Last cluster# + 1 */
+      - LD_U16(&fs->win[BPB_RsvdSecCnt]) - fatsize - fs->n_rootdir / (S_SIZ/32)
+      ) / fs->sects_clust + 2;
+
+  fmt = FS_FAT12;                                                                              /* Determine the FAT sub type */
+  if (maxclust > 0xFF7) fmt = FS_FAT16;
+  if (maxclust > 0xFFF7) fmt = FS_FAT32;
+  fs->fs_type = fmt;
+
+  if (fmt == FS_FAT32)
+    fs->dirbase = LD_U32(&fs->win[BPB_RootClus]);      /* Root directory start cluster */
+  else
+    fs->dirbase = fs->fatbase + fatsize;                       /* Root directory start sector (lba) */
+  fs->database = fs->fatbase + fatsize + fs->n_rootdir / (S_SIZ/32);   /* Data start sector (lba) */
+
+#if !_FS_READONLY
+  fs->free_clust = 0xFFFFFFFF;
+#if _USE_FSINFO
+  /* Load fsinfo sector if needed */
+  if (fmt == FS_FAT32) {
+    fs->fsi_sector = bootsect + LD_U16(&fs->win[BPB_FSInfo]);
+    if (diskRead(0, fs->win, fs->fsi_sector, 1) == RES_OK &&
+        LD_U16(&fs->win[BS_55AA]) == 0xAA55 &&
+        LD_U32(&fs->win[FSI_LeadSig]) == 0x41615252 &&
+        LD_U32(&fs->win[FSI_StrucSig]) == 0x61417272) {
+      fs->last_clust = LD_U32(&fs->win[FSI_Nxt_Free]);
+      fs->free_clust = LD_U32(&fs->win[FSI_Free_Count]);
+    }
+  }
+#endif
+#endif
+  fs->id = ++fsid;                                                                     /* File system mount ID */
+  return FR_OK;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Check if the file/dir object is valid or not                          */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT validate (             /* FR_OK(0): The object is valid, !=0: Not valid */
+    const FATFS *fs,   /* Pointer to the file system object */
+    U16 id                             /* id member of the target object to be checked */
+    )
+{
+  if (!fs || fs->id != id)
+    return FR_INVALID_OBJECT;
+  if (diskStatus(fs->drive) & STA_NOINIT)
+    return FR_NOT_READY;
+
+  return FR_OK;
+}
+
+
+
+
+/*--------------------------------------------------------------------------
+
+  Public Functions
+
+  --------------------------------------------------------------------------*/
+
+
+void f_printerror (FRESULT f)
+{
+  unsigned int i;
+
+  typedef struct errorStrings_s
+  {
+    FRESULT fresult;
+    const char *string;
+  }
+  errorStrings_t;
+
+  static errorStrings_t errorStrings [] =
+  {
+    { FR_OK,              "OK"              },
+    { FR_NOT_READY,       "NOT_READY"       },
+    { FR_NO_FILE,         "NO_FILE"         },
+    { FR_NO_PATH,         "NO_PATH"         },
+    { FR_INVALID_NAME,    "INVALID_NAME"    },
+    { FR_INVALID_DRIVE,   "INVALID_DRIVE"   },
+    { FR_DENIED,          "DENIED"          },
+    { FR_EXIST,           "EXIST"           },
+    { FR_RW_ERROR,        "RW_ERROR"        },
+    { FR_WRITE_PROTECTED, "WRITE_PROTECTED" },
+    { FR_NOT_ENABLED,     "NOT_ENABLED"     },
+    { FR_NO_FILESYSTEM,   "NO_FILESYSTEM"   },
+    { FR_INVALID_OBJECT,  "INVALID_OBJECT"  },
+    { FR_MKFS_ABORTED,    "MKFS_ABORTED"    },
+  };
+
+  for (i = 0; i < arrsizeof (errorStrings); i++)
+  {
+    if (errorStrings [i].fresult == f)
+    {
+      printf ("rrc=%u FR_%s\n", f, errorStrings [f].string);
+      return;
+    }
+  }
+
+  printf ("rrc=%u (no text equivalent)\n", f);
+}
+
+
+/*-----------------------------------------------------------------------*/
+/* Mount/Unmount a Locical Drive                                         */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_mount (U8 drv, FATFS *fs)
+{
+  FATFS *fsobj;
+
+  if (drv >= _DRIVES) 
+    return FR_INVALID_DRIVE;
+
+  fsobj = FatFs [drv];
+  FatFs [drv] = fs;
+
+  if (fsobj) 
+    memset (fsobj, 0, sizeof (FATFS));
+  if (fs) 
+    memset (fs, 0, sizeof (FATFS));
+
+  return FR_OK;
+}
+
+/*-----------------------------------------------------------------------*/
+/* Open or Create a File                                                 */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_open (
+    FIL *fp,                   /* Pointer to the blank file object */
+    const char *path,  /* Pointer to the file name */
+    U8 mode                    /* Access mode and file open mode flags */
+    )
+{
+  FRESULT res;
+  U8 *dir;
+  DIR dirobj;
+  char fn[8+3+1];
+  FATFS *fs;
+
+
+  fp->fs = NULL;
+#if !_FS_READONLY
+  mode &= (FA_READ|FA_WRITE|FA_CREATE_ALWAYS|FA_OPEN_ALWAYS|FA_CREATE_NEW);
+  res = auto_mount(&path, &fs, (U8)(mode & (FA_WRITE|FA_CREATE_ALWAYS|FA_OPEN_ALWAYS|FA_CREATE_NEW)));
+#else
+  mode &= FA_READ;
+  res = auto_mount(&path, &fs, 0);
+#endif
+  if (res != FR_OK) return res;
+  dirobj.fs = fs;
+
+  /* Trace the file path */
+  res = trace_path(&dirobj, fn, path, &dir);
+#if !_FS_READONLY
+  /* Create or Open a file */
+  if (mode & (FA_CREATE_ALWAYS|FA_OPEN_ALWAYS|FA_CREATE_NEW)) {
+    U32 ps, rs;
+    if (res != FR_OK) {                /* No file, create new */
+      if (res != FR_NO_FILE) return res;
+      res = reserve_direntry(&dirobj, &dir);
+      if (res != FR_OK) return res;
+      memset(dir, 0, 32);                                              /* Initialize the new entry with open name */
+      memcpy(&dir[DIR_Name], fn, 8+3);
+      dir[DIR_NTres] = fn[11];
+      mode |= FA_CREATE_ALWAYS;
+    }
+    else {                                     /* Any object is already existing */
+      if (mode & FA_CREATE_NEW)                        /* Cannot create new */
+        return FR_EXIST;
+      if (dir == NULL || (dir[DIR_Attr] & (AM_RDO|AM_DIR)))    /* Cannot overwrite it (R/O or DIR) */
+        return FR_DENIED;
+      if (mode & FA_CREATE_ALWAYS) {           /* Resize it to zero if needed */
+        rs = ((U32)LD_U16(&dir[DIR_FstClusHI]) << 16) | LD_U16(&dir[DIR_FstClusLO]);   /* Get start cluster */
+        ST_U16(&dir[DIR_FstClusHI], 0);        /* cluster = 0 */
+        ST_U16(&dir[DIR_FstClusLO], 0);
+        ST_U32(&dir[DIR_FileSize], 0); /* size = 0 */
+        fs->winflag = 1;
+        ps = fs->winsect;                              /* Remove the cluster chain */
+        if (!remove_chain(fs, rs) || !move_window(fs, ps))
+          return FR_RW_ERROR;
+        fs->last_clust = rs - 1;               /* Reuse the cluster hole */
+      }
+    }
+    if (mode & FA_CREATE_ALWAYS) {
+      dir[DIR_Attr] = AM_ARC;                          /* New attribute */
+      ps = get_fattime();
+      ST_U32(&dir[DIR_WrtTime], ps);   /* Updated time */
+      ST_U32(&dir[DIR_CrtTime], ps);   /* Created time */
+      fs->winflag = 1;
+    }
+  }
+  /* Open an existing file */
+  else {
+#endif /* !_FS_READONLY */
+    if (res != FR_OK) return res;              /* Trace failed */
+    if (dir == NULL || (dir[DIR_Attr] & AM_DIR))       /* It is a directory */
+      return FR_NO_FILE;
+#if !_FS_READONLY
+    if ((mode & FA_WRITE) && (dir[DIR_Attr] & AM_RDO)) /* R/O violation */
+      return FR_DENIED;
+  }
+
+  fp->dir_sect = fs->winsect;                  /* Pointer to the directory entry */
+  fp->dir_ptr = dir;
+#endif
+  fp->flag = mode;                                     /* File access mode */
+  fp->org_clust =                                              /* File start cluster */
+    ((U32)LD_U16(&dir[DIR_FstClusHI]) << 16) | LD_U16(&dir[DIR_FstClusLO]);
+  fp->fsize = LD_U32(&dir[DIR_FileSize]);      /* File size */
+  fp->fptr = 0;                                                /* File ptr */
+  fp->sect_clust = 1;                                  /* Sector counter */
+  fp->fs = fs; fp->id = fs->id;                /* Owner file system object of the file */
+
+  return FR_OK;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Read File                                                             */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_read (
+    FIL *fp,           /* Pointer to the file object */
+    void *buff,                /* Pointer to data buffer */
+    U16 btr,           /* Number of bytes to read */
+    U16 *br            /* Pointer to number of bytes read */
+    )
+{
+  U32 clust, sect, remain;
+  U16 rcnt;
+  U8 cc, *rbuff = buff;
+  FRESULT res;
+  FATFS *fs = fp->fs;
+
+
+  *br = 0;
+  res = validate(fs, fp->id);                                          /* Check validity of the object */
+  if (res) return res;
+  if (fp->flag & FA__ERROR) return FR_RW_ERROR;        /* Check error flag */
+  if (!(fp->flag & FA_READ)) return FR_DENIED; /* Check access mode */
+  remain = fp->fsize - fp->fptr;
+  if (btr > remain) btr = (U16)remain;                 /* Truncate read count by number of bytes left */
+
+  for ( ;  btr;                                                                        /* Repeat until all data transferred */
+      rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) {
+    if ((fp->fptr & (S_SIZ - 1)) == 0) {               /* On the sector boundary */
+      if (--fp->sect_clust) {                                  /* Decrement left sector counter */
+        sect = fp->curr_sect + 1;                      /* Get current sector */
+      } else {                                                         /* On the cluster boundary, get next cluster */
+        clust = (fp->fptr == 0) ?
+          fp->org_clust : get_cluster(fs, fp->curr_clust);
+        if (clust < 2 || clust >= fs->max_clust)
+          goto fr_error;
+        fp->curr_clust = clust;                                /* Current cluster */
+        sect = clust2sect(fs, clust);          /* Get current sector */
+        fp->sect_clust = fs->sects_clust;      /* Re-initialize the left sector counter */
+      }
+#if !_FS_READONLY
+      if (fp->flag & FA__DIRTY) {                              /* Flush file I/O buffer if needed */
+        if (diskWrite(fs->drive, fp->buffer, fp->curr_sect, 1) != RES_OK)
+          goto fr_error;
+        fp->flag &= ~FA__DIRTY;
+      }
+#endif
+      fp->curr_sect = sect;                                    /* Update current sector */
+      cc = btr / S_SIZ;                                                /* When left bytes >= S_SIZ, */
+      if (cc) {                                                                /* Read maximum contiguous sectors directly */
+        if (cc > fp->sect_clust) cc = fp->sect_clust;
+        if (diskRead(fs->drive, rbuff, sect, cc) != RES_OK)
+          goto fr_error;
+        fp->sect_clust -= cc - 1;
+        fp->curr_sect += cc - 1;
+        rcnt = cc * S_SIZ; continue;
+      }
+      if (diskRead(fs->drive, fp->buffer, sect, 1) != RES_OK)  /* Load the sector into file I/O buffer */
+        goto fr_error;
+    }
+    rcnt = S_SIZ - ((U16)fp->fptr & (S_SIZ - 1));                              /* Copy fractional bytes from file I/O buffer */
+    if (rcnt > btr) rcnt = btr;
+    memcpy(rbuff, &fp->buffer[fp->fptr & (S_SIZ - 1)], rcnt);
+  }
+
+  return FR_OK;
+
+fr_error:      /* Abort this file due to an unrecoverable error */
+  fp->flag |= FA__ERROR;
+  return FR_RW_ERROR;
+}
+
+
+
+
+#if !_FS_READONLY
+/*-----------------------------------------------------------------------*/
+/* Write File                                                            */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_write (
+    FIL *fp,                   /* Pointer to the file object */
+    const void *buff,  /* Pointer to the data to be written */
+    U16 btw,                   /* Number of bytes to write */
+    U16 *bw                    /* Pointer to number of bytes written */
+    )
+{
+  U32 clust, sect;
+  U16 wcnt;
+  U8 cc;
+  FRESULT res;
+  const U8 *wbuff = buff;
+  FATFS *fs = fp->fs;
+
+
+  *bw = 0;
+  res = validate(fs, fp->id);                                          /* Check validity of the object */
+  if (res) return res;
+  if (fp->flag & FA__ERROR) return FR_RW_ERROR;        /* Check error flag */
+  if (!(fp->flag & FA_WRITE)) return FR_DENIED;        /* Check access mode */
+  if (fp->fsize + btw < fp->fsize) return FR_OK;       /* File size cannot reach 4GB */
+
+  for ( ;  btw;                                                                        /* Repeat until all data transferred */
+      wbuff += wcnt, fp->fptr += wcnt, *bw += wcnt, btw -= wcnt) {
+    if ((fp->fptr & (S_SIZ - 1)) == 0) {               /* On the sector boundary */
+      if (--fp->sect_clust) {                                  /* Decrement left sector counter */
+        sect = fp->curr_sect + 1;                      /* Get current sector */
+      } else {                                                         /* On the cluster boundary, get next cluster */
+        if (fp->fptr == 0) {                           /* Is top of the file */
+          clust = fp->org_clust;
+          if (clust == 0)                                      /* No cluster is created yet */
+            fp->org_clust = clust = create_chain(fs, 0);       /* Create a new cluster chain */
+        } else {                                                       /* Middle or end of file */
+          clust = create_chain(fs, fp->curr_clust);                    /* Trace or streach cluster chain */
+        }
+        if (clust == 0) break;                         /* Disk full */
+        if (clust == 1 || clust >= fs->max_clust) goto fw_error;
+        fp->curr_clust = clust;                                /* Current cluster */
+        sect = clust2sect(fs, clust);          /* Get current sector */
+        fp->sect_clust = fs->sects_clust;      /* Re-initialize the left sector counter */
+      }
+      if (fp->flag & FA__DIRTY) {                              /* Flush file I/O buffer if needed */
+        if (diskWrite(fs->drive, fp->buffer, fp->curr_sect, 1) != RES_OK)
+          goto fw_error;
+        fp->flag &= ~FA__DIRTY;
+      }
+      fp->curr_sect = sect;                                    /* Update current sector */
+      cc = btw / S_SIZ;                                                /* When left bytes >= S_SIZ, */
+      if (cc) {                                                                /* Write maximum contiguous sectors directly */
+        if (cc > fp->sect_clust) cc = fp->sect_clust;
+        if (diskWrite(fs->drive, wbuff, sect, cc) != RES_OK)
+          goto fw_error;
+        fp->sect_clust -= cc - 1;
+        fp->curr_sect += cc - 1;
+        wcnt = cc * S_SIZ; continue;
+      }
+      if (fp->fptr < fp->fsize &&                      /* Fill sector buffer with file data if needed */
+          diskRead(fs->drive, fp->buffer, sect, 1) != RES_OK)
+        goto fw_error;
+    }
+    wcnt = S_SIZ - ((U16)fp->fptr & (S_SIZ - 1));      /* Copy fractional bytes to file I/O buffer */
+    if (wcnt > btw) wcnt = btw;
+    memcpy(&fp->buffer[fp->fptr & (S_SIZ - 1)], wbuff, wcnt);
+    fp->flag |= FA__DIRTY;
+  }
+
+  if (fp->fptr > fp->fsize) fp->fsize = fp->fptr;      /* Update file size if needed */
+  fp->flag |= FA__WRITTEN;                                             /* Set file changed flag */
+  return FR_OK;
+
+fw_error:      /* Abort this file due to an unrecoverable error */
+  fp->flag |= FA__ERROR;
+  return FR_RW_ERROR;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Synchronize between File and Disk                                     */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_sync (
+    FIL *fp            /* Pointer to the file object */
+    )
+{
+  U32 tim;
+  U8 *dir;
+  FRESULT res;
+  FATFS *fs = fp->fs;
+
+
+  res = validate(fs, fp->id);                  /* Check validity of the object */
+  if (res == FR_OK) {
+    if (fp->flag & FA__WRITTEN) {      /* Has the file been written? */
+      /* Write back data buffer if needed */
+      if (fp->flag & FA__DIRTY) {
+        if (diskWrite(fs->drive, fp->buffer, fp->curr_sect, 1) != RES_OK)
+          return FR_RW_ERROR;
+        fp->flag &= ~FA__DIRTY;
+      }
+      /* Update the directory entry */
+      if (!move_window(fs, fp->dir_sect))
+        return FR_RW_ERROR;
+      dir = fp->dir_ptr;
+      dir[DIR_Attr] |= AM_ARC;                                         /* Set archive bit */
+      ST_U32(&dir[DIR_FileSize], fp->fsize);           /* Update file size */
+      ST_U16(&dir[DIR_FstClusLO], fp->org_clust);      /* Update start cluster */
+      ST_U16(&dir[DIR_FstClusHI], fp->org_clust >> 16);
+      tim = get_fattime();                                     /* Updated time */
+      ST_U32(&dir[DIR_WrtTime], tim);
+      fp->flag &= ~FA__WRITTEN;
+      res = sync(fs);
+    }
+  }
+  return res;
+}
+
+#endif /* !_FS_READONLY */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Close File                                                            */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_close (
+    FIL *fp            /* Pointer to the file object to be closed */
+    )
+{
+  FRESULT res;
+
+
+#if !_FS_READONLY
+  res = f_sync(fp);
+#else
+  res = validate(fp->fs, fp->id);
+#endif
+  if (res == FR_OK)
+    fp->fs = NULL;
+  return res;
+}
+
+
+
+
+#if _FS_MINIMIZE <= 2
+/*-----------------------------------------------------------------------*/
+/* Seek File R/W Pointer                                                 */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_lseek (
+    FIL *fp,           /* Pointer to the file object */
+    U32 ofs            /* File pointer from top of file */
+    )
+{
+  U32 clust, csize;
+  U8 csect;
+  FRESULT res;
+  FATFS *fs = fp->fs;
+
+
+  res = validate(fs, fp->id);                  /* Check validity of the object */
+  if (res) return res;
+  if (fp->flag & FA__ERROR) return FR_RW_ERROR;
+#if !_FS_READONLY
+  if (fp->flag & FA__DIRTY) {                  /* Write-back dirty buffer if needed */
+    if (diskWrite(fs->drive, fp->buffer, fp->curr_sect, 1) != RES_OK)
+      goto fk_error;
+    fp->flag &= ~FA__DIRTY;
+  }
+  if (ofs > fp->fsize && !(fp->flag & FA_WRITE))
+#else
+    if (ofs > fp->fsize)
+#endif
+      ofs = fp->fsize;
+  fp->fptr = 0; fp->sect_clust = 1;            /* Set file R/W pointer to top of the file */
+
+  /* Move file R/W pointer if needed */
+  if (ofs) {
+    clust = fp->org_clust;     /* Get start cluster */
+#if !_FS_READONLY
+    if (!clust) {                      /* If the file does not have a cluster chain, create new cluster chain */
+      clust = create_chain(fs, 0);
+      if (clust == 1) goto fk_error;
+      fp->org_clust = clust;
+    }
+#endif
+    if (clust) {                       /* If the file has a cluster chain, it can be followed */
+      csize = (U32)fs->sects_clust * S_SIZ;            /* Cluster size in unit of byte */
+      for (;;) {                                                                       /* Loop to skip leading clusters */
+        fp->curr_clust = clust;                                        /* Update current cluster */
+        if (ofs <= csize) break;
+#if !_FS_READONLY
+        if (fp->flag & FA_WRITE)                               /* Check if in write mode or not */
+          clust = create_chain(fs, clust);     /* Force streached if in write mode */
+        else
+#endif
+          clust = get_cluster(fs, clust);              /* Only follow cluster chain if not in write mode */
+        if (clust == 0) {                                              /* Stop if could not follow the cluster chain */
+          ofs = csize; break;
+        }
+        if (clust == 1 || clust >= fs->max_clust) goto fk_error;
+        fp->fptr += csize;                                             /* Update R/W pointer */
+        ofs -= csize;
+      }
+      csect = (U8)((ofs - 1) / S_SIZ);                 /* Sector offset in the cluster */
+      fp->curr_sect = clust2sect(fs, clust) + csect;   /* Current sector */
+      if ((ofs & (S_SIZ - 1)) &&                                       /* Load current sector if needed */
+          diskRead(fs->drive, fp->buffer, fp->curr_sect, 1) != RES_OK)
+        goto fk_error;
+      fp->sect_clust = fs->sects_clust - csect;        /* Left sector counter in the cluster */
+      fp->fptr += ofs;                                                 /* Update file R/W pointer */
+    }
+  }
+#if !_FS_READONLY
+  if ((fp->flag & FA_WRITE) && fp->fptr > fp->fsize) { /* Set updated flag if in write mode */
+    fp->fsize = fp->fptr;
+    fp->flag |= FA__WRITTEN;
+  }
+#endif
+
+  return FR_OK;
+
+fk_error:      /* Abort this file due to an unrecoverable error */
+  fp->flag |= FA__ERROR;
+  return FR_RW_ERROR;
+}
+
+
+
+
+#if _FS_MINIMIZE <= 1
+/*-----------------------------------------------------------------------*/
+/* Create a directroy object                                             */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_opendir (
+    DIR *dirobj,               /* Pointer to directory object to create */
+    const char *path   /* Pointer to the directory path */
+    )
+{
+  U8 *dir;
+  char fn[8+3+1];
+  FRESULT res;
+  FATFS *fs;
+
+
+  res = auto_mount(&path, &fs, 0);
+  if (res != FR_OK) return res;
+  dirobj->fs = fs;
+
+  res = trace_path(dirobj, fn, path, &dir);    /* Trace the directory path */
+  if (res == FR_OK) {                                          /* Trace completed */
+    if (dir != NULL) {                                 /* It is not the root dir */
+      if (dir[DIR_Attr] & AM_DIR) {            /* The entry is a directory */
+        dirobj->clust = ((U32)LD_U16(&dir[DIR_FstClusHI]) << 16) | LD_U16(&dir[DIR_FstClusLO]);
+        dirobj->sect = clust2sect(fs, dirobj->clust);
+        dirobj->index = 2;
+      } else {                                         /* The entry is not a directory */
+        res = FR_NO_FILE;
+      }
+    }
+    dirobj->id = fs->id;
+  }
+  return res;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Read Directory Entry in Sequense                                      */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_readdir (
+    DIR *dirobj,               /* Pointer to the directory object */
+    FILINFO *finfo             /* Pointer to file information to return */
+    )
+{
+  U8 *dir, c, res;
+  FATFS *fs = dirobj->fs;
+
+
+  res = validate(fs, dirobj->id);                      /* Check validity of the object */
+  if (res) return (FRESULT) res;
+
+  finfo->fname[0] = 0;
+  while (dirobj->sect) {
+    if (!move_window(fs, dirobj->sect))
+      return FR_RW_ERROR;
+    dir = &fs->win[(dirobj->index & ((S_SIZ - 1) >> 5)) * 32]; /* pointer to the directory entry */
+    c = *dir;
+    if (c == 0) break;                                                         /* Has it reached to end of dir? */
+    if (c != 0xE5 && !(dir[DIR_Attr] & AM_VOL))                /* Is it a valid entry? */
+      get_fileinfo(finfo, dir);
+    if (!next_dir_entry(dirobj)) dirobj->sect = 0;     /* Next entry */
+    if (finfo->fname[0]) break;                                                /* Found valid entry */
+  }
+
+  return FR_OK;
+}
+
+
+
+
+#if _FS_MINIMIZE == 0
+/*-----------------------------------------------------------------------*/
+/* Get File Status                                                       */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_stat (
+    const char *path,  /* Pointer to the file path */
+    FILINFO *finfo             /* Pointer to file information to return */
+    )
+{
+  U8 *dir;
+  char fn[8+3+1];
+  FRESULT res;
+  DIR dirobj;
+  FATFS *fs;
+
+
+  res = auto_mount(&path, &fs, 0);
+  if (res != FR_OK) return res;
+  dirobj.fs = fs;
+
+  res = trace_path(&dirobj, fn, path, &dir);   /* Trace the file path */
+  if (res == FR_OK) {                                                  /* Trace completed */
+    if (dir)   /* Found an object */
+      get_fileinfo(finfo, dir);
+    else               /* It is root dir */
+      res = FR_INVALID_NAME;
+  }
+
+  return res;
+}
+
+
+
+#if !_FS_READONLY
+/*-----------------------------------------------------------------------*/
+/* Get Number of Free Clusters                                           */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_getfree (
+    const char *drv,   /* Logical drive number */
+    U32 *nclust,               /* Pointer to the double word to return number of free clusters */
+    FATFS **fatfs              /* Pointer to pointer to the file system object to return */
+    )
+{
+  U32 n, clust, sect;
+  U8 fat, f, *p;
+  FRESULT res;
+  FATFS *fs;
+
+
+  /* Get drive number */
+  res = auto_mount(&drv, &fs, 0);
+  if (res != FR_OK) return res;
+  *fatfs = fs;
+
+  /* If number of free cluster is valid, return it without cluster scan. */
+  if (fs->free_clust <= fs->max_clust - 2) {
+    *nclust = fs->free_clust;
+    return FR_OK;
+  }
+
+  /* Count number of free clusters */
+  fat = fs->fs_type;
+  n = 0;
+  if (fat == FS_FAT12) {
+    clust = 2;
+    do {
+      if ((U16)get_cluster(fs, clust) == 0) n++;
+    } while (++clust < fs->max_clust);
+  } else {
+    clust = fs->max_clust;
+    sect = fs->fatbase;
+    f = 0; p = 0;
+    do {
+      if (!f) {
+        if (!move_window(fs, sect++)) return FR_RW_ERROR;
+        p = fs->win;
+      }
+      if (fat == FS_FAT16) {
+        if (LD_U16(p) == 0) n++;
+        p += 2; f += 1;
+      } else {
+        if (LD_U32(p) == 0) n++;
+        p += 4; f += 2;
+      }
+    } while (--clust);
+  }
+  fs->free_clust = n;
+#if _USE_FSINFO
+  if (fat == FS_FAT32) fs->fsi_flag = 1;
+#endif
+
+  *nclust = n;
+  return FR_OK;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Delete a File or a Directory                                          */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_unlink (
+    const char *path                   /* Pointer to the file or directory path */
+    )
+{
+  U8 *dir, *sdir;
+  U32 dclust, dsect;
+  char fn[8+3+1];
+  FRESULT res;
+  DIR dirobj;
+  FATFS *fs;
+
+
+  res = auto_mount(&path, &fs, 1);
+  if (res != FR_OK) return res;
+  dirobj.fs = fs;
+
+  res = trace_path(&dirobj, fn, path, &dir);   /* Trace the file path */
+  if (res != FR_OK) return res;                                /* Trace failed */
+  if (dir == NULL) return FR_INVALID_NAME;     /* It is the root directory */
+  if (dir[DIR_Attr] & AM_RDO) return FR_DENIED;        /* It is a R/O object */
+  dsect = fs->winsect;
+  dclust = ((U32)LD_U16(&dir[DIR_FstClusHI]) << 16) | LD_U16(&dir[DIR_FstClusLO]);
+
+  if (dir[DIR_Attr] & AM_DIR) {                                /* It is a sub-directory */
+    dirobj.clust = dclust;                                     /* Check if the sub-dir is empty or not */
+    dirobj.sect = clust2sect(fs, dclust);
+    dirobj.index = 2;
+    do {
+      if (!move_window(fs, dirobj.sect)) return FR_RW_ERROR;
+      sdir = &fs->win[(dirobj.index & ((S_SIZ - 1) >> 5)) * 32];
+      if (sdir[DIR_Name] == 0) break;
+      if (sdir[DIR_Name] != 0xE5 && !(sdir[DIR_Attr] & AM_VOL))
+        return FR_DENIED;      /* The directory is not empty */
+    } while (next_dir_entry(&dirobj));
+  }
+
+  if (!move_window(fs, dsect)) return FR_RW_ERROR;     /* Mark the directory entry 'deleted' */
+  dir[DIR_Name] = 0xE5;
+  fs->winflag = 1;
+  if (!remove_chain(fs, dclust)) return FR_RW_ERROR;   /* Remove the cluster chain */
+
+  return sync(fs);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Create a Directory                                                    */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_mkdir (
+    const char *path           /* Pointer to the directory path */
+    )
+{
+  U8 *dir, *fw, n;
+  char fn[8+3+1];
+  U32 sect, dsect, dclust, pclust, tim;
+  FRESULT res;
+  DIR dirobj;
+  FATFS *fs;
+
+  res = auto_mount(&path, &fs, 1);
+  if (res != FR_OK) return res;
+  dirobj.fs = fs;
+
+  res = trace_path(&dirobj, fn, path, &dir);   /* Trace the file path */
+  if (res == FR_OK) return FR_EXIST;                   /* Any file or directory is already existing */
+  if (res != FR_NO_FILE) return res;
+
+  res = reserve_direntry(&dirobj, &dir);               /* Reserve a directory entry */
+  if (res != FR_OK) return res;
+  sect = fs->winsect;
+
+  dclust = create_chain(fs, 0);                                /* Allocate a cluster for new directory table */
+  if (dclust == 1) return FR_RW_ERROR;
+
+  dsect = clust2sect(fs, dclust);
+  if (!dsect) return FR_DENIED;
+
+  if (!move_window(fs, dsect)) return FR_RW_ERROR;
+
+  fw = fs->win;
+  memset(fw, 0, S_SIZ);                                                /* Clear the new directory table */
+  for (n = 1; n < fs->sects_clust; n++) {
+    if (diskWrite(fs->drive, fw, ++dsect, 1) != RES_OK)
+      return FR_RW_ERROR;
+  }
+  memset(&fw[DIR_Name], ' ', 8+3);                     /* Create "." entry */
+  fw[DIR_Name] = '.';
+  fw[DIR_Attr] = AM_DIR;
+  tim = get_fattime();
+  ST_U32(&fw[DIR_WrtTime], tim);
+  memcpy(&fw[32], &fw[0], 32); fw[33] = '.';   /* Create ".." entry */
+  pclust = dirobj.sclust;
+#if _FAT32
+  ST_U16(&fw[   DIR_FstClusHI], dclust >> 16);
+  if (fs->fs_type == FS_FAT32 && pclust == fs->dirbase) pclust = 0;
+  ST_U16(&fw[32+DIR_FstClusHI], pclust >> 16);
+#endif
+  ST_U16(&fw[   DIR_FstClusLO], dclust);
+  ST_U16(&fw[32+DIR_FstClusLO], pclust);
+  fs->winflag = 1;
+
+  if (!move_window(fs, sect)) return FR_RW_ERROR;
+  memset(&dir[0], 0, 32);                                              /* Initialize the new entry */
+  memcpy(&dir[DIR_Name], fn, 8+3);                     /* Name */
+  dir[DIR_NTres] = fn[11];
+  dir[DIR_Attr] = AM_DIR;                                              /* Attribute */
+  ST_U32(&dir[DIR_WrtTime], tim);                      /* Crated time */
+  ST_U16(&dir[DIR_FstClusLO], dclust);         /* Table start cluster */
+  ST_U16(&dir[DIR_FstClusHI], dclust >> 16);
+
+  return sync(fs);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Change File Attribute                                                 */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_chmod (
+    const char *path,  /* Pointer to the file path */
+    U8 value,                  /* Attribute bits */
+    U8 mask                    /* Attribute mask to change */
+    )
+{
+  FRESULT res;
+  U8 *dir;
+  DIR dirobj;
+  char fn[8+3+1];
+  FATFS *fs;
+
+
+  res = auto_mount(&path, &fs, 1);
+  if (res == FR_OK) {
+    dirobj.fs = fs;
+    res = trace_path(&dirobj, fn, path, &dir); /* Trace the file path */
+    if (res == FR_OK) {                        /* Trace completed */
+      if (dir == NULL) {
+        res = FR_INVALID_NAME;
+      } else {
+        mask &= AM_RDO|AM_HID|AM_SYS|AM_ARC;   /* Valid attribute mask */
+        dir[DIR_Attr] = (value & mask) | (dir[DIR_Attr] & (U8)~mask);  /* Apply attribute change */
+        res = sync(fs);
+      }
+    }
+  }
+  return res;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Rename File/Directory                                                 */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_rename (
+    const char *path_old,      /* Pointer to the old name */
+    const char *path_new       /* Pointer to the new name */
+    )
+{
+  FRESULT res;
+  U32 sect_old;
+  U8 *dir_old, *dir_new, direntry[32-11];
+  DIR dirobj;
+  char fn[8+3+1];
+  FATFS *fs;
+
+
+  res = auto_mount(&path_old, &fs, 1);
+  if (res != FR_OK) return res;
+  dirobj.fs = fs;
+
+  res = trace_path(&dirobj, fn, path_old, &dir_old);   /* Check old object */
+  if (res != FR_OK) return res;                        /* The old object is not found */
+  if (!dir_old) return FR_NO_FILE;
+  sect_old = fs->winsect;                                      /* Save the object information */
+  memcpy(direntry, &dir_old[DIR_Attr], 32-11);
+
+  res = trace_path(&dirobj, fn, path_new, &dir_new);   /* Check new object */
+  if (res == FR_OK) return FR_EXIST;                   /* The new object name is already existing */
+  if (res != FR_NO_FILE) return res;                   /* Is there no old name? */
+  res = reserve_direntry(&dirobj, &dir_new);   /* Reserve a directory entry */
+  if (res != FR_OK) return res;
+
+  memcpy(&dir_new[DIR_Attr], direntry, 32-11); /* Create new entry */
+  memcpy(&dir_new[DIR_Name], fn, 8+3);
+  dir_new[DIR_NTres] = fn[11];
+  fs->winflag = 1;
+
+  if (!move_window(fs, sect_old)) return FR_RW_ERROR;  /* Remove old entry */
+  dir_old[DIR_Name] = 0xE5;
+
+  return sync(fs);
+}
+
+
+
+#if _USE_MKFS
+/*-----------------------------------------------------------------------*/
+/* Create File System on the Drive                                       */
+/*-----------------------------------------------------------------------*/
+
+#define N_ROOTDIR 512
+#define N_FATS 1
+#define MAX_SECTOR 64000000UL
+#define MIN_SECTOR 2000UL
+#define ERASE_BLK 32
+
+
+FRESULT f_mkfs (
+    U8 drv,            /* Logical drive number */
+    U8 partition,              /* Partitioning rule 0:FDISK, 1:SFD */
+    U8 allocsize               /* Allocation unit size [sectors] */
+    )
+{
+  U8 fmt, m, *tbl;
+  U32 b_part, b_fat, b_dir, b_data;            /* Area offset (LBA) */
+  U32 n_part, n_rsv, n_fat, n_dir;             /* Area size */
+  U32 n_clust, n;
+  FATFS *fs;
+  DSTATUS stat;
+
+
+  /* Check and mounted drive and clear work area */
+  if (drv >= _DRIVES) 
+    return FR_INVALID_DRIVE;
+
+  if (!(fs = FatFs [drv]))
+    return FR_NOT_ENABLED;
+
+  memset (fs, 0, sizeof(FATFS));
+  drv = LD2PD(drv);
+
+  /* Check validity of the parameters */
+  for (n = 1; n <= 64 && allocsize != n; n <<= 1)
+    ;
+  if (n > 64 || partition >= 2) 
+  { // ###
+    // printf ("line %d: n > 64 || partition >= 2.  n=%d, partition=%d\n", __LINE__, n, partition); // ###
+    return FR_MKFS_ABORTED;
+  } // ###
+
+  /* Get disk statics */
+  stat = diskInitialize (drv);
+
+  if (stat & STA_NOINIT) 
+    return FR_NOT_READY;
+  if (stat & STA_PROTECT) 
+    return FR_WRITE_PROTECTED;
+  { // ###
+    DRESULT dres; // ###
+    if ((dres = diskIoctl (drv, GET_SECTOR_COUNT, &n_part)) != RES_OK || n_part < MIN_SECTOR)
+    { // ###
+      // printf ("line %d: ioctl returned %d.  n_part=%d, MIN_SECTOR=%d\n", __LINE__, dres, n_part, MIN_SECTOR); // ###
+      return FR_MKFS_ABORTED;
+    } // ###
+  } // ###
+
+  if (n_part > MAX_SECTOR) 
+    n_part = MAX_SECTOR;
+
+  b_part = (!partition) ? 63 : 0;
+  n_part -= b_part;
+#if S_MAX_SIZ > 512                                            /* Check disk sector size */
+  if (diskIoctl(drv, GET_SECTOR_SIZE, &S_SIZ) != RES_OK
+      || S_SIZ > S_MAX_SIZ
+      || (U32)S_SIZ * allocsize > 32768U)
+    return FR_MKFS_ABORTED;
+#endif
+
+  /* Pre-compute number of clusters and FAT type */
+  n_clust = n_part / allocsize;
+  fmt = FS_FAT12;
+  if (n_clust >= 0xFF7) fmt = FS_FAT16;
+  if (n_clust >= 0xFFF7) fmt = FS_FAT32;
+  switch (fmt) {
+    case FS_FAT12:
+      n_fat = ((n_clust * 3 + 1) / 2 + 3 + S_SIZ - 1) / S_SIZ;
+      n_rsv = 1 + partition;
+      n_dir = N_ROOTDIR * 32 / S_SIZ;
+      break;
+    case FS_FAT16:
+      n_fat = ((n_clust * 2) + 4 + S_SIZ - 1) / S_SIZ;
+      n_rsv = 1 + partition;
+      n_dir = N_ROOTDIR * 32 / S_SIZ;
+      break;
+    default:
+      n_fat = ((n_clust * 4) + 8 + S_SIZ - 1) / S_SIZ;
+      n_rsv = 33 - partition;
+      n_dir = 0;
+  }
+  b_fat = b_part + n_rsv;                      /* FATs start sector */
+  b_dir = b_fat + n_fat * N_FATS;      /* Directory start sector */
+  b_data = b_dir + n_dir;                      /* Data start sector */
+
+#ifdef ERASE_BLK
+  /* Round up data start sector to erase block boundary */
+  n = (b_data + ERASE_BLK - 1) & ~(ERASE_BLK - 1);
+  b_dir += n - b_data;
+  n_fat += (n - b_data) / N_FATS;
+#endif
+  /* Determine number of cluster and final check of validity of the FAT type */
+  n_clust = (n_part - n_rsv - n_fat * 2 - n_dir) / allocsize;
+  if (   (fmt == FS_FAT16 && n_clust < 0xFF7)
+      || (fmt == FS_FAT32 && n_clust < 0xFFF7))
+  { // ###
+    // printf ("line %d: fmt=%d, FS_FAT16=%d, FS_FAT32=%d, n_clust=0x%x\n", __LINE__, fmt, FS_FAT16, FS_FAT32, n_clust); // ###
+    return FR_MKFS_ABORTED;
+  } // ###
+
+  /* Create partition table if needed */
+  if (!partition) {
+    U32 n_disk = b_part + n_part;
+
+    tbl = &fs->win[MBR_Table];
+    ST_U32(&tbl[0], 0x00010180);       /* Partition start in CHS */
+    if (n_disk < 63UL * 255 * 1024) {  /* Partition end in CHS */
+      n_disk = n_disk / 63 / 255;
+      tbl[7] = (U8)n_disk;
+      tbl[6] = (U8)((n_disk >> 2) | 63);
+    } else {
+      ST_U16(&tbl[6], 0xFFFF);
+    }
+    tbl[5] = 254;
+    if (fmt != FS_FAT32)                       /* System ID */
+      tbl[4] = (n_part < 0x10000) ? 0x04 : 0x06;
+    else
+      tbl[4] = 0x0c;
+    ST_U32(&tbl[8], 63);                       /* Partition start in LBA */
+    ST_U32(&tbl[12], n_part);          /* Partition size in LBA */
+    ST_U16(&tbl[64], 0xAA55);          /* Signature */
+    if (diskWrite(drv, fs->win, 0, 1) != RES_OK)
+      return FR_RW_ERROR;
+  }
+
+  /* Create boot record */
+  memset(tbl = fs->win, 0, S_SIZ);
+  ST_U32(&tbl[BS_jmpBoot], 0x90FEEB);          /* Boot code (jmp $, nop) */
+  ST_U16(&tbl[BPB_BytsPerSec], S_SIZ);         /* Sector size */
+  tbl[BPB_SecPerClus] = (U8)allocsize;         /* Sectors per cluster */
+  ST_U16(&tbl[BPB_RsvdSecCnt], n_rsv);         /* Reserved sectors */
+  tbl[BPB_NumFATs] = N_FATS;                                   /* Number of FATs */
+  ST_U16(&tbl[BPB_RootEntCnt], S_SIZ / 32 * n_dir); /* Number of rootdir entries */
+  if (n_part < 0x10000) {                                              /* Number of total sectors */
+    ST_U16(&tbl[BPB_TotSec16], n_part);
+  } else {
+    ST_U32(&tbl[BPB_TotSec32], n_part);
+  }
+  tbl[BPB_Media] = 0xF8;                                               /* Media descripter */
+  ST_U16(&tbl[BPB_SecPerTrk], 63);                     /* Number of sectors per track */
+  ST_U16(&tbl[BPB_NumHeads], 255);                     /* Number of heads */
+  ST_U32(&tbl[BPB_HiddSec], b_part);           /* Hidden sectors */
+  if (fmt != FS_FAT32) {
+    ST_U16(&tbl[BPB_FATSz16], n_fat);          /* Number of secters per FAT */
+    tbl[BS_DrvNum] = 0x80;                                     /* Drive number */
+    tbl[BS_BootSig] = 0x29;                                    /* Extended boot signature */
+    memcpy(&tbl[BS_VolLab], "NO NAME    FAT     ", 19);        /* Volume lavel, FAT signature */
+  } else {
+    ST_U32(&tbl[BPB_FATSz32], n_fat);          /* Number of secters per FAT */
+    ST_U32(&tbl[BPB_RootClus], 2);             /* Root directory cluster (2) */
+    ST_U16(&tbl[BPB_FSInfo], 1);                       /* FSInfo record (bs+1) */
+    ST_U16(&tbl[BPB_BkBootSec], 6);            /* Backup boot record (bs+6) */
+    tbl[BS_DrvNum32] = 0x80;                           /* Drive number */
+    tbl[BS_BootSig32] = 0x29;                          /* Extended boot signature */
+    memcpy(&tbl[BS_VolLab32], "NO NAME    FAT32   ", 19);      /* Volume lavel, FAT signature */
+  }
+  ST_U16(&tbl[BS_55AA], 0xAA55);                       /* Signature */
+  if (diskWrite(drv, tbl, b_part+0, 1) != RES_OK)
+    return FR_RW_ERROR;
+  if (fmt == FS_FAT32)
+    diskWrite(drv, tbl, b_part+6, 1);
+
+  /* Initialize FAT area */
+  for (m = 0; m < N_FATS; m++) {
+    memset(tbl, 0, S_SIZ);             /* 1st sector of the FAT  */
+    if (fmt != FS_FAT32) {
+      n = (fmt == FS_FAT12) ? 0x00FFFFF8 : 0xFFFFFFF8;
+      ST_U32(&tbl[0], n);                      /* Reserve cluster #0-1 (FAT12/16) */
+    } else {
+      ST_U32(&tbl[0], 0xFFFFFFF8);     /* Reserve cluster #0-1 (FAT32) */
+      ST_U32(&tbl[4], 0xFFFFFFFF);
+      ST_U32(&tbl[8], 0x0FFFFFFF);     /* Reserve cluster #2 for root dir */
+    }
+    if (diskWrite(drv, tbl, b_fat++, 1) != RES_OK)
+      return FR_RW_ERROR;
+    memset(tbl, 0, S_SIZ);             /* Following FAT entries are filled by zero */
+    for (n = 1; n < n_fat; n++) {
+      if (diskWrite(drv, tbl, b_fat++, 1) != RES_OK)
+        return FR_RW_ERROR;
+    }
+  }
+
+  /* Initialize Root directory */
+  for (m = 0; m < 64; m++) {
+    if (diskWrite(drv, tbl, b_fat++, 1) != RES_OK)
+      return FR_RW_ERROR;
+  }
+
+  /* Create FSInfo record if needed */
+  if (fmt == FS_FAT32) {
+    ST_U16(&tbl[BS_55AA], 0xAA55);
+    ST_U32(&tbl[FSI_LeadSig], 0x41615252);
+    ST_U32(&tbl[FSI_StrucSig], 0x61417272);
+    ST_U32(&tbl[FSI_Free_Count], n_clust - 1);
+    ST_U32(&tbl[FSI_Nxt_Free], 0xFFFFFFFF);
+    diskWrite(drv, tbl, b_part+1, 1);
+    diskWrite(drv, tbl, b_part+7, 1);
+  }
+
+  return (diskIoctl(drv, CTRL_SYNC, NULL) == RES_OK) ? FR_OK : FR_RW_ERROR;
+}
+
+#endif /* _USE_MKFS */
+#endif /* !_FS_READONLY */
+#endif /* _FS_MINIMIZE == 0 */
+#endif /* _FS_MINIMIZE <= 1 */
+#endif /* _FS_MINIMIZE <= 2 */
+
diff --git a/fatfs/ff.h b/fatfs/ff.h
new file mode 100644 (file)
index 0000000..70d64d9
--- /dev/null
@@ -0,0 +1,338 @@
+/*--------------------------------------------------------------------------/
+/  FatFs - FAT file system module include file  R0.04b       (C)ChaN, 2007
+/---------------------------------------------------------------------------/
+/ FatFs module is an experimenal project to implement FAT file system to
+/ cheap microcontrollers. This is a free software and is opened for education,
+/ research and development under license policy of following trems.
+/
+/  Copyright (C) 2007, ChaN, all right reserved.
+/
+/ * The FatFs module is a free software and there is no warranty.
+/ * You can use, modify and/or redistribute it for personal, non-profit or
+/   profit use without any restriction under your responsibility.
+/ * Redistributions of source code must retain the above copyright notice.
+/
+/---------------------------------------------------------------------------*/
+
+#ifndef _FATFS_H_
+#define _FATFS_H_
+
+#define _MCU_ENDIAN 2
+/* The _MCU_ENDIAN defines which access method is used to the FAT structure.
+/  1: Enable word access.
+/  2: Disable word access and use byte-by-byte access instead.
+/  When the architectural byte order of the MCU is big-endian and/or address
+/  miss-aligned access is prohibited, the _MCU_ENDIAN must be set to 2.
+/  If it is not the case, it can be set to 1 for good code efficiency. */
+
+#define _FS_READONLY    0
+/* Setting _FS_READONLY to 1 defines read only configuration. This removes
+/  writing functions, f_write, f_sync, f_unlink, f_mkdir, f_chmod, f_rename
+/  and useless f_getfree. */
+
+#define _FS_MINIMIZE    0
+/* The _FS_MINIMIZE option defines minimization level to remove some functions.
+/  0: Full function.
+/  1: f_stat, f_getfree, f_unlink, f_mkdir, f_chmod and f_rename are removed.
+/  2: f_opendir and f_readdir are removed in addition to level 1.
+/  3: f_lseek is removed in addition to level 2. */
+
+#define _DRIVES     1
+/* Number of logical drives to be used. This affects the size of internal table. */
+
+#define _USE_MKFS   1
+/* When _USE_MKFS is set to 1 and _FS_READONLY is set to 0, f_mkfs function is
+/  enabled. */
+
+#define _MULTI_PARTITION    0
+/* When _MULTI_PARTITION is set to 0, each logical drive is bound to same
+/  physical drive number and can mount only 1st primaly partition. When it is
+/  set to 1, each logical drive can mount a partition listed in Drives[]. */
+
+#define _USE_FSINFO 1
+/* To enable FSInfo support on FAT32 volume, set _USE_FSINFO to 1. */
+
+#define _USE_SJIS   1
+/* When _USE_SJIS is set to 1, Shift-JIS code transparency is enabled, otherwise
+/  only US-ASCII(7bit) code can be accepted as file/directory name. */
+
+#define _USE_NTFLAG 1
+/* When _USE_NTFLAG is set to 1, upper/lower case of the file name is preserved.
+/  Note that the files are always accessed in case insensitive. */
+
+#include "sysdefs.h"
+
+//
+//  Definitions corresponds to multiple sector size (not tested) 
+//
+#define S_MAX_SIZ   512         /* Do not change */
+#if S_MAX_SIZ > 512
+#define S_SIZ   (fs->s_size)
+#else
+#define S_SIZ   512
+#endif
+
+//
+//  File system object structure 
+//
+typedef struct _FATFS
+{
+    U16 id;             /* File system mount ID */
+    U16 n_rootdir;      /* Number of root directory entries */
+    U32 winsect;        /* Current sector appearing in the win[] */
+    U32 sects_fat;      /* Sectors per fat */
+    U32 max_clust;      /* Maximum cluster# + 1 */
+    U32 fatbase;        /* FAT start sector */
+    U32 dirbase;        /* Root directory start sector (cluster# for FAT32) */
+    U32 database;       /* Data start sector */
+#if _FS_READONLY == 0
+    U32 last_clust;     /* Last allocated cluster */
+    U32 free_clust;     /* Number of free clusters */
+#if _USE_FSINFO
+    U32 fsi_sector;     /* fsinfo sector */
+    U8  fsi_flag;       /* fsinfo dirty flag (1:must be written back) */
+    U8  pad2;
+#endif
+#endif
+    U8  fs_type;        /* FAT sub type */
+    U8  sects_clust;    /* Sectors per cluster */
+#if S_MAX_SIZ > 512
+    U16 s_size;         /* Sector size */
+#endif
+    U8  n_fats;         /* Number of FAT copies */
+    U8  drive;          /* Physical drive number */
+    U8  winflag;        /* win[] dirty flag (1:must be written back) */
+    U8  pad1;
+    U8  win[S_MAX_SIZ]; /* Disk access window for Directory/FAT */
+} 
+/* __attribute__ ((packed)) */ FATFS;
+
+//
+//  Directory object structure 
+//
+typedef struct _DIR 
+{
+    U16 id;         /* Owner file system mount ID */
+    U16 index;      /* Current index */
+    FATFS*  fs;     /* Pointer to the owner file system object */
+    U32 sclust;     /* Start cluster */
+    U32 clust;      /* Current cluster */
+    U32 sect;       /* Current sector */
+} 
+/* __attribute__ ((packed)) */ DIR;
+
+//
+//  File object structure 
+//
+typedef struct _FIL 
+{
+    U16 id;             /* Owner file system mount ID */
+    U8  flag;           /* File status flags */
+    U8  sect_clust;     /* Left sectors in cluster */
+    FATFS* fs;          /* Pointer to the owner file system object */
+    U32 fptr;           /* File R/W pointer */
+    U32 fsize;          /* File size */
+    U32 org_clust;      /* File start cluster */
+    U32 curr_clust;     /* Current cluster */
+    U32 curr_sect;      /* Current sector */
+#if _FS_READONLY == 0
+    U32 dir_sect;       /* Sector containing the directory entry */
+    U8* dir_ptr;        /* Ponter to the directory entry in the window */
+#endif
+    U8  buffer [S_MAX_SIZ];  /* File R/W buffer */
+} 
+/* __attribute__ ((packed)) */ FIL;
+
+//
+//  File status structure 
+//
+typedef struct _FILINFO 
+{
+    U32 fsize;              /* Size */
+    U16 fdate;              /* Date */
+    U16 ftime;              /* Time */
+    U8 fattrib;             /* Attribute */
+    char fname [8+1+3+1];   /* Name (8.3 format) */
+} 
+/* __attribute__ ((packed)) */ FILINFO;
+
+//
+//  Definitions corresponds to multi partition 
+//
+#if _MULTI_PARTITION != 0   /* Multiple partition cfg */
+
+typedef struct _PARTITION 
+{
+    U8 pd;  /* Physical drive # (0-255) */
+    U8 pt;  /* Partition # (0-3) */
+} 
+/* __attribute__ ((packed)) */ PARTITION;
+
+extern const PARTITION Drives [];   /* Logical drive# to physical location conversion table */
+#define LD2PD(drv) (Drives[drv].pd) /* Get physical drive# */
+#define LD2PT(drv) (Drives[drv].pt) /* Get partition# */
+
+#else                       /* Single partition cfg */
+
+#define LD2PD(drv) (drv)        /* Physical drive# is equal to logical drive# */
+#define LD2PT(drv) 0            /* Always mounts the 1st partition */
+
+#endif
+
+//
+//  File function return code (FRESULT) 
+//
+typedef enum 
+{
+    FR_OK = 0,          /* 0 */
+    FR_NOT_READY,       /* 1 */
+    FR_NO_FILE,         /* 2 */
+    FR_NO_PATH,         /* 3 */
+    FR_INVALID_NAME,    /* 4 */
+    FR_INVALID_DRIVE,   /* 5 */
+    FR_DENIED,          /* 6 */
+    FR_EXIST,           /* 7 */
+    FR_RW_ERROR,        /* 8 */
+    FR_WRITE_PROTECTED, /* 9 */
+    FR_NOT_ENABLED,     /* 10 */
+    FR_NO_FILESYSTEM,   /* 11 */
+    FR_INVALID_OBJECT,  /* 12 */
+    FR_MKFS_ABORTED     /* 13 */
+} 
+FRESULT;
+
+//
+//  FatFs module application interface
+//
+void    f_printerror (FRESULT f);               /* Print error code */
+FRESULT f_mount (U8, FATFS*);                   /* Mount/Unmount a logical drive */
+FRESULT f_open (FIL*, const char*, U8);         /* Open or create a file */
+FRESULT f_read (FIL*, void*, U16, U16*);        /* Read data from a file */
+FRESULT f_write (FIL*, const void*, U16, U16*); /* Write data to a file */
+FRESULT f_lseek (FIL*, U32);                    /* Move file pointer of a file object */
+FRESULT f_close (FIL*);                         /* Close an open file object */
+FRESULT f_opendir (DIR*, const char*);          /* Open an existing directory */
+FRESULT f_readdir (DIR*, FILINFO*);             /* Read a directory item */
+FRESULT f_stat (const char*, FILINFO*);         /* Get file status */
+FRESULT f_getfree (const char*, U32*, FATFS**); /* Get number of free clusters on the drive */
+FRESULT f_sync (FIL*);                          /* Flush cached data of a writing file */
+FRESULT f_unlink (const char*);                 /* Delete an existing file or directory */
+FRESULT f_mkdir (const char*);                  /* Create a new directory */
+FRESULT f_chmod (const char*, U8, U8);          /* Change file/dir attriburte */
+FRESULT f_rename (const char*, const char*);    /* Rename/Move a file or directory */
+FRESULT f_mkfs (U8, U8, U8);                    /* Create a file system on the drive */
+
+//
+//  User defined function to give a current time to fatfs module 
+//
+U32 get_fattime (void); /* 31-25: Year(0-127 org.1980), 24-21: Month(1-12), 20-16: Day(1-31) */
+                        /* 15-11: Hour(0-23), 10-5: Minute(0-59), 4-0: Second(0-29 *2) */
+
+//
+//  File access control and file status flags (FIL.flag)
+//
+#define FA_OPEN_EXISTING    0x00
+#define FA_READ             0x01
+#if _FS_READONLY == 0
+#define FA_WRITE            0x02
+#define FA_CREATE_NEW       0x04
+#define FA_CREATE_ALWAYS    0x08
+#define FA_OPEN_ALWAYS      0x10
+#define FA__WRITTEN         0x20
+#define FA__DIRTY           0x40
+#endif
+#define FA__ERROR           0x80
+
+//
+//  FAT sub type (FATFS.fs_type) 
+//
+#define FS_FAT12    1
+#define FS_FAT16    2
+#define FS_FAT32    3
+
+//
+//  File attribute bits for directory entry 
+//
+#define AM_RDO  0x01    /* Read only */
+#define AM_HID  0x02    /* Hidden */
+#define AM_SYS  0x04    /* System */
+#define AM_VOL  0x08    /* Volume label */
+#define AM_LFN  0x0F    /* LFN entry */
+#define AM_DIR  0x10    /* Directory */
+#define AM_ARC  0x20    /* Archive */
+
+//
+//  Offset of FAT structure members 
+//
+#define BS_jmpBoot          0
+#define BS_OEMName          3
+#define BPB_BytsPerSec      11
+#define BPB_SecPerClus      13
+#define BPB_RsvdSecCnt      14
+#define BPB_NumFATs         16
+#define BPB_RootEntCnt      17
+#define BPB_TotSec16        19
+#define BPB_Media           21
+#define BPB_FATSz16         22
+#define BPB_SecPerTrk       24
+#define BPB_NumHeads        26
+#define BPB_HiddSec         28
+#define BPB_TotSec32        32
+#define BS_55AA             510
+
+#define BS_DrvNum           36
+#define BS_BootSig          38
+#define BS_VolID            39
+#define BS_VolLab           43
+#define BS_FilSysType       54
+
+#define BPB_FATSz32         36
+#define BPB_ExtFlags        40
+#define BPB_FSVer           42
+#define BPB_RootClus        44
+#define BPB_FSInfo          48
+#define BPB_BkBootSec       50
+#define BS_DrvNum32         64
+#define BS_BootSig32        66
+#define BS_VolID32          67
+#define BS_VolLab32         71
+#define BS_FilSysType32     82
+
+#define FSI_LeadSig         0
+#define FSI_StrucSig        484
+#define FSI_Free_Count      488
+#define FSI_Nxt_Free        492
+
+#define MBR_Table           446
+
+#define DIR_Name            0
+#define DIR_Attr            11
+#define DIR_NTres           12
+#define DIR_CrtTime         14
+#define DIR_CrtDate         16
+#define DIR_FstClusHI       20
+#define DIR_WrtTime         22
+#define DIR_WrtDate         24
+#define DIR_FstClusLO       26
+#define DIR_FileSize        28
+
+//
+//  Multi-byte word access macros  
+//  
+#if _MCU_ENDIAN == 1    /* Use word access */
+#define LD_U16(ptr)     (U16)(*(U16*)(U8*)(ptr))
+#define LD_U32(ptr)     (U32)(*(U32*)(U8*)(ptr))
+#define ST_U16(ptr,val) *(U16*)(U8*)(ptr)=(U16)(val)
+#define ST_U32(ptr,val) *(U32*)(U8*)(ptr)=(U32)(val)
+#else
+#if _MCU_ENDIAN == 2    /* Use byte-by-byte access */
+#define LD_U16(ptr)     (U16)(((U16)*(U8*)((ptr)+1)<<8)|(U16)*(U8*)(ptr))
+#define LD_U32(ptr)     (U32)(((U32)*(U8*)((ptr)+3)<<24)|((U32)*(U8*)((ptr)+2)<<16)|((U16)*(U8*)((ptr)+1)<<8)|*(U8*)(ptr))
+#define ST_U16(ptr,val) *(U8*)(ptr)=(U8)(val); *(U8*)((ptr)+1)=(U8)((U16)(val)>>8)
+#define ST_U32(ptr,val) *(U8*)(ptr)=(U8)(val); *(U8*)((ptr)+1)=(U8)((U16)(val)>>8); *(U8*)((ptr)+2)=(U8)((U32)(val)>>16); *(U8*)((ptr)+3)=(U8)((U32)(val)>>24)
+#else
+#error Do not forget to set _MCU_ENDIAN properly!
+#endif
+#endif
+
+#endif
diff --git a/fatfs/mmc.c b/fatfs/mmc.c
new file mode 100644 (file)
index 0000000..70b5f36
--- /dev/null
@@ -0,0 +1,944 @@
+/*************************************************************************
+ *
+ *    Used with ICCARM and AARM.
+ *
+ *    (c) Copyright IAR Systems 2005
+ *
+ *    File name   : mmc.c
+ *    Description : MMC
+ *
+ *    History :
+ *    1. Data        : July 1, 2005
+ *       Author      : Stanimir Bonev
+ *       Description : Create
+ *
+ *    $Revision: 1.4 $
+ *
+ * (C) Joel Winarske, 2006,2007                                        
+**************************************************************************/
+#include <stdio.h> // ###
+#include "disk.h"
+#include "diskio.h"
+#include "mmc.h"
+#include "spi.h"
+
+#define MMC_RET_ERROR(Res)          do { mmcLastError = Res; return (MmcCardError); } while (0)
+#define MMC_RET_DATA_ERR(Res)       do { mmcLastError = Res; return (MmcDataError); } while (0)
+
+#define CSD_GET_TRAN_SPEED_EXP()      (mmcSdCsd [ 3] & 0x07)
+#define CSD_GET_TRAN_SPEED_MANT()    ((mmcSdCsd [ 3] & 0xF8) >> 3)
+#define CSD_GET_NSAC()                (mmcSdCsd [ 2])
+#define CSD_GET_TAAC_EXP()            (mmcSdCsd [ 1] & 0x7)
+#define CSD_GET_TAAC_MANT()          ((mmcSdCsd [ 1] & 0xF8) >> 3)
+#define CSD_GET_R2W_FACTOR()         ((mmcSdCsd [12] & 0x1C) >> 2)
+#define CSD_GET_READ_BL_LEN()         (mmcSdCsd [ 5] & 0x0F)
+#define CSD_GET_C_SIZE()            (((mmcSdCsd [ 6] & 0x03) << 10) + (mmcSdCsd [7] << 2) + ((mmcSdCsd [8] & 0xc0) >> 6))
+#define CSD_GET_C_SIZE_MULT()       (((mmcSdCsd [ 9] & 0x03) << 1) + ((mmcSdCsd [10] & 0x80) >> 7))
+#define CSD_GET_PERM_WRITE_PROTECT() ((mmcSdCsd [14] & 0x20) >> 5)
+#define CSD_GET_TMP_WRITE_PROTECT()  ((mmcSdCsd [14] & 0x10) >> 4)
+
+static const U32 mmcTransfExp [] =
+{
+     10000UL,
+    100000UL,
+   1000000UL,
+  10000000UL,
+         0UL,
+         0UL,
+         0UL,
+         0UL,
+};
+
+static const U32 mmmcAccessTime [] =
+{
+ 10000000UL,
+  1000000UL,
+   100000UL,
+    10000UL,
+     1000UL,
+      100UL,
+       10UL,
+        1UL,
+};
+
+static const U32 mmcCsdMant [] =
+{
+  0UL,10UL,12UL,13UL,15UL,
+  20UL,25UL,
+  30UL,35UL,
+  40UL,45UL,
+  50UL,55UL,
+  60UL,
+  70UL,
+  80UL,
+};
+
+static const U32 mmcAccessTimeMant [] =
+{
+  0UL,100UL,83UL,77UL,67UL,
+  50UL,40UL,
+  33UL,29UL,
+  25UL,22UL,
+  20UL,18UL,
+  17UL,
+  14UL,
+  13UL,
+};
+
+static const mmcCommads_t mmcCmd [CMD_END] =
+{
+  { 0x40, MmcNoArg,     MmcR1 }, // CMD0
+  { 0x41, MmcNoArg,     MmcR1 }, // CMD1
+  { 0x49, MmcNoArg,     MmcR1 }, // CMD9
+  { 0x4A, MmcNoArg,     MmcR1 }, // CMD10
+  { 0x4C, MmcNoArg,     MmcR1 }, // CMD12
+  { 0x4D, MmcNoArg,     MmcR2 }, // CMD13
+  { 0x50, MmcBlockLen,  MmcR1 }, // CMD16
+  { 0x51, MmcDataAdd,   MmcR1 }, // CMD17
+  { 0x52, MmcDataAdd,   MmcR1 }, // CMD18
+  { 0x58, MmcDataAdd,   MmcR1 }, // CMD24
+  { 0x59, MmcDataAdd,   MmcR1 }, // CMD25
+  { 0x5B, MmcNoArg,     MmcR1 }, // CMD27
+  { 0x5C, MmcDataAdd,   MmcR1b}, // CMD28
+  { 0x5D, MmcDataAdd,   MmcR1b}, // CMD29
+  { 0x5E, MmcDataAdd,   MmcR1 }, // CMD30
+  { 0x60, MmcDataAdd,   MmcR1 }, // CMD32
+  { 0x61, MmcDataAdd,   MmcR1 }, // CMD33
+  { 0x62, MmcDataAdd,   MmcR1 }, // CMD34
+  { 0x63, MmcDataAdd,   MmcR1 }, // CMD35
+  { 0x64, MmcDataAdd,   MmcR1 }, // CMD36
+  { 0x65, MmcDataAdd,   MmcR1 }, // CMD37
+  { 0x66, MmcDummyWord, MmcR1b}, // CMD38
+  { 0x6A, MmcDummyWord, MmcR1b}, // CMD42
+  { 0x77, MmcNoArg,     MmcR1 }, // CMD55
+  { 0x78, MmcNoArg,     MmcR1 }, // CMD56
+  { 0x7A, MmcNoArg,     MmcR3 }, // CMD58
+  { 0x7B, MmcDummyWord, MmcR1 }, // CMD59
+  { 0x69, MmcNoArg,     MmcR1 } // ACMD41
+};
+
+static volatile DSTATUS Stat = STA_NOINIT;  /* Disk status */
+static DiskStatus_t mmcDskStatus;
+static U32 mmcLastError; 
+static U32 Tnac;
+static U32 Twr;
+static U8 mmcSdCsd [16];
+
+//
+//
+//
+static U32 mmcSendCmd (mmcSpiCmdInd_t ComdInd, U32 Arg);
+static U32 mmcSetBlockLen (U32 length);
+static void mmcCSDImplement (void);
+static mmcState_t mmcInitMedia (void);
+static mmcState_t mmcReadCardInfo (U8 *pData, mmcSpiCmdInd_t Command);
+static inline mmcState_t mmcRead (U8 *pData, U32 Add, U32 Length);
+static inline mmcState_t mmcWrite (U8 *pData, U32 Add, U32 Length);
+static inline mmcState_t mmcVerify (U8 *pData, U32 Add, U32 Length);
+
+/*************************************************************************
+ * Function Name: mmcSendCmd
+ * Parameters: MmcSpiCmdInd_t ComdInd,U32 Arg
+ *
+ * Return: U32
+ *
+ * Description: MMC commands implemet
+ *
+ *************************************************************************/
+static U32 mmcSendCmd (mmcSpiCmdInd_t ComdInd, U32 Arg)
+{
+  U32 ch = 0xff;
+  U32 i;
+
+  //
+  //  Chip Select
+  //
+  spiChipSelect (1);
+
+  //
+  //  Send command code
+  //
+  spiTransferByte (mmcCmd [ComdInd].TxData);
+
+  //
+  //  Send command's arguments
+  //
+  if (mmcCmd [ComdInd].Arg == MmcNoArg)
+  {
+    spiTransferByte (0x00);
+    spiTransferByte (0x00);
+    spiTransferByte (0x00);
+    spiTransferByte (0x00);
+  }
+  else
+  {
+    spiTransferByte (Arg >> 24);
+    spiTransferByte (Arg >> 16);
+    spiTransferByte (Arg >> 8);
+    spiTransferByte (Arg);
+  }
+
+  //
+  //  Send CRC
+  //
+  if (ComdInd == CMD0)
+    spiTransferByte (0x95);
+  else
+    spiTransferByte (0xff);
+
+  for (i = 9; i && (ch == 0xff); --i) 
+    ch = spiTransferByte (0xff);
+
+  if (i == 0)
+  {
+    spiChipSelect (0);
+    return ((U32) -1);
+  }
+
+  switch (mmcCmd [ComdInd].Resp)
+  {
+    case MmcR1b :
+      {
+        U32 busy;
+
+        for (busy = 0, i = Twr; i && (busy != 0xff); --i)
+          busy = spiTransferByte (0xff);
+      }
+      return (ch);
+
+    case MmcR1 :
+      return (ch);
+
+    case MmcR2 :
+      Arg  = ((U32) ch << 8) & 0x0000FF00;
+      Arg |= spiTransferByte (0xff) & 0xff;
+      return (Arg);
+
+    case MmcR3 :
+    default:
+      Arg  = ((U32) ch << 24) & 0xff000000;
+      Arg |= ((U32) spiTransferByte (0xff) << 16) & 0x00FF0000;
+      Arg |= ((U32) spiTransferByte (0xff) << 8 ) & 0x0000FF00;
+      Arg |= spiTransferByte (0xff) & 0xff;
+      return (Arg);
+  }
+}
+
+/*************************************************************************
+ * Function Name: mmcSetBlockLen
+ * Parameters: U32 Length
+ *
+ * Return: U32
+ *
+ * Description: Set Block length Return command's result
+ *
+ *************************************************************************/
+static U32 mmcSetBlockLen (U32 length)
+{
+  U32 res = mmcSendCmd (CMD16, length);
+  spiChipSelect (0);
+  return (res);
+}
+
+/*************************************************************************
+ * Function Name: mmcCSDImplement
+ * Parameters:  none
+ *
+ * Return: none
+ *
+ * Description: Implemet data from CSD
+ *
+ *************************************************************************/
+static void mmcCSDImplement (void)
+{
+  U32 frequency;
+
+  //
+  // Calculate SPI max clock
+  //
+  frequency = mmcTransfExp [CSD_GET_TRAN_SPEED_EXP ()] * mmcCsdMant [CSD_GET_TRAN_SPEED_MANT ()];
+
+  if (frequency > 20000000)
+    frequency = 20000000;
+
+  frequency = spiSetClockFreq (frequency);
+
+  if (mmcDskStatus.DiskType == DiskMMC)
+  {
+    Tnac = mmmcAccessTime [CSD_GET_TAAC_EXP ()] * mmcAccessTimeMant [CSD_GET_TAAC_MANT ()];
+    Tnac = frequency / Tnac;
+    Tnac += 1 << (CSD_GET_NSAC () + 4);
+    Tnac *= 10;
+    Twr   = Tnac * CSD_GET_R2W_FACTOR ();
+  }
+  else
+  {
+    Tnac = frequency / SD_READ_TIME_OUT;
+    Twr  = frequency / SD_WRITE_TIME_OUT;
+  }
+
+  mmcDskStatus.BlockSize = 1 << CSD_GET_READ_BL_LEN ();
+  mmcDskStatus.BlockNumb = (CSD_GET_C_SIZE () + 1) * (4 << CSD_GET_C_SIZE_MULT ());
+  mmcDskStatus.WriteProtect = spiWriteProtect () | CSD_GET_PERM_WRITE_PROTECT () | CSD_GET_TMP_WRITE_PROTECT ();
+}
+
+/*************************************************************************
+ * Function Name: mmcInitMedia
+ * Parameters: none
+ *
+ * Return: mmcState_t
+ *
+ * Description: MMC detect and initialize
+ *
+ *************************************************************************/
+static mmcState_t mmcInitMedia (void)
+{
+  U32 i;
+  U32 res;
+
+  Tnac = 1;
+
+  if (!spiPresent ())
+    return (MmcNoPresent);
+
+  //
+  //  Clock Freq. Identification Mode < 400kHz
+  //
+  spiSetClockFreq (IdentificationModeClock);
+
+  //
+  //  Set maximum time out
+  //
+  Tnac = IdentificationModeClock / SD_READ_TIME_OUT;
+
+  //
+  //  Power up cycles.  After power up at least 74 clock cycles are required 
+  //  prior to starting bus communication
+  //
+  for (i = 0; i < 2; i++)
+  {
+    spiChipSelect (0);
+
+    for (res = 10; res; --res)
+      spiTransferByte (0xff);
+
+    //
+    //  CMD0 (Go to IDLE) to put MMC in SPI mode
+    //
+    res = mmcSendCmd (CMD0, 0);
+    spiChipSelect (0);
+
+    if (res == MMC_IDLE_STATE)
+      break;
+  }
+
+  if (res != MMC_IDLE_STATE)
+    return (MmcNoResponse);
+
+  //
+  //  Determinate Card type SD or MMC
+  //
+  mmcDskStatus.DiskType = DiskMMC;
+
+  for (i = 100; i; --i)
+  {
+    spiChipSelect (0);
+    spiTransferByte (0xff);
+    res = mmcSendCmd (CMD55, 0);
+    spiChipSelect (0);
+    spiChipSelect (0);
+    spiTransferByte (0xff);
+    res = mmcSendCmd (ACMD41, 0);
+    spiChipSelect (0);
+
+    if (res & MMC_ILLEGAL_CMD)
+    {
+      //
+      //  MMC card may be CMD1 for MMC Init sequence will be complete within 500ms
+      //
+      for (i = 100; i; --i)
+      {
+        spiChipSelect (0);
+        spiTransferByte (0xff);
+        res = mmcSendCmd (CMD1, 0);
+        spiChipSelect (0);
+
+        if (res == MMC_OK)
+          break;
+
+        spiDelay1ms (50);
+      }
+      break;
+    }
+
+    if (res == MMC_OK)
+    {
+      mmcDskStatus.DiskType = DiskSD;
+      break;
+    }
+
+    spiDelay1ms (50);
+  }
+
+  if (i == 0)
+    return (MmcNoResponse);
+
+  //
+  //  Read CSD.  CSD must always be valid
+  //
+  if ((res = mmcReadCardInfo (mmcSdCsd, CMD9)) != MmcOk)
+    return (MmcNoResponse);
+
+  //
+  //  Implement CSD data, and set block size
+  //
+  mmcCSDImplement ();
+  mmcSetBlockLen (mmcDskStatus.BlockSize);
+
+  // mmcDecode (mmcSdCsd); // ###
+
+  return (MmcOk);
+}
+
+/*************************************************************************
+ * Function Name: mmcReadCardInfo
+ * Parameters: U8 *pData,
+ *             mmcSpiCmdInd_t Command - CMD9, CMD10 are only allowed
+ *
+ * Return: mmcState_t
+ *
+ * Description: Read CSD or CID  registers depend of commoand
+ *
+ *************************************************************************/
+static mmcState_t mmcReadCardInfo (U8 *pData, mmcSpiCmdInd_t Command)
+{
+  U32 i;
+  U32 res;
+
+  switch (Command)
+  {
+    case CMD9 :
+    case CMD10 :
+      break;
+
+    default:
+      return (MmmcParameterError);
+  }
+
+  spiChipSelect (0);
+  spiTransferByte (0xff);
+
+  if ((res = mmcSendCmd (Command, 0)) == MMC_OK)
+  {
+    for (i = 8; i ; --i)
+    {
+      if (((res = spiTransferByte (0xff)) | MMC_DATA_ERR_TOKEN) == MMC_DATA_ERR_TOKEN)
+      {
+        // printf ("line %d: spiTransferByte returned 0x%x\n", __LINE__, res); // ###
+        MMC_RET_DATA_ERR (res);
+      }
+      else if (res == MMC_DATA_TOKEN)
+      {
+        for (i = 0; i <16 ; ++i)
+          *pData++ = spiTransferByte (0xff);
+
+        //
+        // CRC receive
+        //
+        spiTransferByte (0xff);
+        spiTransferByte (0xff);
+        spiChipSelect (0);
+        return (MmcOk);
+      }
+    }
+  }
+  // else
+  //   printf ("line %d: mmcSendCmd returned %d\n", __LINE__, res); // ###
+
+  spiChipSelect (0);
+  MMC_RET_ERROR (res);
+}
+
+/*************************************************************************
+ * Function Name: mmcRead
+ * Parameters: U8 *pData, U32 Add, U32 Length
+ *
+ * Return: mmcState_t
+ *
+ * Description: Read from a MMC
+ *
+ *************************************************************************/
+static inline mmcState_t mmcRead (U8 *pData, U32 Add, U32 Length)
+{
+  U32 res;
+  U32 i;
+
+  //
+  //  For synchronization
+  //
+  spiChipSelect (0);
+  spiTransferByte (0xff);
+  res = mmcSendCmd (CMD17, Add);
+
+  if (res == MMC_OK)
+  {
+    for (i = Tnac; i; --i)
+    {
+      res = spiTransferByte (0xff);
+
+      if ((res | MMC_DATA_ERR_TOKEN) == MMC_DATA_ERR_TOKEN)
+        MMC_RET_DATA_ERR (res);
+      else if (res == MMC_DATA_TOKEN)
+      {
+        spiReceiveBlock (pData, Length);
+
+        //
+        //  CRC receive
+        //
+        spiTransferByte (0xff);
+        spiTransferByte (0xff);
+        spiChipSelect (0);
+        return (MmcOk);
+      }
+    }
+
+    spiChipSelect (0);
+    return (MmcNoResponse);
+  }
+
+  spiChipSelect (0);
+  MMC_RET_ERROR (res);
+}
+
+/*************************************************************************
+ * Function Name: mmcWrite
+ * Parameters: U8 *pData, U32 Add, U32 Length
+ *
+ * Return: mmcState_t
+ *
+ * Description: Write to a MMC
+ *
+ *************************************************************************/
+static inline mmcState_t mmcWrite (U8 *pData, U32 Add, U32 Length)
+{
+  U32 res;
+  U32 i;
+
+  //
+  //  For synchronization
+  //
+  spiChipSelect (0);
+  spiTransferByte (0xff);
+
+  if ((res = mmcSendCmd (CMD24, Add)) == MMC_OK)
+  {
+    spiTransferByte (0xff);
+    spiTransferByte (MMC_DATA_TOKEN);
+    spiSendBlock (pData, Length);
+
+    //
+    //  CRC Send
+    //
+    spiTransferByte (0xff);
+    spiTransferByte (0xff);
+
+    if ((spiTransferByte (0xff) & 0x1F) != 0x05)
+      MMC_RET_ERROR (res);
+
+    for (i = Twr; i ;i--)
+      if (spiTransferByte (0xff) == 0xff)
+        break;
+    
+    spiChipSelect (0);
+
+    if (i == 0)
+      return (MmcNoResponse);
+
+    return (MmcOk);
+  }
+
+  spiChipSelect (0);
+  MMC_RET_ERROR (res);
+}
+
+/*************************************************************************
+ * Function Name: mmcVerify
+ * Parameters: U8 *pData, U32 Add, U32 Length
+ *
+ * Return: mmcState_t
+ *
+ * Description: Verify on a MMC
+ *
+ *************************************************************************/
+static inline mmcState_t mmcVerify (U8 *pData, U32 Add, U32 Length)
+{
+  U32 res,i;
+
+  //
+  //  For synchronization
+  //
+  spiChipSelect (0);
+  spiTransferByte (0xff);
+
+  if ((res = mmcSendCmd (CMD17, Add)) == MMC_OK)
+  {
+    for (i = Tnac; i; --i)
+    {
+      res = spiTransferByte (0xff);
+
+      if ((res | MMC_DATA_ERR_TOKEN) == MMC_DATA_ERR_TOKEN)
+        MMC_RET_DATA_ERR (res);
+      else if (res == MMC_DATA_TOKEN)
+      {
+        for (res = 0, i = 0; i < Length; ++i, ++pData)
+        {
+          *pData ^= spiTransferByte (0xff);
+
+          if (*pData != 0)
+            res = 1;
+        }
+
+        //
+        //  CRC receive
+        //
+        spiTransferByte (0xff);
+        spiTransferByte (0xff);
+        spiChipSelect (0);
+        spiTransferByte (0xff);
+        spiTransferByte (0xff);
+
+        if (res)
+          return (MmcMiscompare);
+
+        return (MmcOk);
+      }
+    }
+
+    return (MmcNoResponse);
+  }
+
+  MMC_RET_ERROR (res);
+}
+
+//
+//
+//
+DSTATUS diskInitialize (U8 drv __attribute__ ((unused)))
+{
+  mmcDskStatus.BlockNumb = mmcDskStatus.BlockSize = mmcLastError = 0;
+
+  //
+  //  Init SPI
+  //
+  spiInit ();
+
+  //
+  //  Media Init
+  //
+  switch (mmcInitMedia ())
+  {
+    case MmcOk :
+      {
+        mmcCSDImplement ();
+        mmcDskStatus.DiskStatus = DiskCommandPass;
+        mmcDskStatus.MediaChanged = TRUE;
+        Stat = 0;
+        if (mmcDskStatus.WriteProtect) 
+          Stat |= STA_PROTECT;
+      }
+      break;
+
+    case MmcCardError :
+    case MmcDataError :
+      {
+        mmcDskStatus.DiskStatus = DiskNotReady;
+        Stat = STA_NOINIT;
+        if (mmcDskStatus.WriteProtect) 
+          Stat |= STA_PROTECT;
+      }
+      break;
+
+    default:
+      {
+        mmcDskStatus.DiskStatus = DiskNotPresent;
+        Stat = STA_NODISK;
+      }
+      break;
+  }
+
+  return Stat;
+}
+
+//
+//
+//
+DSTATUS diskShutdown (void)
+{
+  Stat |= STA_NOINIT;
+
+  return Stat;
+}
+
+//
+//
+//
+DSTATUS diskStatus (U8 drv __attribute__ ((unused)))
+{
+  return Stat;
+}
+
+//
+//
+//
+DRESULT diskRead (U8 disk __attribute__ ((unused)), U8 *buff, U32 sector, U8 count)
+{
+  U32 res;
+
+  if (Stat & STA_NOINIT) 
+    return RES_NOTRDY;
+  if (!count) 
+    return RES_PARERR;
+
+  res = mmcRead (buff, sector * mmcDskStatus.BlockSize, count * mmcDskStatus.BlockSize);
+
+  if (res == MMC_OK)
+    return RES_OK;
+  else
+    return RES_ERROR; 
+}
+
+//
+//
+//
+#if _FS_READONLY == 0
+DRESULT diskWrite (U8 disk __attribute__ ((unused)), const U8 *buff, U32 sector, U8 count)
+{
+  U32 res;
+
+  if (Stat & STA_NOINIT) 
+    return RES_NOTRDY;
+  if (Stat & STA_PROTECT) 
+    return RES_WRPRT;
+  if (!count) 
+    return RES_PARERR;
+
+  res = mmcWrite ((U8 *) buff, sector * mmcDskStatus.BlockSize, count * mmcDskStatus.BlockSize);
+
+  if (res == MMC_OK)
+    return RES_OK;
+  else
+    return RES_ERROR; 
+}
+#endif
+
+//
+//
+//
+DRESULT diskIoctl (U8 drv, U8 ctrl, void *buff)
+{
+  DRESULT res;
+  U8 n;
+  U8 csd [16];
+  U16 csize;
+
+  if (drv) 
+    return RES_PARERR;
+  if (Stat & STA_NOINIT) 
+    return RES_NOTRDY;
+
+  res = RES_ERROR;
+
+  switch (ctrl) 
+  {
+    case GET_SECTOR_COUNT :
+      { 
+        mmcState_t jcwres; // ###
+        if ((jcwres = mmcReadCardInfo (csd, CMD9)) == MmcOk)                
+        {
+          //
+          //  SDC ver 2.00
+          //
+          if ((csd [0] >> 6) == 1) 
+          { 
+            csize = csd [9] + ((U16)csd [8] << 8) + 1;
+            *(U32 *) buff = (U32) csize << 10;
+          } 
+          //
+          //  MMC or SDC ver 1.XX
+          //
+          else 
+          {            
+            n = (csd [5] & 15) + ((csd [10] & 128) >> 7) + ((csd [9] & 3) << 1) + 2;
+            csize = (csd [8] >> 6) + ((U16) csd [7] << 2) + ((U16) (csd [6] & 3) << 10) + 1;
+            *(U32 *) buff = (U32) csize << (n - 9);
+          }
+
+          res = RES_OK;
+        }
+        // else // ###
+        // printf ("line %d: mmcReadCardInfo returned %d\n", __LINE__, jcwres); // ###
+      }
+      break;
+
+    case GET_SECTOR_SIZE :
+      {
+        *(U16 *) buff = 512;
+        res = RES_OK;
+      }
+      break;
+
+    case CTRL_SYNC :
+      {
+        if (spiWaitReady () == 0xff)
+          res = RES_OK;
+      }
+      break;
+
+    case MMC_GET_CSD :
+      {
+        if (mmcReadCardInfo (buff, CMD9) == MmcOk)
+          res = RES_OK;
+      }
+      break;
+
+    case MMC_GET_CID :
+      {
+        if (mmcReadCardInfo (buff, CMD10) == MmcOk)
+          res = RES_OK;
+      }
+      break;
+
+# if 0
+    case CTRL_POWER:
+    case CTRL_LOCK:
+    case CTRL_EJECT:
+    case MMC_GET_OCR:     /* Receive OCR as an R3 resp (4 bytes) */
+    case ATA_GET_REV:
+    case ATA_GET_MODEL:
+    case ATA_GET_SN:
+#endif                        
+
+    default:
+      res = RES_PARERR;
+  }
+
+  return res;
+}
+
+#if 0
+static void mmcDump (U8 *buff, U32 ofs, U8 cnt)
+{
+  U8 n;
+
+  printf ("\n\r%08X ", ofs);
+
+  for (n = 0; n < cnt; n++)
+    printf (" %02X", buff [n]);
+
+  putchar (' ');
+
+  for (n = 0; n < cnt; n++) 
+  {
+    if ((buff [n] < 0x20) || (buff [n] >= 0x7F))
+      putchar ('.');
+    else
+      putchar (buff [n]);
+  }
+}
+#endif
+
+#if 0
+typedef struct csd_11_s
+{
+  unsigned int not_used_1          : 2;   // 0..1  [121:120]   0x44
+  unsigned int mmc_prot            : 4;   // 2..5  [125:122]
+  unsigned int csd_structure       : 2;   // 6..7  [127:126]
+  unsigned int taac                : 8;   // 0..7  [119:112]   0x26
+  unsigned int nsac                : 8;   // 0..7  [111:104]   0x00
+  unsigned int tran_speed          : 8;   // 0..7  [103:96]    0x2a
+  unsigned int ccc_hi              : 8;   // 0..7  [95:88]     0x1f
+  unsigned int read_bl_len         : 4;   // 0..3  [83:80]     0xf9
+  unsigned int ccc_lo              : 4;   // 4..7  [87:84]
+
+  unsigned int c_size_hi           : 2;   // 0..1  [73:72]     0x83
+  unsigned int not_used_2          : 2;   // 2..3  [75:74]
+  unsigned int dsr_imp             : 1;   // 4..4  [76:76]
+  unsigned int read_blk_misalign   : 1;   // 5..5  [77:77]
+  unsigned int write_blk_misalign  : 1;   // 6..6  [78:78]
+  unsigned int read_bl_partial     : 1;   // 7..7  [79:79]
+  unsigned int c_size_mid          : 8;   // 0..7  [71:64]     0xd3
+  unsigned int vdd_r_curr_max      : 3;   // 0..1  [58:56]     0xe3
+  unsigned int vdd_r_curr_min      : 3;   // 2..5  [61:59]
+  unsigned int c_size_lo           : 2;   // 6..7  [63:62]
+
+  unsigned int c_size_mult_hi      : 2;   // 0..1  [49:48]     0x91
+  unsigned int vdd_w_curr_max      : 3;   // 2..4  [52:50]
+  unsigned int vdd_w_curr_min      : 3;   // 4..7  [55:53]
+  unsigned int erase_grp_size_lo   : 2;   // 0..1  [41:40]     0x83
+  unsigned int sector_size         : 5;   // 2..6  [46:42]
+  unsigned int c_size_mult_lo      : 1;   // 7..7  [47:47]
+  unsigned int wp_grp_size         : 5;   // 0..4  [36:32]     0xff
+  unsigned int erase_grp_size_hi   : 3;   // 5..7  [39:37]
+
+  unsigned int write_bl_len_hi     : 2;   // 0..1  [25:24]     0x92
+  unsigned int r2w_factor          : 3;   // 2..4  [28:26]
+  unsigned int default_ecc         : 2;   // 5..6  [30:29]
+  unsigned int wp_grp_enable       : 1;   // 7..7  [31:31]     
+  unsigned int not_used_3          : 5;   // 0..4  [20:16]     0x40
+  unsigned int write_bl_partial    : 1;   // 5..5  [21:21]
+  unsigned int write_bl_len_lo     : 2;   // 6..7  [23:22]
+
+  unsigned int ecc                 : 2;   // 0..1  [9:8]       0x40
+  unsigned int not_used_5          : 2;   // 2..3  [11:10]
+  unsigned int tmp_write_protect   : 1;   // 4..4  [12:12]
+  unsigned int perm_write_protect  : 1;   // 5..5  [13:13]
+  unsigned int copy                : 1;   // 6..6  [14:14]
+  unsigned int not_used_4          : 1;   // 7..7  [15:15]
+
+  unsigned int notused_6           : 1;   // 0..0  [0:0]       0x67
+  unsigned int crc                 : 7;   // 1..7  [7:1]
+}
+__attribute__ ((packed)) csd_11_t;
+
+static void mmcDecode (U8 *buffer)
+{
+  csd_11_t *p = (csd_11_t *) buffer;
+
+  printf ("\n");
+  printf ("sizeof (csd_11_t)     : %lu\n",    sizeof (csd_11_t));
+  printf ("CSD structure version : 1.%d\n",   p->csd_structure);
+  printf ("MMC protocol version  : %d\n",     p->mmc_prot);
+  printf ("TAAC                  : 0x%02x\n", p->taac);
+  printf ("NSAC                  : 0x%02x\n", p->nsac);
+  printf ("TRAN_SPEED            : 0x%02x\n", p->tran_speed);
+  printf ("CCC                   : 0x%03x\n", (p->ccc_hi << 4) | p->ccc_lo);
+  printf ("READ_BL_LEN           : %d\n",     p->read_bl_len);
+  printf ("READ_BL_PARTIAL       : %d\n",     p->read_bl_partial);
+  printf ("WRITE_BLK_MISALIGN    : %d\n",     p->write_blk_misalign);
+  printf ("READ_BLK_MISALIGN     : %d\n",     p->read_blk_misalign);
+  printf ("DSR_IMP               : %d\n",     p->read_blk_misalign);
+  printf ("C_SIZE                : %d\n",     (p->c_size_hi << 10) | (p->c_size_mid << 2) | p->c_size_lo);
+  printf ("VDD_R_CURR_MIN        : %d\n",     p->vdd_r_curr_min);
+  printf ("VDD_R_CURR_MAX        : %d\n",     p->vdd_r_curr_max);
+  printf ("VDD_W_CURR_MIN        : %d\n",     p->vdd_w_curr_min);
+  printf ("VDD_W_CURR_MAX        : %d\n",     p->vdd_w_curr_max);
+  printf ("VDD_W_CURR_MAX        : %d\n",     p->vdd_w_curr_max);
+  printf ("C_SIZE_MULT           : %d\n",     (p->c_size_mult_hi << 1) | p->c_size_mult_lo);
+  printf ("SECTOR_SIZE           : %d\n",     p->sector_size);
+  printf ("ERASE_GRP_SIZE        : %d\n",     (p->erase_grp_size_hi << 2) | p->erase_grp_size_lo);
+  printf ("WP_GRP_SIZE           : %d\n",     p->wp_grp_size);
+  printf ("WP_GRP_ENABLE         : %d\n",     p->wp_grp_enable);
+  printf ("DEFAULT_ECC           : %d\n",     p->default_ecc);
+  printf ("R2W_FACTOR            : %d\n",     p->r2w_factor);
+  printf ("WRITE_BL_LEN          : %d\n",     (p->write_bl_len_hi << 2) | p->write_bl_len_lo);
+  printf ("WRITE_BL_PARTIAL      : %d\n",     p->write_bl_partial);
+  printf ("COPY                  : %d\n",     p->copy);
+  printf ("PERM_WRITE_PROTECT    : %d\n",     p->perm_write_protect);
+  printf ("TMP_WRITE_PROTECT     : %d\n",     p->tmp_write_protect);
+  printf ("ECC                   : %d\n",     p->ecc);
+  printf ("MEDIA SIZE            : %u\n",     (U32) (((p->c_size_hi << 10) | (p->c_size_mid << 2) | p->c_size_lo) + 1) *
+                                              (U32) (4 << ((p->c_size_mult_hi << 1) | p->c_size_mult_lo)) *
+                                              (U32) (1 << (p->read_bl_len)));
+}
+#endif
+
diff --git a/fatfs/mmc.h b/fatfs/mmc.h
new file mode 100644 (file)
index 0000000..9d61c85
--- /dev/null
@@ -0,0 +1,127 @@
+/*************************************************************************
+ *
+ *    Used with ICCARM and AARM.
+ *
+ *    (c) Copyright IAR Systems 2003
+ *
+ *    File name   : mmc.h
+ *    Description : define MMC module
+ *
+ *    History :
+ *    1. Data        : July 1, 2005
+ *       Author      : Stanimir Bonev
+ *       Description : Create
+ *
+ *    $Revision: 1.4 $
+**************************************************************************/
+
+#ifndef _MMC_H_
+#define _MMC_H_
+
+#include "sysdefs.h"
+#include "disk.h"
+
+//
+//  Hardware depends definitions
+//
+#define IdentificationModeClock   400000l
+#define SystemPeripherialClock    48000000l
+
+// 
+//  Time out definition for SD Read Time out ~100msec, Write Time out ~250ms
+//
+#define SD_READ_TIME_OUT          7     // [Hz]
+#define SD_WRITE_TIME_OUT         3     // [HZ]
+
+//
+//
+//
+#define MMC_OK              0x00
+#define MMC_IDLE_STATE      0x01
+#define MMC_ERASE_RST       0x02
+#define MMC_ILLEGAL_CMD     0x04
+#define MMC_CRC_ERROR       0x08
+#define MMC_ERASE_ERROR     0x10
+#define MMC_ADD_ERROR       0x20
+#define MMC_PARAM_ERROR     0x40
+
+#define MMC_DATA_TOKEN      0xfe
+#define MMC_DATA_ERR_TOKEN  0x1f
+#define MMC_STOP_TRAN       0xfd
+
+#define MMC_DLY_1MSEC       1000
+
+typedef enum
+{
+  MmcOk = 0, 
+  MmcNoPresent, 
+  MmcNoResponse, 
+  MmcCardError, 
+  MmcDataError,
+  MmcUknowError, 
+  MmmcParameterError, 
+  MmcMiscompare
+} 
+mmcState_t;
+
+typedef enum
+{
+  CMD0 = 0, // Resets the MultiMediaCard
+  CMD1,     // Activates the card initialization process
+  CMD9,     // Asks the selected card to send its card-specific data (CSD)
+  CMD10,    // Asks the selected card to send its card identification (CID)
+  CMD12,    // Stop transmission on multiple block read
+  CMD13,    // Asks the selected card to send its status register
+  CMD16,    // Selects a block length (in bytes) for all following block commands (read and write)
+  CMD17,    // Reads a block of the size selected by the SET_BLOCKLEN command
+  CMD18,    // Continuously transfers data blocks from card to host until interrupted by a Stop command or the requested number of data blocks transmitted
+  CMD24,    // Writes a block of the size selected by the SET_BLOCKLEN command
+  CMD25,    // Continuously writes blocks of data until a "Stop Tran" token or the requested number of blocks received
+  CMD27,    // Programming of the programmable bits of the CSD
+  CMD28,    // If the card has write protection features, this command sets the write protection bit of the addressed group. The properties of write protection are coded in the card specific data (WP_GRP_SIZE).
+  CMD29,    // If the card has write protection features, this command clears the write protection bit of the addressed group
+  CMD30,    // If the card has write protection features, this command asks the card to send the status of the write protection bits
+  CMD32,    // Sets the address of the first sector of the erase group
+  CMD33,    // Sets the address of the last sector in a continuous range within the selected erase group, or the address of a single sector to be selected for erase
+  CMD34,    // Removes one previously selected sector from the erase selection
+  CMD35,    // Sets the address of the first erase group within a range to be selected for erase
+  CMD36,    // Sets the address of the last erase group within a continuous range to be selected for erase
+  CMD37,    // Removes one previously selected erase group from the erase selection.
+  CMD38,    // Erases all previously selected sectors
+  CMD42,    // Used to set/reset the password or lock/unlock the card. The size of the Data Block is defined by the SET_BLOCK_LEN command
+  CMD55,    // Notifies the card that the next command is an application specific command rather than a standard command.
+  CMD56,    // Used either to transfer a Data Block to the card or to get a Data Block from the card for general purpose/application specific commands. The size of the Data Block is defined with SET_BLOCK_LEN command
+  CMD58,    // Reads the OCR register of a card
+  CMD59,    // Turns the CRC option on or off. A \911\92 in the CRC option bit will turn the option on, a \910\92 will turn it off
+  ACMD41,   // Activates the card\92s initialization process (Only for SD)
+  CMD_END   // End of commands index
+} 
+mmcSpiCmdInd_t;
+
+typedef enum
+{
+  MmcNoArg = 0,
+  MmcBlockLen,
+  MmcDataAdd, 
+  MmcDummyWord
+} 
+mmcAgmType_t;
+
+typedef enum
+{
+  MmcR1 = 0,
+  MmcR1b,
+  MmcR2,
+  MmcR3
+} 
+mmcRespType_t;
+
+typedef struct
+{
+  U8            TxData;
+  mmcAgmType_t  Arg;
+  mmcRespType_t Resp;
+} 
+mmcCommads_t;
+
+#endif 
diff --git a/fatfs/spi.c b/fatfs/spi.c
new file mode 100644 (file)
index 0000000..d478381
--- /dev/null
@@ -0,0 +1,284 @@
+#include <stdio.h> // ###
+#include "lpc210x.h"
+#include "mmc.h"
+#include "spi.h"
+
+/*************************************************************************
+ *
+ *    Used with ICCARM and AARM.
+ *
+ *    (c) Copyright IAR Systems 2003
+ *
+ *    File name   : mmc_ll.h
+ *    Description : define MMC module
+ *
+ *    History :
+ *    1. Data        : July 1, 2005
+ *       Author      : Stanimir Bonev
+ *       Description : Create
+ *    2. Data        : July 1, 2005
+ *       Author      : Stanimir Bonev
+ *       Description : Modify
+ *        Fix a lock problem in spiReceiveBlock
+ *
+ *    $Revision: 1.4 $
+ * (C) Joel Winarske, 2006,2007                                        
+**************************************************************************/
+
+/*************************************************************************
+ * Function Name: spiChipSelect
+ * Parameters: Boolean Select
+ * Return: none
+ *
+ * Description: MMC Chip select control
+ * Select = true  - Chip is enabled
+ * Select = false - Chip is disabled
+ *
+ *************************************************************************/
+void spiChipSelect (BOOL select)
+{
+  if (select)
+    GPIO0_IOCLR = GPIO_IO_P20;
+  else
+  {
+    GPIO0_IOSET = GPIO_IO_P20;
+    
+    while (!(SSP_SR & SSP_SR_TNF))
+      ;
+
+    SSP_DR = 0xff;
+
+    //
+    // Wait until TX fifo and TX shift buffer are empty
+    //
+    while (SSP_SR & SSP_SR_BSY)
+      ;
+    while (!(SSP_SR & SSP_SR_RNE))
+      ;
+
+    do
+    {
+      select = SSP_DR;
+    }
+    while (SSP_SR & SSP_SR_RNE);
+  }
+}
+
+/*************************************************************************
+ * Function Name: spiPresent
+ * Parameters: none
+ * Return: Boolean - true card present
+ *                 - false card not present
+ *
+ * Description: MMC present check
+ *
+ *************************************************************************/
+inline BOOL spiPresent (void)
+{
+  return TRUE;
+}
+
+/*************************************************************************
+ * Function Name: spiWriteProtect
+ * Parameters: none
+ * Return: Boolean - true card is protected
+ *                 - false card not protected
+ *
+ * Description: MMC Write protect check
+ *
+ *************************************************************************/
+inline BOOL spiWriteProtect (void)
+{
+  return FALSE;
+}
+
+/*************************************************************************
+ * Function Name: spiSetClockFreq
+ * Parameters: Int32U Frequency
+ * Return: Int32U
+ *
+ * Description: Set SPI ckl frequency
+ *
+ *************************************************************************/
+U32 spiSetClockFreq (U32 frequency)
+{
+  U32 Div = SystemPeripherialClock / frequency;
+
+  if (Div < 2)
+    Div = 2;
+  else if (Div > 254)
+    Div = 254;
+
+  ++Div; 
+  Div &= ~1;
+  SSP_CPSR = Div;
+
+  return (SystemPeripherialClock / Div);
+}
+
+/*************************************************************************
+ * Function Name: spiInit
+ * Parameters: none
+ * Return: int
+ * 0 - no error
+ * 1 - speed is to high
+ *
+ * Description: Init SPI, Cart Present, Write Protect and Chip select pins
+ *
+ *************************************************************************/
+void spiInit (void)
+{
+  U32 i;
+  volatile U32 dummy;
+
+  //
+  //  Chip select
+  //
+  GPIO0_IOSET = GPIO_IO_P20;
+  GPIO0_IODIR |= GPIO_IO_P20;
+
+  //
+  //  SPI init
+  //
+  SCB_PCONP |= SCB_PCONP_PCSPI1;
+
+  SSP_CR0  = SSP_CR0_DSS_8 | SSP_CR0_FRF_SPI;
+  SSP_CR1  = 0x00;
+  SSP_IMSC = 0x00;
+
+  //
+  //  Clock Freq. Identification Mode < 400kHz
+  //
+  spiSetClockFreq (400000);
+
+  PCB_PINSEL1 |=  PCB_PINSEL1_P017_SCK1;
+  PCB_PINSEL1 |=  PCB_PINSEL1_P018_MISO1;
+  PCB_PINSEL1 |=  PCB_PINSEL1_P019_MOSI1;
+  PCB_PINSEL1 &= ~PCB_PINSEL1_P020_MASK;
+
+  //
+  //  Enable SPI
+  //
+  SSP_CR1 |= SSP_CR1_SSE;
+
+  for (i = 0; i < 8; i++)
+    dummy = SSP_DR;
+}
+
+/*************************************************************************
+ * Function Name: spiTransferByte
+ * Parameters: U8 ch
+ * Return: U8
+ *
+ * Description: Read byte from SPI
+ *
+ *************************************************************************/
+U8 spiTransferByte (U8 c)
+{
+  while (!(SSP_SR & SSP_SR_TNF))
+    ;
+
+  SSP_DR = c;
+
+  while (!(SSP_SR & SSP_SR_RNE))
+    ;
+
+  return SSP_DR;
+}
+
+/*-----------------------------------------------------------------------*/
+/* Wait for card ready                                                   */
+/*-----------------------------------------------------------------------*/
+U8 spiWaitReady (void)
+{
+  U8 res;
+
+  do                        /* TODO: add in 500ms timeout */
+  {      
+    SSP_DR = 0xff;
+
+    while (!(SSP_SR & SSP_SR_RNE))
+      ;
+
+    res = SSP_DR;
+  }
+  while (res != 0xff);
+
+  return res;
+}
+
+/*************************************************************************
+ * Function Name: spiSendBlock
+ * Parameters: pInt8U pData, Int32U Size
+ *
+ * Return: void
+ *
+ * Description: Read byte from SPI
+ *
+ *************************************************************************/
+void spiSendBlock (U8 *pData, U32 size)
+{
+  U32 outCount = size;
+  volatile U32 dummy;
+
+  while (outCount)
+  {
+    while ((SSP_SR & SSP_SR_TNF) && outCount)
+    {
+      SSP_DR = *pData++;
+      --outCount;
+    }
+  }
+
+  while ((SSP_SR & SSP_SR_RNE) || !(SSP_SR & SSP_SR_TFE))
+    dummy = SSP_DR;
+}
+
+/*************************************************************************
+ * Function Name: spiReceiveBlock
+ * Parameters: pInt8U pData, Int32U Size
+ *
+ * Return: void
+ *
+ * Description: Read byte from SPI
+ *
+ *************************************************************************/
+void spiReceiveBlock (U8 *pData, U32 size)
+{
+  U32 delta = 0;
+
+  while (size || delta)
+  {
+    while ((SSP_SR & SSP_SR_TNF) && (delta < SSP_FIFO_DEPTH) && size)
+    {
+      SSP_DR = 0xff;
+      --size; 
+      ++delta;
+    }
+
+    while (SSP_SR & SSP_SR_RNE)
+    {
+      *pData++ = SSP_DR;
+      --delta;
+    }
+  }
+}
+
+/*************************************************************************
+ * Function Name: spiDly_1ms
+ * Parameters: Int32U Delay
+ * Return: none
+ *
+ * Description: Delay [msec]
+ *
+ *************************************************************************/
+void spiDelay1ms (U32 delay)
+{
+  volatile U32 i;
+
+  for (;delay; --delay)
+  {
+    for (i = MMC_DLY_1MSEC; i; --i)
+      ;
+  }
+}
diff --git a/fatfs/spi.h b/fatfs/spi.h
new file mode 100644 (file)
index 0000000..a2a6eaa
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef _MMCLLSPI1_H_
+#define _MMCLLSPI1_H_
+
+#include "sysdefs.h"
+
+//
+//
+//
+void spiChipSelect (BOOL select);
+inline BOOL spiPresent (void);
+inline BOOL spiWriteProtect (void);
+U32 spiSetClockFreq (U32 frequency);
+void spiInit (void);
+U8 spiTransferByte (U8 c);
+U8 spiWaitReady (void);
+void spiSendBlock (U8 *pData, U32 size);
+void spiReceiveBlock (U8 *pData, U32 size);
+void spiDelay1ms (U32 delay);
+
+#endif
diff --git a/fiq/Makefile b/fiq/Makefile
new file mode 100644 (file)
index 0000000..53e74ae
--- /dev/null
@@ -0,0 +1,25 @@
+SRC_FILES=fiq.c
+
+#
+# Define all object files.
+#
+ARM_OBJ = $(SRC_FILES:.c=.o)
+
+.PHONY: all
+all: $(ARM_OBJ)
+
+$(ARM_OBJ) : %.o : %.c Makefile .depend
+       $(CC) -c $(CFLAGS) $< -o $@
+       $(AR) r $(COMMON)/common.a $@
+
+#
+#  The .depend files contains the list of header files that the
+#  various source files depend on.  By doing this, we'll only
+#  rebuild the .o's that are affected by header files changing.
+#
+.depend:
+                       $(CC) $(CFLAGS) -M $(SRC_FILES) > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff --git a/fiq/fiq.c b/fiq/fiq.c
new file mode 100644 (file)
index 0000000..71a0d99
--- /dev/null
+++ b/fiq/fiq.c
@@ -0,0 +1,59 @@
+#include "FreeRTOS.h"
+
+#include "fiq.h"
+
+//
+//
+//
+static volatile unsigned int fiqCounter;
+
+//
+//
+//
+void fiqInit (void)
+{
+  SCB_PCONP |= SCB_PCONP_PCTIM1;
+
+  VIC_IntSelect |= VIC_IntSelect_Timer1;
+  VIC_IntEnable = VIC_IntEnable_Timer1;
+
+  T1_PR = 0;
+  T1_MR0 = configCPU_CLOCK_HZ / 8;
+  T1_MCR = T_MCR_MR0R | T_MCR_MR0I;
+}
+
+int fiqEnable (void)
+{
+  unsigned int state = T1_TCR;
+
+  T1_TCR = T_TCR_CE;
+
+  return (state & T_TCR_CE) ? 1 : 0;
+}
+
+int fiqDisable (void)
+{
+  unsigned int state = T1_TCR;
+
+  T1_TCR = T_TCR_CR;
+
+  return (state & T_TCR_CE) ? 1 : 0;
+}
+
+unsigned int fiqGetCount (void)
+{
+  return fiqCounter;
+}
+
+void fiqClearCount (void)
+{
+  fiqCounter = 0;
+}
+
+void fiqISR (void) __attribute__ ((interrupt ("FIQ")));
+void fiqISR (void)
+{
+  ++fiqCounter;
+
+  T1_IR = T_IR_MASK;
+}
diff --git a/fiq/fiq.h b/fiq/fiq.h
new file mode 100644 (file)
index 0000000..cc16aef
--- /dev/null
+++ b/fiq/fiq.h
@@ -0,0 +1,11 @@
+#ifndef _FIQ_H_
+#define _FIQ_H_
+
+void fiqInit (void);
+int fiqEnable (void);
+int fiqDisable (void);
+unsigned int fiqGetCount (void);
+void fiqClearCount (void);
+void fiqISR (void);
+
+#endif
diff --git a/gps/Makefile b/gps/Makefile
new file mode 100644 (file)
index 0000000..1c20afa
--- /dev/null
@@ -0,0 +1,25 @@
+SRC_FILES=gps.c
+
+#
+# Define all object files.
+#
+ARM_OBJ = $(SRC_FILES:.c=.o)
+
+.PHONY: all
+all: $(ARM_OBJ)
+
+$(ARM_OBJ) : %.o : %.c Makefile .depend
+       $(CC) -c $(CFLAGS) $< -o $@
+       $(AR) r $(COMMON)/common.a $@
+
+#
+#  The .depend files contains the list of header files that the
+#  various source files depend on.  By doing this, we'll only
+#  rebuild the .o's that are affected by header files changing.
+#
+.depend:
+                       $(CC) $(CFLAGS) -M $(SRC_FILES) > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff --git a/gps/gps.c b/gps/gps.c
new file mode 100644 (file)
index 0000000..c0a9f1c
--- /dev/null
+++ b/gps/gps.c
@@ -0,0 +1,284 @@
+//
+//
+//
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "FreeRTOS.h"
+#include "task.h"
+#include "semphr.h"
+
+#include "gps.h"
+
+//
+//
+//
+#define GPS_MAX_NMEA_SENTENCE 128
+
+//
+//
+//
+static gpsData_t gpsData;
+static xSemaphoreHandle semaphore;
+
+//
+//
+//
+static void gpsNormalizeNMEA (char *s);
+static unsigned char gpsChecksumNMEA (char *sz);
+static void gpsHandlerGGA (char *nmeaSentence);
+static void gpsHandlerRMC (char *nmeaSentence);
+static void gpsHandlerRestart (char *nmeaSentence);
+static void gpsDispatchMessages (char *nmeaSentence);
+static int gpsProcessByte (unsigned char c, char *nmeaSentence);
+
+//
+//
+//
+static void gpsNormalizeNMEA (char *s)
+{
+  int l = -1;
+
+  while (*s && *s != '*')
+  {
+    if (*s == ',' && (*(s + 1) == ',' || *(s + 1) == '*'))
+    {
+      if (l == -1)
+        l = strlen (s) + 1;
+
+      memmove (s + 3, s + 1, l);
+      *++s = '-';
+      *++s = '1';
+      l += 2;
+    }
+
+    s++;
+
+    if (l != -1)
+      l--;
+  }
+}
+
+//
+//
+//
+static unsigned char gpsChecksumNMEA (char *sz)
+{
+  short i;
+  unsigned char cs;
+
+  for (cs = 0, i = 1; sz [i] && sz [i] != '*'; i++)
+    cs ^= ((unsigned char) sz [i]);
+
+  return cs;
+}
+
+//
+//
+//
+static void gpsHandlerGGA (char *nmeaSentence)
+{
+  char   valid = 0;
+  double height = 0.0;
+  double latitude = 0.0, longitude = 0.0;
+  char   latitudeSign = 0, longitudeSign = 0;
+
+  if (sscanf (nmeaSentence, "%*f,%lf,%c,%lf,%c,%c,%*d,%*f,%lf", &latitude, &latitudeSign, &longitude, &longitudeSign, &valid, &height) == 6)
+  {
+    if (xSemaphoreTake (semaphore, portMAX_DELAY) == pdTRUE)
+    {
+      gpsData.valid = (valid - '0');
+      gpsData.height = height;
+      gpsData.latitude  = latitude * (latitudeSign == 'N' ? 1.0 : -1.0);
+      gpsData.longitude = longitude * (longitudeSign == 'E' ? 1.0 : -1.0);
+
+      xSemaphoreGive (semaphore);
+    }
+  }
+}
+
+static void gpsHandlerRMC (char *nmeaSentence)
+{
+  float speed, course;
+  int gpsdate, gpstime;
+
+  if (sscanf (nmeaSentence, "%d.%*d,%*c,%*f,%*c,%*f,%*c,%f,%f,%d", &gpstime, &speed, &course, &gpsdate) == 4)
+  {
+    if (xSemaphoreTake (semaphore, portMAX_DELAY) == pdTRUE)
+    {
+      gpsData.utcDay      =  gpsdate / 10000;
+      gpsData.utcMonth    = (gpsdate / 100) % 100;
+      gpsData.utcYear     = (gpsdate % 100) + 2000;
+      gpsData.utcHours    =  gpstime / 10000;
+      gpsData.utcMinutes  = (gpstime / 100) % 100;
+      gpsData.utcSeconds  =  gpstime % 100;
+      gpsData.groundSpeed =  speed;
+      gpsData.trueCourse  =  course;
+
+      xSemaphoreGive (semaphore);
+    }
+  }
+}
+
+static void gpsHandlerRestart (char *nmeaSentencemea __attribute__ ((unused)))
+{
+  if (xSemaphoreTake (semaphore, portMAX_DELAY) == pdTRUE)
+  {
+    gpsData.restarts++;
+    xSemaphoreGive (semaphore);
+  }
+}
+
+//
+//
+//
+typedef struct nmeaDispatch_s
+{
+  const char *sentence;
+  short length;
+  void (*handler) (char *sentence);
+  short normalize;
+}
+nmeaDispatch_t;
+
+static const nmeaDispatch_t nmeaDispatch [] =
+{
+  { "$GPGGA",    6, gpsHandlerGGA,      1 },
+  { "$GPRMC",    6, gpsHandlerRMC,      1 },
+  { "$HW Type",  8, gpsHandlerRestart,  0 },
+  { NULL,        0, NULL,               0 }
+};
+
+static void gpsDispatchMessages (char *nmeaSentence)
+{
+  int i;
+
+  for (i = 0; nmeaDispatch [i].handler; i++)
+  {
+    if (!strncmp (nmeaDispatch [i].sentence, nmeaSentence, nmeaDispatch [i].length))
+    {
+      if (nmeaDispatch [i].normalize)
+      {
+        gpsNormalizeNMEA (&nmeaSentence [7]);
+        (*nmeaDispatch [i].handler) (&nmeaSentence [7]);
+      }
+      else
+        (*nmeaDispatch [i].handler) (NULL);
+
+      break;
+    }
+  }
+}
+
+//
+//
+//
+static int gpsProcessByte (unsigned char c, char *nmeaSentence)
+{
+  short complete = 0;
+  static short state = 0;
+  static short pos = 0;
+
+  switch (state)
+  {
+    case 0 :
+      {
+        if (c == '$')
+        {
+          pos = 0;
+          nmeaSentence [pos++] = '$';
+          nmeaSentence [pos] = '\0';
+          state = 1;
+        }
+        else
+          state = 0;
+      }
+      break;
+
+    case 1 :
+      {
+        if (pos < GPS_MAX_NMEA_SENTENCE)
+        {
+          if (c == 0x0a)
+          {
+            char *s;
+
+            state = 0;
+
+            if ((s = strchr (nmeaSentence, '*')))
+            {
+              int cksum;
+
+              if (sscanf (s + 1, "%x", &cksum) == 1)
+              {
+                if (gpsChecksumNMEA (nmeaSentence) == cksum)
+                  complete = 1;
+              }
+              else
+                fprintf (stderr, "NMEA checksum error: got 0x%02x, want %s", cksum, s);
+            }
+            else
+              fprintf (stderr, "NMEA checksum not found: \"%s\"", nmeaSentence);
+          }
+          else if (c != 0x0d)
+          {
+            nmeaSentence [pos++] = c;
+            nmeaSentence [pos] = '\0';
+          }
+        }
+        else
+          state = 0;
+      }
+      break;
+  }
+
+  return (complete);
+}
+
+//
+//  Return 1 if got a copy, 0 if not.
+//
+int gpsCopyData (gpsData_t *dst)
+{
+#ifndef CFG_CONSOLE_UART1
+  if (xSemaphoreTake (semaphore, 100 / portTICK_RATE_MS) == pdTRUE)
+  {
+    memcpy (dst, &gpsData, sizeof (gpsData_t));
+    xSemaphoreGive (semaphore);
+    return 1;
+  }
+#endif
+
+  memset (dst, 0, sizeof (gpsData_t));
+  return 0;
+}
+
+//
+//
+//
+portTASK_FUNCTION (vGPSTask, pvParameters __attribute__ ((unused)))
+{
+  int fd;
+  static char nmeaSentence [GPS_MAX_NMEA_SENTENCE];
+
+  memset (&gpsData, 0, sizeof (gpsData));
+
+  vSemaphoreCreateBinary (semaphore);
+
+  fd = open ("/dev/uart1", O_RDONLY);
+
+  if ((fd == -1) || (semaphore == NULL))
+    for (;;)
+      vTaskDelay (100);
+
+  for (;;)
+  {
+    portCHAR c;
+
+    if (read (fd, &c, sizeof (c)) == sizeof (c))
+      if (gpsProcessByte (c, nmeaSentence))
+        gpsDispatchMessages (nmeaSentence);
+  }
+}
diff --git a/gps/gps.h b/gps/gps.h
new file mode 100644 (file)
index 0000000..b8e008f
--- /dev/null
+++ b/gps/gps.h
@@ -0,0 +1,33 @@
+#ifndef _GPS_H_
+#define _GPS_H_
+
+#include "semphr.h"
+
+//
+//
+//
+typedef struct gpsData_s
+{
+  unsigned char valid;
+  double latitude;
+  double longitude;
+  double height;
+  float groundSpeed;
+  float trueCourse;
+  unsigned char utcDay;
+  unsigned char utcMonth;
+  unsigned short utcYear;
+  unsigned char utcHours;
+  unsigned char utcMinutes;
+  unsigned char utcSeconds;
+  int restarts;
+}
+gpsData_t;
+
+//
+//
+//
+int gpsCopyData (gpsData_t *dst);
+portTASK_FUNCTION_PROTO (vGPSTask, pvParameters __attribute__ ((unused)));
+
+#endif
diff --git a/i2c/Makefile b/i2c/Makefile
new file mode 100644 (file)
index 0000000..0aef6ce
--- /dev/null
@@ -0,0 +1,25 @@
+SRC_FILES=i2c.c i2cInt.c lm75.c eeprom.c
+
+#
+# Define all object files.
+#
+ARM_OBJ = $(SRC_FILES:.c=.o)
+
+.PHONY: all
+all: $(ARM_OBJ)
+
+$(ARM_OBJ) : %.o : %.c Makefile .depend
+       $(CC) -c $(CFLAGS) $< -o $@
+       $(AR) r $(COMMON)/common.a $@
+
+#
+#  The .depend files contains the list of header files that the
+#  various source files depend on.  By doing this, we'll only
+#  rebuild the .o's that are affected by header files changing.
+#
+.depend:
+                       $(CC) $(CFLAGS) -M $(SRC_FILES) > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff --git a/i2c/eeprom.c b/i2c/eeprom.c
new file mode 100644 (file)
index 0000000..d537508
--- /dev/null
@@ -0,0 +1,149 @@
+#include "FreeRTOS.h"
+
+#include <string.h>
+
+#include "i2c.h"
+#include "eeprom.h"
+
+//
+//
+//
+static U32 rwAddress;
+static U8 deviceAddress = EEPROM_ADDRESS;
+
+//
+//
+//
+void eepromInit (void)
+{
+}
+
+int eepromSetAddress (U32 address)
+{
+  int r = 0;
+
+  if (address >= EEPROM_SIZE)
+    r = -1;
+
+  address %= EEPROM_SIZE;
+
+  if ((rwAddress = address) >= 65536)
+    deviceAddress |= 0x02;
+  else
+    deviceAddress &= ~0x02;
+
+  return r;
+}
+
+static int eepromSetAddressEx (U32 address, U8 *buffer)
+{
+  int r;
+
+  if ((r = eepromSetAddress (address)))
+    return r;
+
+  buffer [0] = rwAddress >> 8;
+  buffer [1] = rwAddress;
+
+  return 0;
+}
+
+U32 eepromGetAddress (void)
+{
+  return rwAddress;
+}
+
+//
+//
+//
+int eepromRead (U8 *buffer, U32 bufferLength)
+{
+  int r;
+
+  buffer [0] = rwAddress >> 8;
+  buffer [1] = rwAddress;
+
+  if (!(r = i2cWriteReadBufferPoll (deviceAddress, buffer, sizeof (U16), bufferLength)))
+    eepromSetAddress (eepromGetAddress () + bufferLength);
+
+  return r;
+}
+
+int eepromReadAddress (U32 address, U8 *buffer, U32 bufferLength)
+{
+  int r;
+
+  if ((r = eepromSetAddress (address)))
+    return r;
+
+  return eepromRead (buffer, bufferLength);
+}
+
+//
+//
+//
+int eepromWrite (U8 *buffer, U32 bufferLength)
+{
+  int r;
+
+  buffer [0] = rwAddress >> 8;
+  buffer [1] = rwAddress;
+
+  if (!(r = i2cWriteBufferPoll (deviceAddress, buffer, bufferLength + 2)))
+    eepromSetAddress (eepromGetAddress () + bufferLength);
+
+  return r;
+}
+
+int eepromWriteAddress (U32 address, U8 *buffer, U32 bufferLength)
+{
+  int r;
+
+  if ((r = eepromSetAddress (address)))
+    return r;
+
+  return eepromWrite (buffer, bufferLength);
+}
+
+//
+//
+//
+static int eepromFillAddressCommon (U32 address, U8 *buffer, U32 bufferLength)
+{
+  int r;
+
+  if (!(r = eepromSetAddressEx (address, buffer)))
+    r = i2cWriteBufferPoll (deviceAddress, buffer, bufferLength + 2);
+
+  return r;
+}
+
+int eepromFillAddress (U32 address, U32 bufferLength, U8 fillValue)
+{
+  int r;
+  U32 l;
+  U32 i;
+  U8 buffer [EEPROM_PAGESIZE + 2];
+
+  memset (buffer, fillValue, sizeof (buffer));
+
+  l = (EEPROM_PAGESIZE - ((address + EEPROM_PAGESIZE) % EEPROM_PAGESIZE)) % EEPROM_PAGESIZE;
+  l = MIN (l, bufferLength);
+
+  if (l && (r = eepromFillAddressCommon (address, buffer, l)))
+    return r;
+
+  address += l;
+  bufferLength -= l;
+  l = bufferLength - (bufferLength % EEPROM_PAGESIZE);
+
+  for (i = 0; i < l; i += EEPROM_PAGESIZE, address += (sizeof (buffer) - 2), bufferLength -= (sizeof (buffer) - 2))
+    if ((r = eepromFillAddressCommon (address, buffer, sizeof (buffer) - 2)))
+      return r;
+
+  if (bufferLength && (r = eepromFillAddressCommon (address, buffer, bufferLength)))
+    return r;
+
+  return 0;
+}
+
diff --git a/i2c/eeprom.h b/i2c/eeprom.h
new file mode 100644 (file)
index 0000000..bfd1412
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef _EEPROM_H_
+#define _EEPROM_H_
+
+//
+//
+//
+#define EEPROM_ADDRESS  (0xa0)
+#define EEPROM_SIZE     (131072)
+#define EEPROM_PAGESIZE (256)
+
+//
+//
+//
+void eepromInit (void);
+int eepromSetAddress (U32 address);
+U32 eepromGetAddress (void);
+int eepromRead (U8 *buffer, U32 bufferLength);
+int eepromReadAddress (U32 address, U8 *buffer, U32 bufferLength);
+int eepromWrite (U8 *buffer, U32 bufferLength);
+int eepromWriteAddress (U32 address, U8 *buffer, U32 bufferLength);
+int eepromFillAddress (U32 address, U32 length, U8 fillValue);
+
+#endif
diff --git a/i2c/eeprom_working.c b/i2c/eeprom_working.c
new file mode 100644 (file)
index 0000000..207f0a9
--- /dev/null
@@ -0,0 +1,156 @@
+#include "FreeRTOS.h"
+
+#include <string.h>
+
+#include "i2c.h"
+#include "eeprom.h"
+
+//
+//
+//
+static U32 rwAddress;
+static U8 deviceAddress = EEPROM_ADDRESS;
+
+//
+//
+//
+void eepromInit (void)
+{
+}
+
+int eepromSetAddress (U32 address)
+{
+  int r = 0;
+
+  if (address >= EEPROM_SIZE)
+    r = -1;
+
+  address %= EEPROM_SIZE;
+
+  if ((rwAddress = address) >= 65536)
+    deviceAddress |= 0x02;
+  else
+    deviceAddress &= ~0x02;
+
+  return r;
+}
+
+static int eepromSetAddressEx (U32 address, U8 *buffer)
+{
+  int r;
+
+  if ((r = eepromSetAddress (address)))
+    return r;
+
+  buffer [0] = rwAddress >> 8;
+  buffer [1] = rwAddress;
+
+  return 0;
+}
+
+U32 eepromGetAddress (void)
+{
+  return rwAddress;
+}
+
+//
+//
+//
+int eepromRead (U8 *buffer, U32 bufferLength)
+{
+  int r;
+
+  buffer [0] = rwAddress >> 8;
+  buffer [1] = rwAddress;
+
+  if (!(r = i2cWriteReadBuffer (deviceAddress, buffer, sizeof (U16), bufferLength)))
+    eepromSetAddress (eepromGetAddress () + bufferLength);
+
+  return r;
+}
+
+int eepromReadAddress (U32 address, U8 *buffer, U32 bufferLength)
+{
+  int r;
+
+  if ((r = eepromSetAddress (address)))
+    return r;
+
+  return eepromRead (buffer, bufferLength);
+}
+
+//
+//
+//
+int eepromWrite (U8 *buffer, U32 bufferLength)
+{
+  int r;
+
+  buffer [0] = rwAddress >> 8;
+  buffer [1] = rwAddress;
+
+  if (!(r = i2cWriteBuffer (deviceAddress, buffer, bufferLength + 2)))
+    eepromSetAddress (eepromGetAddress () + bufferLength);
+
+  return r;
+}
+
+int eepromWriteAddress (U32 address, U8 *buffer, U32 bufferLength)
+{
+  int r;
+
+  if ((r = eepromSetAddress (address)))
+    return r;
+
+  return eepromWrite (buffer, bufferLength);
+}
+
+//
+//
+//
+int eepromFillAddress (U32 address, U32 bufferLength, U8 fillValue)
+{
+  int r;
+  U32 l;
+  U32 i;
+  U8 buffer [EEPROM_PAGESIZE + 2];
+
+  memset (buffer, fillValue, sizeof (buffer));
+
+  l = (EEPROM_PAGESIZE - ((address + EEPROM_PAGESIZE) % EEPROM_PAGESIZE)) % EEPROM_PAGESIZE;
+  l = MIN (l, bufferLength);
+
+  if (l)
+  {
+    if ((r = eepromSetAddressEx (address, buffer)))
+      return r;
+
+    if ((r = i2cWriteBuffer (deviceAddress, buffer, l + 2)))
+      return r;
+  }
+
+  address += l;
+  bufferLength -= l;
+  l = bufferLength - (bufferLength % EEPROM_PAGESIZE);
+
+  for (i = 0; i < l; i += EEPROM_PAGESIZE, address += (sizeof (buffer) - 2), bufferLength -= (sizeof (buffer) - 2))
+  {
+    if ((r = eepromSetAddressEx (address, buffer)))
+      return r;
+
+    if ((r = i2cWriteBuffer (deviceAddress, buffer, sizeof (buffer))))
+      return r;
+  }
+
+  if (bufferLength)
+  {
+    if ((r = eepromSetAddressEx (address, buffer)))
+      return r;
+
+    if ((r = i2cWriteBuffer (deviceAddress, buffer, bufferLength + 2)))
+      return r;
+  }
+
+  return 0;
+}
+
diff --git a/i2c/i2c.c b/i2c/i2c.c
new file mode 100644 (file)
index 0000000..e2732bb
--- /dev/null
+++ b/i2c/i2c.c
@@ -0,0 +1,60 @@
+#include "FreeRTOS.h"
+
+#include "i2c.h"
+
+//
+//
+//
+typedef struct i2cErrnoStr_s
+{
+  int errno;
+  const char *text;
+}
+i2cErrnoStr_t;
+
+static i2cErrnoStr_t i2cErrnoStr [] =
+{
+  { I2CERR_NONE,              "I2CERR_NONE" },
+  { I2CERR_BUSY,              "I2CERR_BUSY" },
+  { I2CERR_EMPTY,             "I2CERR_EMPTY" },
+  { I2CERR_TIMEOUT,           "I2CERR_TIMEOUT" },
+  { I2CERR_TIMEOUTWC,         "I2CERR_TIMEOUTWC" },
+  { I2CERR_TIMEOUTACKPOLL,    "I2CERR_TIMEOUTACKPOLL" },
+  { I2CERR_NOTIMPLEMENTED,    "I2CERR_NOTIMPLEMENTED" },
+  { I2CERR_OTHER,             "I2CERR_OTHER" },
+  { I2CERR_BUSERROR,          "I2CERR_BUSERROR" },
+  { I2CERR_BUSERRORx,         "I2CERR_BUSERRORx" },
+  { I2CERR_STARTTX,           "I2CERR_STARTTX" },
+  { I2CERR_REPEATEDSTARTTX,   "I2CERR_REPEATEDSTARTTX" },
+  { I2CERR_SLAWTX_ACKRX,      "I2CERR_SLAWTX_ACKRX" },
+  { I2CERR_SLAWTX_NACKRX,     "I2CERR_SLAWTX_NACKRX" },
+  { I2CERR_DATTX_ACKRX,       "I2CERR_DATTX_ACKRX" },
+  { I2CERR_DATTX_NACKRX,      "I2CERR_DATTX_NACKRX" },
+  { I2CERR_ARBLOST,           "I2CERR_ARBLOST" },
+  { I2CERR_SLARTX_ACKRX,      "I2CERR_SLARTX_ACKRX" },
+  { I2CERR_SLARTX_NACKRX,     "I2CERR_SLARTX_NACKRX" },
+  { I2CERR_DATRX_ACKTX,       "I2CERR_DATRX_ACKTX" },
+  { I2CERR_DATRX_NACKTX,      "I2CERR_DATRX_NACKTX" },
+  { I2CERR_NOINFO,            "I2CERR_NOINFO" },
+};
+
+i2cErr_e i2cErrno = I2CERR_NONE;
+
+//
+//
+//
+int i2cGetErrno (void)
+{
+  return i2cErrno;
+}
+
+const char *i2cStrerror (int err)
+{
+  unsigned int i;
+
+  for (i = 0; i < arrsizeof (i2cErrnoStr); i++)
+    if (i2cErrnoStr [i].errno == err)
+      return i2cErrnoStr [i].text;
+
+  return NULL;
+}
diff --git a/i2c/i2c.h b/i2c/i2c.h
new file mode 100644 (file)
index 0000000..cfaa16c
--- /dev/null
+++ b/i2c/i2c.h
@@ -0,0 +1,58 @@
+#ifndef _I2C_H_
+#define _I2C_H_
+
+#include "sysdefs.h"
+
+//
+//  Does not define slave RX statuses.  Bus errors (I2C_STAT == 0) is remapped
+//  to I2CERR_ERROR in i2cStatus() so that we can use a value of 0 to indicate 
+//  no error.
+//
+typedef enum
+{
+  I2CERR_NONE = 0,
+  I2CERR_BUSY,
+  I2CERR_EMPTY,
+  I2CERR_TIMEOUT,
+  I2CERR_TIMEOUTWC,
+  I2CERR_TIMEOUTACKPOLL,
+  I2CERR_NOTIMPLEMENTED,
+  I2CERR_OTHER,
+  I2CERR_BUSERROR,
+  I2CERR_BUSERRORx       = 0x00,
+  I2CERR_STARTTX         = 0x08,
+  I2CERR_REPEATEDSTARTTX = 0x10,
+  I2CERR_SLAWTX_ACKRX    = 0x18,
+  I2CERR_SLAWTX_NACKRX   = 0x20,
+  I2CERR_DATTX_ACKRX     = 0x28,
+  I2CERR_DATTX_NACKRX    = 0x30,
+  I2CERR_ARBLOST         = 0x38,
+  I2CERR_SLARTX_ACKRX    = 0x40,
+  I2CERR_SLARTX_NACKRX   = 0x48,
+  I2CERR_DATRX_ACKTX     = 0x50,
+  I2CERR_DATRX_NACKTX    = 0x58,
+  I2CERR_NOINFO          = 0xf8
+}
+i2cErr_e;
+
+//
+//
+//
+extern i2cErr_e i2cErrno;
+
+//
+//
+//
+void i2cInit (void);
+int i2cGetErrno (void);
+const char *i2cStrerror (int err);
+void i2cSetTimeout (unsigned int timeoutInMilliseconds);
+void i2cDump (void);
+int i2cWriteBuffer (U8 address, U8 *buffer, U32 bufferLength);
+int i2cReadBuffer (U8 address, U8 *buffer, U32 bufferLength);
+int i2cWriteReadBuffer (U8 address, U8 *buffer, U32 putLength, U32 getLength);
+int i2cWriteBufferPoll (U8 address, U8 *buffer, U32 bufferLength);
+int i2cWriteReadBufferPoll (U8 address, U8 *buffer, U32 putLength, U32 getLength);
+
+
+#endif
diff --git a/i2c/i2cInt.c b/i2c/i2cInt.c
new file mode 100644 (file)
index 0000000..80f0bdf
--- /dev/null
@@ -0,0 +1,405 @@
+#include "FreeRTOS.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/times.h>
+
+#include "i2c.h"
+
+//
+//  Default timeout, in milliseconds for generic read/write
+//
+#define I2C_DEFAULT_TIMEOUT 100
+#undef  I2C_DEBUG
+
+//
+//
+//
+typedef enum
+{
+  ACKPOLL_NO = 0,
+  ACKPOLL_YES
+}
+ackPoll_e;
+
+//
+//
+//
+static volatile int i2cBusInUse;
+static U8 i2cAddress;
+static U8 *i2cDataBuffer;
+static int i2cDataLenWrite;
+static int i2cDataLenRead;
+static unsigned int i2cTimeoutInTicks = I2C_DEFAULT_TIMEOUT / portTICK_RATE_MS;
+static int i2cDataCnt;
+static ackPoll_e i2cAckPoll = ACKPOLL_NO;
+
+//
+//
+//
+#ifdef I2C_DEBUG
+static U8 i2cTransactions [64];
+static int i2cTransactionsIndex;
+#define i2cDebug(x) do { if (i2cAckPoll && (i2cTransactionsIndex < (int) sizeof (i2cTransactions))) i2cTransactions [i2cTransactionsIndex++] = x; } while (0)
+#define i2cDebugReset() do { i2cTransactionsIndex = 0; } while (0)
+#else
+#define i2cDebug(x) do { } while (0)
+#define i2cDebugReset() do { } while (0)
+#endif
+
+static void i2cISR (void) __attribute__ ((interrupt ("IRQ")));
+static void i2cISR (void)
+{
+  i2cErrno = (I2C0_STAT & I2C_STAT_STATMASK);
+  i2cDebug (i2cErrno);
+
+  switch (i2cErrno)
+  {
+    //
+    //  Transmit conditions
+    //
+    case I2CERR_BUSERRORx : // 0x00
+      {
+        I2C0_CONSET = I2C_CONSET_STO | I2C_CONSET_AA;
+        i2cAckPoll = ACKPOLL_NO;
+        i2cBusInUse = FALSE;
+      }
+      break;
+
+    case I2CERR_STARTTX : // 0x08
+    case I2CERR_REPEATEDSTARTTX : // 0x10
+      {
+        i2cDebug (i2cAddress);
+        I2C0_DAT = i2cAddress;
+      }
+      break;
+
+    case I2CERR_SLAWTX_ACKRX : // 0x18
+    case I2CERR_DATTX_ACKRX : // 0x28
+      {
+        i2cAckPoll = ACKPOLL_NO;
+
+        if (i2cDataLenWrite && (i2cDataCnt < i2cDataLenWrite))
+        {
+          i2cDebug (i2cDataBuffer [i2cDataCnt]);
+          I2C0_DAT = i2cDataBuffer [i2cDataCnt++];
+          I2C0_CONCLR = I2C_CONCLR_STAC;
+        }
+        else
+        {
+          if (!i2cDataLenRead)
+          {
+            i2cDebug (0xff);
+            I2C0_CONCLR = I2C_CONCLR_STAC;
+            I2C0_CONSET = I2C_CONSET_STO;
+            i2cErrno = I2CERR_NONE;
+            i2cBusInUse = FALSE;
+          }
+          else
+          {
+            i2cDebug (0xfe);
+            i2cAddress |= 0x01;
+            i2cDataCnt = 0;
+            I2C0_CONSET = I2C_CONSET_STA;
+          }
+        }
+      }
+      break;
+
+    case I2CERR_DATRX_NACKTX : // 0x58
+      {
+        i2cDataBuffer [i2cDataCnt++] = I2C0_DAT;
+        i2cDebug (i2cDataBuffer [i2cDataCnt - 1]);
+        i2cErrno = I2CERR_NONE;
+      }
+
+    case I2CERR_SLAWTX_NACKRX : // 0x20
+    case I2CERR_SLARTX_NACKRX : // 0x48
+      {
+        if (i2cAckPoll)
+          break;
+      }
+
+    case I2CERR_DATTX_NACKRX : // 0x30
+      {
+        I2C0_CONCLR = I2C_CONCLR_STAC;
+        I2C0_CONSET = I2C_CONSET_STO;
+        i2cBusInUse = FALSE;
+      }
+      break;
+
+    case I2CERR_ARBLOST : // 0x38
+      {
+        I2C0_CONSET = I2C_CONSET_STA;
+      }
+      break;
+
+    //
+    //  Receive byte conditions (fall through is intentional)
+    //
+    case I2CERR_DATRX_ACKTX : // 0x50
+      {
+        i2cDataBuffer [i2cDataCnt++] = I2C0_DAT;
+        i2cDebug (i2cDataBuffer [i2cDataCnt - 1]);
+      }
+
+    case I2CERR_SLARTX_ACKRX : // 0x40
+      {
+        if (i2cDataCnt < i2cDataLenRead - 1)
+        {
+          I2C0_CONCLR = I2C_CONCLR_STAC;
+          I2C0_CONSET = I2C_CONSET_AA;
+        }
+        else
+          I2C0_CONCLR = I2C_CONCLR_STAC | I2C_CONCLR_AAC;
+      }
+      break;
+
+    case I2CERR_NOINFO :
+      break;
+
+    default:
+      {
+        I2C0_CONCLR = I2C_CONCLR_I2ENC;
+        i2cAckPoll = ACKPOLL_NO;
+        i2cBusInUse = FALSE;
+      }
+      break;
+  }
+
+  I2C0_CONCLR = I2C_CONSET_SI;
+  VIC_VectAddr = 0;
+}
+
+//
+// i2c1Init
+//
+void i2cInit (void)
+{
+  i2cBusInUse = FALSE;
+  i2cAckPoll = ACKPOLL_NO;
+
+  SCB_PCONP |= SCB_PCONP_PCI2C0;
+
+  PCB_PINSEL0 = (PCB_PINSEL0 & ~(PCB_PINSEL0_P02_MASK | PCB_PINSEL0_P03_MASK)) | (PCB_PINSEL0_P02_SCL0 | PCB_PINSEL0_P03_SDA0);
+
+  I2C0_CONCLR = I2C_CONCLR_MASK;
+  I2C0_CONSET = I2C_CONSET_I2EN;
+  I2C0_SCLL   = 240;
+  I2C0_SCLH   = 240;
+
+  //
+  //  Initialize the interrupt vector
+  //
+  VIC_IntSelect &= ~VIC_IntSelect_I2C0;
+  VIC_VectCntl7 = VIC_VectCntl_ENABLE | VIC_Channel_I2C0;
+  VIC_VectAddr7 = (int) i2cISR;
+  VIC_IntEnable = VIC_IntEnable_I2C0;
+}
+
+//
+//
+//
+static int i2cWaitComplete (int ticks)
+{
+  if (i2cBusInUse)
+  {
+    clock_t theFuture;
+
+    for (theFuture = times (NULL) + ticks; i2cBusInUse; )
+    {
+      if (times (NULL) > theFuture)
+      {
+        I2C0_CONCLR = I2C_CONCLR_I2ENC;
+        i2cErrno = I2CERR_TIMEOUTWC;
+        return -1;
+      }
+    }
+  }
+
+  return (i2cErrno == I2CERR_NONE) ? 0 : -1;
+}
+
+static int i2cPoll (U8 address)
+{
+  clock_t theFuture = times (NULL) + 10;
+
+  VIC_IntEnClr = VIC_IntEnClr_I2C0;
+
+  while (times (NULL) < theFuture)
+  {
+    I2C0_CONCLR = I2C_CONSET_SI;
+    I2C0_CONSET = I2C_CONSET_STA;
+
+    while (!(I2C0_CONSET & I2C_CONSET_SI))
+      ;
+
+    I2C0_CONCLR = I2C_CONCLR_STAC | I2C_CONCLR_SIC;
+    I2C0_DAT = address & ~0x01;
+
+    while (!(I2C0_CONSET & I2C_CONSET_SI))
+      ;
+
+    if ((i2cErrno = I2C0_STAT) == I2CERR_SLAWTX_ACKRX)
+      break;
+  }
+
+  if (i2cErrno != I2CERR_SLAWTX_ACKRX)
+    i2cErrno = I2CERR_TIMEOUTACKPOLL;
+
+  I2C0_CONCLR = I2C_CONCLR_SIC;
+  I2C0_CONSET = I2C_CONSET_STO | I2C_CONSET_AA;
+
+  while (I2C0_CONSET & I2C_CONSET_STO)
+    ;
+
+  VIC_IntEnable = VIC_IntEnable_I2C0;
+
+  return (i2cErrno == I2CERR_SLAWTX_ACKRX) ? 0 : -1;
+}
+
+//
+//
+//
+static int i2cKickOff (U8 address, U8 *buffer, int bufferLenWrite, int bufferLenRead, ackPoll_e ackPoll)
+{
+  //
+  //  Determine if our first operation will be a write or read.  If both, the
+  //  write always occurs first.
+  //
+  if (bufferLenWrite)
+    address &= ~0x01;
+  else if (bufferLenRead)
+    address |= 0x01;
+  else
+    address &= ~0x01;
+
+  //
+  //  Wait until last I2C operation has finished.  
+  //
+  if (i2cBusInUse && i2cWaitComplete (i2cTimeoutInTicks))
+  {
+    i2cErrno = I2CERR_TIMEOUT;
+    return -1;
+  }
+
+  //
+  //  Mark bus as in use, save the address, buffer and length
+  //
+  i2cBusInUse = TRUE;
+  i2cAddress = address;
+  i2cDataBuffer = buffer;
+  i2cDataLenWrite = bufferLenWrite;
+  i2cDataLenRead = bufferLenRead;
+  i2cDataCnt = 0;
+  i2cAckPoll = ackPoll;
+  i2cDebugReset ();
+
+  //
+  //  Clear any outstanding bits, enable the interface, and send a start bit.
+  //  Once the start bit goes out, the interrupt drive state machine begins.
+  //
+  I2C0_CONCLR = I2C_CONCLR_MASK;
+  I2C0_CONSET = I2C_CONSET_I2EN;
+  I2C0_CONSET = I2C_CONSET_STA;
+
+  return 0;
+}
+
+//
+//
+//
+static int i2cWriteBufferEx (U8 address, U8 *buffer, U32 bufferLength, int milliseconds)
+{
+  int r;
+
+  if (!(r = i2cKickOff (address, buffer, bufferLength, 0, ACKPOLL_NO)))
+    r = i2cWaitComplete (milliseconds / portTICK_RATE_MS);
+
+  return r;
+}
+
+static int i2cReadBufferEx (U8 address, U8 *buffer, U32 bufferLength, int milliseconds)
+{
+  int r;
+
+  if (!(r = i2cKickOff (address, buffer, 0, bufferLength, ACKPOLL_NO)))
+    r = i2cWaitComplete (milliseconds / portTICK_RATE_MS);
+
+  return r;
+}
+
+static int i2cWriteReadBufferEx (U8 address, U8 *buffer, U32 putLength, U32 getLength, int milliseconds)
+{
+  int r;
+
+  if (!(r = i2cKickOff (address, buffer, putLength, getLength, ACKPOLL_NO)))
+    r = i2cWaitComplete (milliseconds / portTICK_RATE_MS);
+
+  return r;
+}
+
+//
+//
+//
+void i2cSetTimeout (unsigned int timeoutInMilliseconds)
+{
+  if (timeoutInMilliseconds < portTICK_RATE_MS)
+    timeoutInMilliseconds = portTICK_RATE_MS;
+
+  i2cTimeoutInTicks = timeoutInMilliseconds / portTICK_RATE_MS;
+}
+
+void i2cDump (void)
+{
+#ifdef I2C_DEBUG
+  int i;
+
+  for (i = 0; i < i2cTransactionsIndex; i++)
+    printf ("0x%02x ", i2cTransactions [i]);
+
+  printf ("\n");
+#else
+  printf ("Not compiled for i2c debugging\n");
+#endif
+}
+
+//
+//  DANGER, WILL ROBINSON!  The callers buffer must persist until we're done
+//
+int i2cWriteBuffer (U8 address, U8 *buffer, U32 bufferLength)
+{
+  return i2cWriteBufferEx (address, buffer, bufferLength, i2cTimeoutInTicks);
+}
+
+int i2cReadBuffer (U8 address, U8 *buffer, U32 bufferLength)
+{
+  return i2cReadBufferEx (address, buffer, bufferLength, i2cTimeoutInTicks);
+}
+
+int i2cWriteReadBuffer (U8 address, U8 *buffer, U32 putLength, U32 getLength)
+{
+  return i2cWriteReadBufferEx (address, buffer, putLength, getLength, i2cTimeoutInTicks);
+}
+
+int i2cWriteBufferPoll (U8 address, U8 *buffer, U32 bufferLength)
+{
+  int r;
+
+  if (!(r = i2cKickOff (address, buffer, bufferLength, 0, ACKPOLL_NO)))
+    if (!(r = i2cWaitComplete (i2cTimeoutInTicks)))
+      r = i2cPoll (address);
+
+  return r;
+}
+
+int i2cWriteReadBufferPoll (U8 address, U8 *buffer, U32 putLength, U32 getLength)
+{
+  int r;
+
+  if (!(r = i2cKickOff (address, buffer, putLength, getLength, ACKPOLL_NO)))
+    if (!(r = i2cWaitComplete (i2cTimeoutInTicks)))
+      r = i2cPoll (address);
+
+  return r;
+}
diff --git a/i2c/i2cIntWorking.c b/i2c/i2cIntWorking.c
new file mode 100644 (file)
index 0000000..7ef4f11
--- /dev/null
@@ -0,0 +1,342 @@
+#include "FreeRTOS.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/times.h>
+
+#include "i2c.h"
+
+//
+//  Default timeout, in milliseconds for generic read/write
+//
+#define I2C_DEFAULT_TIMEOUT 100
+
+//
+//
+//
+static volatile int i2cBusInUse;
+static U8 i2cAddress;
+static U8 *i2cDataBuffer;
+static int i2cDataLenWrite;
+static int i2cDataLenRead;
+static int i2cTimeout = I2C_DEFAULT_TIMEOUT;
+static U8 *i2cDataPtr;
+static U8 i2cTransactions [64];
+static int i2cTransactionsIndex;
+
+//
+//
+//
+#define i2cDebug(x) do { if (i2cTransactionsIndex < (int) sizeof (i2cTransactions)) i2cTransactions [i2cTransactionsIndex++] = x; } while (0)
+
+static void i2cISR (void) __attribute__ ((interrupt ("IRQ")));
+static void i2cISR (void)
+{
+  i2cErrno = (I2C0_STAT & I2C_STAT_STATMASK);
+  i2cDebug (i2cErrno);
+
+  switch (i2cErrno)
+  {
+    //
+    //  Transmit conditions
+    //
+    case I2CERR_BUSERRORx : // 0x00
+      {
+        I2C0_CONSET = I2C_CONSET_STO | I2C_CONSET_AA;
+        i2cBusInUse = FALSE;
+      }
+      break;
+
+    case I2CERR_STARTTX : // 0x08
+      {
+        i2cDebug (i2cAddress);
+        I2C0_DAT = i2cAddress;
+      }
+      break;
+
+    case I2CERR_REPEATEDSTARTTX : // 0x10
+      {
+        i2cDebug (i2cAddress);
+        I2C0_DAT = i2cAddress;
+      }
+      break;
+
+    case I2CERR_SLAWTX_ACKRX : // 0x18
+      {
+        i2cDebug (*i2cDataPtr);
+        I2C0_DAT = *i2cDataPtr++;
+        I2C0_CONCLR = I2C_CONCLR_STAC;
+      }
+      break;
+
+    case I2CERR_SLAWTX_NACKRX : // 0x20
+      {
+        I2C0_CONSET = I2C_CONSET_STO;
+        i2cBusInUse = FALSE;
+      }
+      break;
+
+    case I2CERR_DATTX_ACKRX : // 0x28
+      {
+        if (--i2cDataLenWrite)
+        {
+          i2cDebug (*i2cDataPtr);
+          I2C0_DAT = *i2cDataPtr++;
+          I2C0_CONCLR = I2C_CONCLR_STAC;
+        }
+        else
+        {
+          if (!i2cDataLenRead)
+          {
+            i2cDebug (0xff);
+            I2C0_CONCLR = I2C_CONCLR_STAC;
+            I2C0_CONSET = I2C_CONSET_STO;
+            i2cBusInUse = FALSE;
+          }
+          else
+          {
+            i2cDebug (0xfe);
+            i2cAddress |= 0x01;
+            i2cDataPtr = i2cDataBuffer;
+            I2C0_CONSET = I2C_CONSET_STA;
+          }
+        }
+      }
+      break;
+
+    case I2CERR_DATTX_NACKRX : // 0x30
+      {
+        I2C0_CONCLR = I2C_CONCLR_STAC;
+        I2C0_CONSET = I2C_CONSET_STO;
+        i2cBusInUse = FALSE;
+      }
+      break;
+
+    case I2CERR_ARBLOST : // 0x38
+      {
+        I2C0_CONSET = I2C_CONSET_STA;
+      }
+      break;
+
+    //
+    //  Receive byte conditions
+    //
+    case I2CERR_SLARTX_ACKRX : // 0x40
+      {
+        I2C0_CONCLR = I2C_CONCLR_STAC;
+        I2C0_CONSET = I2C_CONSET_AA;
+      }
+      break;
+
+    case I2CERR_SLARTX_NACKRX : // 0x48
+      {
+        I2C0_CONCLR = I2C_CONCLR_STAC;
+        I2C0_CONSET = I2C_CONSET_STO;
+        i2cBusInUse = FALSE;
+      }
+      break;
+
+    case I2CERR_DATRX_ACKTX : // 0x50
+      {
+        *i2cDataPtr++ = I2C0_DAT;
+        i2cDebug (*(i2cDataPtr - 1));
+
+        if (--i2cDataLenRead)
+        {
+          I2C0_CONCLR = I2C_CONCLR_STAC;
+          I2C0_CONSET = I2C_CONSET_AA;
+        }
+        else
+        {
+          I2C0_CONCLR = I2C_CONCLR_STAC | I2C_CONCLR_AAC;
+          i2cBusInUse = FALSE;
+        }
+      }
+      break;
+
+    case I2CERR_DATRX_NACKTX : // 0x58
+      {
+        // *i2cDataPtr = I2C0_DAT;
+        // i2cDebug (*i2cDataPtr);
+        I2C0_CONCLR = I2C_CONCLR_STAC;
+        I2C0_CONSET = I2C_CONSET_STO;
+        i2cBusInUse = FALSE;
+      }
+      break;
+
+    case I2CERR_NOINFO :
+      break;
+
+    default:
+      {
+        I2C0_CONCLR = I2C_CONCLR_I2ENC;
+        i2cBusInUse = FALSE;
+      }
+      break;
+  }
+
+  I2C0_CONCLR = I2C_CONSET_SI;
+  VIC_VectAddr = 0;
+}
+
+//
+// i2c1Init
+//
+void i2cInit (void)
+{
+  i2cBusInUse = FALSE;
+
+  SCB_PCONP |= SCB_PCONP_PCI2C0;
+
+  PCB_PINSEL0 = (PCB_PINSEL0 & ~(PCB_PINSEL0_P02_MASK | PCB_PINSEL0_P03_MASK)) | (PCB_PINSEL0_P02_SCL0 | PCB_PINSEL0_P03_SDA0);
+
+  I2C0_CONCLR = I2C_CONCLR_MASK;
+  I2C0_CONSET = I2C_CONSET_I2EN;
+  I2C0_SCLL   = 240;
+  I2C0_SCLH   = 240;
+
+  //
+  //  Initialize the interrupt vector
+  //
+  VIC_IntSelect &= ~VIC_IntSelect_I2C0;
+  VIC_VectCntl7 = VIC_VectCntl_ENABLE | VIC_Channel_I2C0;
+  VIC_VectAddr7 = (int) i2cISR;
+  VIC_IntEnable = VIC_IntEnable_I2C0;
+}
+
+//
+//
+//
+static int i2cTransferBytes (U8 address, U8 *buffer, int bufferLenWrite, int bufferLenRead)
+{
+  //
+  //  Determine if our first operation will be a write or read.  If both, the
+  //  write always occurs first.
+  //
+  if (bufferLenWrite)
+    address &= ~0x01;
+  else if (bufferLenRead)
+    address |= 0x01;
+  else
+  {
+    i2cErrno = I2CERR_OTHER;
+    return -1;
+  }
+
+  //
+  //  Wait until last I2C operation has finished.  
+  //
+  if (i2cBusInUse && i2cWaitComplete (i2cTimeout))
+  {
+    i2cErrno = I2CERR_TIMEOUT;
+    return -1;
+  }
+
+  //
+  //  Mark bus as in use, save the address, buffer and length
+  //
+  i2cBusInUse = TRUE;
+  i2cAddress = address;
+  i2cDataBuffer = buffer;
+  i2cDataLenWrite = bufferLenWrite;
+  i2cDataLenRead = bufferLenRead;
+  i2cDataPtr = buffer;
+
+  i2cTransactionsIndex = 0; // ###
+
+  I2C0_CONCLR = I2C_CONCLR_MASK;
+  I2C0_CONSET = I2C_CONSET_I2EN;
+  I2C0_CONSET = I2C_CONSET_STA;
+
+  return 0;
+}
+
+//
+//
+//
+int i2cWaitComplete (int milliseconds)
+{
+  if (i2cBusInUse)
+  {
+    clock_t theFuture;
+
+    if (milliseconds < 10)
+      milliseconds = 10;
+
+    for (theFuture = times (NULL) + (milliseconds / 10); i2cBusInUse; )
+    {
+      if (times (NULL) > theFuture)
+      {
+        I2C0_CONCLR = I2C_CONCLR_I2ENC;
+        i2cErrno = I2CERR_TIMEOUTWC;
+        return -1;
+      }
+    }
+  }
+
+  return 0;
+}
+
+//
+//
+//
+static int i2cWriteBufferEx (U8 address, U8 *buffer, U32 bufferLength, int milliseconds)
+{
+  if (i2cTransferBytes (address, buffer, bufferLength, 0))
+    return -1;
+
+  return i2cWaitComplete (milliseconds);
+}
+
+static int i2cReadBufferEx (U8 address, U8 *buffer, U32 bufferLength, int milliseconds)
+{
+  if (i2cTransferBytes (address, buffer, 0, bufferLength))
+    return -1;
+
+  return i2cWaitComplete (milliseconds);
+}
+
+static int i2cWriteReadBufferEx (U8 address, U8 *buffer, U32 putLength, U32 getLength, int milliseconds)
+{
+  if (i2cTransferBytes (address, buffer, putLength, getLength))
+    return -1;
+
+  return i2cWaitComplete (milliseconds);
+}
+
+//
+//  DANGER, WILL ROBINSON!  The callers buffer must persist until we're done
+//
+int i2cWriteBuffer (U8 address, U8 *buffer, U32 bufferLength)
+{
+  return i2cWriteBufferEx (address, buffer, bufferLength, i2cTimeout);
+}
+
+int i2cReadBuffer (U8 address, U8 *buffer, U32 bufferLength)
+{
+  return i2cReadBufferEx (address, buffer, bufferLength, i2cTimeout);
+}
+
+int i2cWriteReadBuffer (U8 address, U8 *buffer, U32 putLength, U32 getLength)
+{
+  return i2cWriteReadBufferEx (address, buffer, putLength, getLength, i2cTimeout);
+}
+
+void i2cSetTimeout (int timeoutInMilliseconds)
+{
+  if (timeoutInMilliseconds < 10)
+    timeoutInMilliseconds = 10;
+
+  i2cTimeout = timeoutInMilliseconds;
+}
+
+void i2cDump (void)
+{
+  int i;
+
+  for (i = 0; i < i2cTransactionsIndex; i++)
+    printf ("0x%02x ", i2cTransactions [i]);
+
+  printf ("\n");
+}
+
diff --git a/i2c/i2cPolled.c b/i2c/i2cPolled.c
new file mode 100644 (file)
index 0000000..3b0aa80
--- /dev/null
@@ -0,0 +1,412 @@
+#include "FreeRTOS.h"
+
+#include <stdio.h>
+#include <sys/times.h>
+
+#include "i2c.h"
+
+//
+//  Default timeout, in milliseconds for generic read/write
+//
+#define I2C_DEFAULT_TIMEOUT 100
+
+//
+//
+//
+typedef enum
+{
+  I2CFLAGS_START         = 0x0001,
+  I2CFLAGS_REPEATEDSTART = 0x0002,
+  I2CFLAGS_STOP          = 0x0004,
+  I2CFLAGS_ADDRESS       = 0x0008,
+  I2CFLAGS_WRITEDATA     = 0x0010,
+  I2CFLAGS_READDATA      = 0x0020,
+}
+i2cFlags_e;
+
+typedef enum
+{
+  I2CMODE_ACK = 0,
+  I2CMODE_NACK,
+  I2CMODE_READ
+}
+i2cMode_e;
+
+//
+//
+//
+static unsigned int i2cTimeoutInTicks = I2C_DEFAULT_TIMEOUT / portTICK_RATE_MS;
+
+//
+//  Our PCLK is 48Mhz (12Mhz Xtal, PLL x 4, VBPDIV = /1), we want 100Khz SCLK
+//
+void i2cInit (void)
+{
+  SCB_PCONP |= SCB_PCONP_PCI2C0;
+
+  PCB_PINSEL0 = (PCB_PINSEL0 & ~(PCB_PINSEL0_P02_MASK | PCB_PINSEL0_P03_MASK)) | (PCB_PINSEL0_P02_SCL0 | PCB_PINSEL0_P03_SDA0);
+
+  I2C0_CONCLR = I2C_CONCLR_MASK;
+  I2C0_CONSET = I2C_CONSET_I2EN;
+  I2C0_SCLL   = 480;
+  I2C0_SCLH   = 480;
+}
+
+//
+//
+//
+static i2cErr_e i2cStatus (void)
+{
+  i2cErr_e status;
+
+  while (!(I2C0_CONSET & I2C_CONSET_SI))
+    ;
+
+  if ((status = I2C0_STAT) == I2CERR_BUSERRORx)
+    return I2CERR_BUSERROR;
+
+  return status;
+}
+
+//
+//
+//
+static i2cErr_e i2cStop (void)
+{
+  I2C0_CONCLR = I2C_CONCLR_SIC;
+  I2C0_CONSET = I2C_CONSET_STO;
+
+  while (I2C0_CONSET & I2C_CONSET_STO)
+    ;
+
+  return I2CERR_NONE;
+}
+
+//
+//
+//
+static i2cErr_e i2cStart (void)
+{
+  I2C0_CONCLR = I2C_CONCLR_SIC;
+  I2C0_CONSET = I2C_CONSET_STA;
+
+  while (1)
+  {
+    i2cErr_e status;
+
+    if (((status = i2cStatus ()) == I2CERR_STARTTX) || (status == I2CERR_REPEATEDSTARTTX))
+    {
+      I2C0_CONCLR = I2C_CONCLR_STAC;
+      return I2CERR_NONE;
+    }
+    else if (status != I2CERR_NOINFO)
+    {
+      I2C0_CONCLR = I2C_CONCLR_STAC;
+      return status;
+    }
+    else
+      I2C0_CONCLR = I2C_CONCLR_SIC;
+  }
+}
+
+//
+//
+//
+static i2cErr_e i2cRepeatedStart (void)
+{
+  while (!(I2C0_CONSET & I2C_CONSET_SI))
+    ;
+
+  I2C0_CONCLR = I2C_CONCLR_SIC;
+  I2C0_CONSET = I2C_CONSET_STA;
+
+  while (1)
+  {
+    i2cErr_e status;
+
+    if (((status = i2cStatus ()) == I2CERR_STARTTX) || (status == I2CERR_REPEATEDSTARTTX))
+    {
+      I2C0_CONCLR = I2C_CONCLR_STAC;
+      return I2CERR_NONE;
+    }
+    else if (status != I2CERR_NOINFO)
+    {
+      I2C0_CONCLR = I2C_CONCLR_STAC;
+      return status;
+    }
+    else
+      I2C0_CONCLR = I2C_CONCLR_SIC;
+  }
+}
+
+//
+//
+//
+static i2cErr_e i2cPutByte (U8 data)
+{
+  if (!(I2C0_CONSET & I2C_CONSET_SI))
+    return I2CERR_BUSY;
+
+  I2C0_DAT = data;
+  I2C0_CONCLR = I2C_CONCLR_SIC;
+
+  return I2CERR_NONE;
+}
+
+//
+//
+//
+static i2cErr_e i2cGetByte (i2cMode_e mode, U8 *pData)
+{
+  switch (mode)
+  {
+    case I2CMODE_ACK :
+      I2C0_CONCLR = I2C_CONCLR_SIC;
+      I2C0_CONSET = I2C_CONSET_AA;
+      break;
+
+    case I2CMODE_NACK :
+      I2C0_CONCLR = (I2C_CONCLR_AAC | I2C_CONCLR_SIC);
+      break;
+
+    case I2CMODE_READ :
+      {
+        if (!(I2C0_CONSET & I2C_CONSET_SI))
+          return I2CERR_EMPTY;
+
+        *pData = (U8) I2C0_DAT;
+      }
+      break;
+  }
+
+  return I2CERR_NONE;
+} 
+
+//
+//
+//
+static i2cErr_e i2cWriteBufferEx (U8 address, U8 *buffer, U32 bufferLength, i2cFlags_e flags)
+{
+  U32 i;
+  i2cErr_e status;
+
+  if (flags & I2CFLAGS_START)
+  {
+    if ((status = i2cStart ()) != I2CERR_NONE)
+    {
+      i2cStop ();
+      return status;
+    }
+  }
+  else if (flags & I2CFLAGS_REPEATEDSTART)
+  {
+    if ((status = i2cRepeatedStart ()) != I2CERR_NONE)
+    {
+      i2cStop ();
+      return status;
+    }
+  }
+
+  if (flags & I2CFLAGS_ADDRESS)
+  {
+    do
+      if (((status = i2cPutByte (address & ~0x01)) != I2CERR_NONE) && (status != I2CERR_BUSY))
+        return status;
+    while (status == I2CERR_BUSY);
+  }
+
+  if (flags & I2CFLAGS_WRITEDATA)
+  {
+    for (i = 0; i < bufferLength; i++, buffer++)
+    {
+      while (1)
+      {
+        if (((status = i2cStatus ()) == I2CERR_SLAWTX_ACKRX) || (status == I2CERR_DATTX_ACKRX))
+        {
+          do
+            if (((status = i2cPutByte (*buffer)) != I2CERR_NONE) && (status != I2CERR_BUSY))
+              return status;
+          while (status == I2CERR_BUSY);
+
+          break;
+        }
+        else if (status != I2CERR_NOINFO)
+        {
+          i2cStop ();
+          return status;
+        }
+      }
+    }
+  }
+
+  if (flags & I2CFLAGS_STOP)
+  {
+    while (1)
+    {
+      if (((status = i2cStatus ()) == I2CERR_SLAWTX_ACKRX) || (status == I2CERR_DATTX_ACKRX))
+      {
+        i2cStop ();
+        return I2CERR_NONE;
+      }
+      else if (status != I2CERR_NOINFO)
+      {
+        i2cStop ();
+        return status;
+      }
+    }
+  }
+
+  return I2CERR_NONE;
+}
+
+//
+//
+//
+static i2cErr_e i2cReadBufferEx (U8 address, U8 *buffer, U32 bufferLength, i2cFlags_e flags)
+{
+  U32 i;
+  i2cErr_e status;
+
+  if (flags & I2CFLAGS_START)
+  {
+    if ((status = i2cStart ()) != I2CERR_NONE)
+    {
+      i2cStop ();
+      return status;
+    }
+  }
+  else if (flags & I2CFLAGS_REPEATEDSTART)
+  {
+    if ((status = i2cRepeatedStart ()) != I2CERR_NONE)
+    {
+      i2cStop ();
+      return status;
+    }
+  }
+
+  if (flags & I2CFLAGS_ADDRESS)
+  {
+    do
+      if (((status = i2cPutByte (address | 0x01)) != I2CERR_NONE) && (status != I2CERR_BUSY))
+        return status;
+    while (status == I2CERR_BUSY);
+  }
+
+  if (flags & I2CFLAGS_READDATA)
+  {
+    for (i = 0; i < bufferLength; i++, buffer++)
+    {
+      while (1)
+      {
+        if (((status = i2cStatus ()) == I2CERR_SLARTX_ACKRX) || (status == I2CERR_SLARTX_NACKRX) || (status == I2CERR_DATRX_ACKTX))
+        {
+          i2cGetByte ((i != bufferLength - 1) ? I2CMODE_ACK : I2CMODE_NACK, NULL);
+
+          do
+            status = i2cGetByte (I2CMODE_READ, buffer);
+          while (status == I2CERR_EMPTY);
+
+          break;
+        }
+        else if (status != I2CERR_NOINFO)
+        {
+          i2cStop ();
+          return status;
+        }
+      }
+    }
+  }
+
+  if (flags & I2CFLAGS_STOP)
+    i2cStop ();
+
+  return I2CERR_NONE;
+}
+
+//
+//
+//
+static int i2cPoll (U8 address)
+{
+  clock_t theFuture = times (NULL) + i2cTimeoutInTicks;
+
+  while (times (NULL) < theFuture)
+  {
+    if ((i2cErrno = i2cStart ()) != I2CERR_NONE)
+      break;
+    if ((i2cErrno = i2cPutByte (address & ~0x01)) != I2CERR_NONE)
+      break;
+    if ((i2cErrno = i2cStatus ()) == I2CERR_SLAWTX_ACKRX)
+      break;
+  }
+
+  if (i2cErrno != I2CERR_SLAWTX_ACKRX)
+    i2cErrno = I2CERR_TIMEOUTACKPOLL;
+
+  i2cStop ();
+
+  return (i2cErrno == I2CERR_SLAWTX_ACKRX) ? 0 : -1;
+}
+
+//
+//
+//
+void i2cSetTimeout (unsigned int timeoutInMilliseconds)
+{
+  if (timeoutInMilliseconds < portTICK_RATE_MS)
+    timeoutInMilliseconds = portTICK_RATE_MS;
+
+  i2cTimeoutInTicks = timeoutInMilliseconds / portTICK_RATE_MS;
+}
+
+void i2cDump (void)
+{
+  printf ("i2cDump not implemented for polled mode\n");
+}
+
+int i2cWriteBuffer (U8 address, U8 *buffer, U32 bufferLength)
+{
+  if ((i2cErrno = i2cWriteBufferEx (address, buffer, bufferLength, I2CFLAGS_START | I2CFLAGS_ADDRESS | I2CFLAGS_WRITEDATA | I2CFLAGS_STOP)) != I2CERR_NONE)
+    return -1;
+
+  return 0;
+}
+
+int i2cReadBuffer (U8 address, U8 *buffer, U32 bufferLength)
+{
+  if ((i2cErrno = i2cReadBufferEx (address, buffer, bufferLength, I2CFLAGS_START | I2CFLAGS_ADDRESS | I2CFLAGS_READDATA | I2CFLAGS_STOP)) != I2CERR_NONE)
+    return -1;
+
+  return 0;
+}
+
+int i2cWriteReadBuffer (U8 address, U8 *buffer, U32 putLength, U32 getLength)
+{
+  if ((i2cErrno = i2cWriteBufferEx (address, buffer, putLength, I2CFLAGS_START | I2CFLAGS_ADDRESS | I2CFLAGS_WRITEDATA)) != I2CERR_NONE)
+    return -1;
+
+  if ((i2cErrno = i2cReadBufferEx (address, buffer, getLength, I2CFLAGS_REPEATEDSTART | I2CFLAGS_ADDRESS | I2CFLAGS_READDATA | I2CFLAGS_STOP)) != I2CERR_NONE)
+    return -1;
+
+  return 0;
+}
+
+int i2cWriteBufferPoll (U8 address, U8 *buffer, U32 bufferLength)
+{
+  int r;
+
+  if (!(r = i2cWriteBuffer (address, buffer, bufferLength)))
+    r = i2cPoll (address);
+
+  return r;
+}
+
+int i2cWriteReadBufferPoll (U8 address, U8 *buffer, U32 putLength, U32 getLength)
+{
+  int r;
+
+  if (!(r = i2cWriteReadBuffer (address, buffer, putLength, getLength)))
+    r = i2cPoll (address);
+
+  return r;
+}
diff --git a/i2c/lm75.c b/i2c/lm75.c
new file mode 100644 (file)
index 0000000..a334f54
--- /dev/null
@@ -0,0 +1,158 @@
+#include "FreeRTOS.h"
+
+#include "i2c.h"
+#include "lm75.h"
+
+//
+//
+//
+static U8 lm75Address = LM75_ADDRESS;
+static U8 lm75LastRegister = LM75_REGISTER_TEMPERATURE;
+static U8 lm75Mode = 0;
+
+//
+//
+//
+static int lm75Read8 (U8 reg, int *value)
+{
+  lm75LastRegister = reg;
+  *value = 0;
+
+  if (i2cWriteBuffer (lm75Address, (U8 *) &reg, sizeof (U8)))
+    return -1;
+
+  return i2cReadBuffer (lm75Address, (U8 *) value, sizeof (U8));
+}
+
+static int lm75Write8 (U8 reg, int value)
+{
+  U8 buffer [2];
+
+  buffer [0] = lm75LastRegister = reg;
+  buffer [1] = value;
+
+  return i2cWriteBuffer (lm75Address, buffer, sizeof (buffer));
+}
+
+//
+//  DANGER, WILL ROBINSON!  'value' is the desired temperature * 2, where
+//  the low bit indicates 0.5C or not.  So for -50C degrees, we see -100.
+//  For -50.5C, we see -101.
+//
+static int lm75Read16 (U8 reg, int *value)
+{
+  U8 buffer [2];
+
+  buffer [0] = lm75LastRegister = reg;
+
+  if (!lm75Mode)
+  {
+    if (i2cWriteReadBuffer (lm75Address, buffer, sizeof (U8), sizeof (buffer)))
+      return -1;
+  }
+  else
+  {
+    if (i2cWriteBuffer (lm75Address, (U8 *) &reg, sizeof (U8)))
+      return -1;
+
+    if (i2cReadBuffer (lm75Address, buffer, sizeof (buffer)))
+      return -1;
+  }
+
+  //
+  //  Sign extend negative numbers
+  //
+  *value = ((buffer [0] << 8) | buffer [1]) >> 7;
+
+  if (buffer [0] & 0x80)
+    *value |= 0xfffffe00;
+
+  return I2CERR_NONE;
+}
+
+static int lm75Write16 (U8 reg, int value)
+{
+  U8 buffer [3];
+
+  value <<= 7;
+
+  buffer [0] = lm75LastRegister = reg;
+  buffer [1] = value >> 8;
+  buffer [2] = value;
+
+  return i2cWriteBuffer (lm75Address, buffer, sizeof (buffer));
+}
+
+//
+//  Don't call lm75Init() before tasker is started.  The I2C routines use the
+//  newlib/syscalls.c _times function, which calls xTaskGetTickCount(), which
+//  hasn't been initialized yet.
+//
+int lm75Init (void)
+{
+  return lm75ConfigWrite (0);
+}
+
+void lm75SetMode (int mode)
+{
+  lm75Mode = mode;
+}
+
+void lm75SetAddress (U8 address)
+{
+  lm75Address = address;
+}
+
+int lm75ReRead (int *value)
+{
+  *value = 0;
+
+  if (lm75LastRegister == LM75_REGISTER_CONFIGURATION)
+    return i2cReadBuffer (lm75Address, (U8 *) value, sizeof (U8));
+  else
+  {
+    U8 buffer [2];
+
+    if (i2cReadBuffer (lm75Address, buffer, sizeof (buffer)))
+      return -1;
+
+    *value = ((buffer [0] << 8) | buffer [1]) >> 7;
+  }
+
+  return I2CERR_NONE;
+}
+
+int lm75TemperatureRead (int *temp)
+{
+  return lm75Read16 (LM75_REGISTER_TEMPERATURE, temp);
+}
+
+int lm75ConfigRead (int *configValue)
+{
+  return lm75Read8 (LM75_REGISTER_CONFIGURATION, configValue);
+}
+
+int lm75ConfigWrite (int configValue)
+{
+  return lm75Write8 (LM75_REGISTER_CONFIGURATION, configValue);
+}
+
+int lm75THYSTRead (int *thystValue)
+{
+  return lm75Read16 (LM75_REGISTER_THYST, thystValue);
+}
+
+int lm75THYSTWrite (int thystValue)
+{
+  return lm75Write16 (LM75_REGISTER_THYST, thystValue);
+}
+
+int lm75TOSTRead (int *thystValue)
+{
+  return lm75Read16 (LM75_REGISTER_TOS, thystValue);
+}
+
+int lm75TOSWrite (int thystValue)
+{
+  return lm75Write16 (LM75_REGISTER_TOS, thystValue);
+}
diff --git a/i2c/lm75.h b/i2c/lm75.h
new file mode 100644 (file)
index 0000000..d51fdfd
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef _LM75_H_
+#define _LM75_H_
+
+//
+//
+//
+#define LM75_ADDRESS (0x90)
+
+#define LM75_REGISTER_TEMPERATURE   (0x00)
+#define LM75_REGISTER_CONFIGURATION (0x01)
+#define LM75_REGISTER_THYST         (0x02)
+#define LM75_REGISTER_TOS           (0x03)
+
+//
+//
+//
+int  lm75Init (void);
+void lm75SetMode (int mode);
+void lm75SetAddress (U8 address);
+int  lm75ReRead (int *value);
+int  lm75TemperatureRead (int *temp);
+int  lm75ConfigRead (int *configValue);
+int  lm75ConfigWrite (int configValue);
+int  lm75THYSTRead (int *thystValue);
+int  lm75THYSTWrite (int thystValue);
+int  lm75TOSTRead (int *thystValue);
+int  lm75TOSWrite (int thystValue);
+
+#endif
diff --git a/iap/Makefile b/iap/Makefile
new file mode 100644 (file)
index 0000000..a792c99
--- /dev/null
@@ -0,0 +1,25 @@
+SRC_FILES=iap.c 
+
+#
+# Define all object files.
+#
+ARM_OBJ = $(SRC_FILES:.c=.o)
+
+.PHONY: all
+all: $(ARM_OBJ)
+
+$(ARM_OBJ) : %.o : %.c Makefile .depend
+       $(CC) -c $(CFLAGS) $< -o $@
+       $(AR) r $(COMMON)/common.a $@
+
+#
+#  The .depend files contains the list of header files that the
+#  various source files depend on.  By doing this, we'll only
+#  rebuild the .o's that are affected by header files changing.
+#
+.depend:
+                       $(CC) $(CFLAGS) -M $(SRC_FILES) > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff --git a/iap/iap.c b/iap/iap.c
new file mode 100644 (file)
index 0000000..35bd67c
--- /dev/null
+++ b/iap/iap.c
@@ -0,0 +1,537 @@
+#include "FreeRTOS.h"
+
+#include <string.h>
+#include "../cpu/cpu.h"
+#include "iap.h"
+
+//
+//
+//
+#define CPUCLK_IN_KHZ 48000
+
+#define IRQ_MASK  0x00000080
+#define FIQ_MASK  0x00000040
+#define INTs_MASK (IRQ_MASK | FIQ_MASK)
+
+//
+//
+//
+typedef struct flashSectorToAddress_s
+{
+  unsigned long address;
+  int sizeInBytes;
+}
+flashSectorToAddress_t;
+
+static flashSectorToAddress_t flashSectorToAddress [] = 
+{
+  { 0x00000000, 4096 },   // 0
+  { 0x00001000, 4096 },   // 1
+  { 0x00002000, 4096 },   // 2
+  { 0x00003000, 4096 },   // 3
+  { 0x00004000, 4096 },   // 4
+  { 0x00005000, 4096 },   // 5
+  { 0x00006000, 4096 },   // 6
+  { 0x00007000, 4096 },   // 7
+  { 0x00008000, 32768 },  // 8
+  { 0x00010000, 32768 },  // 9
+  { 0x00018000, 32768 },  // 10
+  { 0x00020000, 32768 },  // 11
+  { 0x00028000, 32768 },  // 12
+  { 0x00030000, 32768 },  // 13
+  { 0x00038000, 32768 },  // 14
+  { 0x00040000, 32768 },  // 15
+  { 0x00048000, 32768 },  // 16
+  { 0x00050000, 32768 },  // 17
+  { 0x00058000, 32768 },  // 18
+  { 0x00060000, 32768 },  // 19
+  { 0x00068000, 32768 },  // 20
+  { 0x00070000, 32768 },  // 21
+  { 0x00078000, 4096 },   // 22
+  { 0x00079000, 4096 },   // 23
+  { 0x0007a000, 4096 },   // 24
+  { 0x0007b000, 4096 },   // 25
+  { 0x0007c000, 4096 },   // 26
+};
+
+typedef struct iapErrnoStr_s
+{
+  int errno;
+  const char *text;
+}
+iapErrnoStr_t;
+
+static iapErrnoStr_t iapErrnoStr [] =
+{
+  { IAP_RESULT_CMD_SUCCESS,         "success" },
+  { IAP_RESULT_INVALID_COMMAND,     "invalid command" },
+  { IAP_RESULT_SRC_ADDR_ERROR,      "source address error" },
+  { IAP_RESULT_DST_ADDR_ERROR,      "destination address error" },
+  { IAP_RESULT_SRC_ADDR_NOT_MAPPED, "source address not mapped" },
+  { IAP_RESULT_DST_ADDR_NOT_MAPPED, "destination address not mapped" },
+  { IAP_RESULT_COUNT_ERROR,         "count error" },
+  { IAP_RESULT_INVALID_SECTOR,      "invalid sector" },
+  { IAP_RESULT_SECTOR_NOT_BLANK,    "sector not blank" },
+  { IAP_RESULT_SECTOR_NOT_PREPARED, "sector not prepared" },
+  { IAP_RESULT_COMPARE_ERROR,       "compare error" },
+  { IAP_RESULT_BUSY,                "busy" },
+  { IAP_RESULT_PARAM_ERROR,         "parameter error" },
+  { IAP_RESULT_ADDR_ERROR,          "address error" },
+  { IAP_RESULT_ADDR_NOT_MAPPED,     "address not mapped" },
+  { IAP_RESULT_CMD_LOCKED,          "command locked" },
+  { IAP_RESULT_INVALID_CODE,        "invalid code" },
+  { IAP_RESULT_INVALID_BAUD_RATE,   "invalid baud rate" },
+  { IAP_RESULT_ANVALID_STOP_BIT,    "invalid stop bit" },
+  { IAP_RESULT_CRP_ENABLED,         "CRP enabled" },
+  { IAP_RESULT_X_NOTSAFEREGION,     "sector or address not in safe region" },
+  { IAP_RESULT_X_NOSAFEREGIONAVAIL, "no safe sectors available (all of memory used?)" },
+};
+
+//
+//
+//
+static unsigned int iapCommands [5];
+static unsigned int iapResults [2];
+static int iapErrno = 0;
+extern unsigned long __end_of_text__;
+static unsigned int end_of_text = (unsigned int) &__end_of_text__;
+
+
+//
+//
+//
+void iapInit (void)
+{
+}
+
+//
+//
+//
+int iapSectorToAddress (int sectorNumber, unsigned long *address, int *sectorSize)
+{
+  if (sectorNumber >= (int) arrsizeof (flashSectorToAddress))
+    return -1;
+
+  if (address)
+    *address = flashSectorToAddress [sectorNumber].address;
+  if (sectorSize)
+    *sectorSize = flashSectorToAddress [sectorNumber].sizeInBytes;
+
+  return 0;
+}
+
+//
+//  Convert address to sector, or -1 if address not in flash area
+//
+int iapAddressToSector (unsigned long address)
+{
+  int i;
+
+  for (i = 0; i < (int) arrsizeof (flashSectorToAddress); i++)
+    if (address < (flashSectorToAddress [i].address + flashSectorToAddress [i].sizeInBytes))
+      return i;
+
+  iapErrno = IAP_RESULT_INVALID_SECTOR;
+  return -1;
+}
+
+//
+//  1 == address in safe region, 0 if not
+//
+int iapIsSafeAddress (unsigned long address)
+{
+  int eotSector;
+  int addressSector;
+
+  if ((eotSector = iapAddressToSector (end_of_text)) == -1)
+    return 0;
+  if ((addressSector = iapAddressToSector (address)) == -1)
+    return 0;
+
+  if (addressSector <= eotSector)
+  {
+    iapErrno = IAP_RESULT_X_NOTSAFEREGION;
+    return 0;
+  }
+
+  return 1;
+}
+
+//
+//  0 == not safe sector, 1 == safe (not in a code sector)
+//
+int iapIsSafeSector (int sector)
+{
+  int eotSector;
+
+  if ((eotSector = iapAddressToSector (end_of_text)) == -1)
+    return 0;
+
+  if (sector <= eotSector)
+  {
+    iapErrno = IAP_RESULT_X_NOTSAFEREGION;
+    return 0;
+  }
+
+  return 1;
+}
+
+//
+//  Returns a safe sector number or -1 if none available
+//
+int iapFindSafeSector (void)
+{
+  unsigned int i;
+
+  for (i = 0; i < arrsizeof (flashSectorToAddress); i++)
+    if (iapIsSafeSector (i))
+      return i;
+
+  iapErrno = IAP_RESULT_X_NOSAFEREGIONAVAIL;
+  return -1;
+}
+
+//
+//  1 == sector is safe, 0 == not safe
+//
+int iapIsValidSector (int sector)
+{
+  if ((sector < 0) || (sector >= (int) arrsizeof (flashSectorToAddress)))
+  {
+    iapErrno = IAP_RESULT_INVALID_SECTOR;
+    return 0;
+  }
+
+  return 1;
+}
+
+//
+//
+//
+int iapGetErrno (void)
+{
+  return iapErrno;
+}
+
+const char *iapStrerror (int err)
+{
+  unsigned int i;
+
+  for (i = 0; i < arrsizeof (iapErrnoStr); i++)
+    if (iapErrnoStr [i].errno == err)
+      return iapErrnoStr [i].text;
+
+  return NULL;
+}
+
+//
+//
+//
+static void iapCall (void) __attribute ((naked));
+static void iapCall (void)
+{
+  register void *pFP0 asm("r0") = iapCommands;
+  register void *pFP1 asm("r1") = iapResults;
+
+  asm volatile(" bx  %[iapLocation]"
+               :
+               : "r" (pFP0), "r" (pFP1), [iapLocation] "r" (IAP_LOCATION) );
+}
+
+//
+//
+//
+static inline unsigned __get_cpsr (void)
+{
+  unsigned long retval;
+
+  asm volatile (" mrs  %0, cpsr" : "=r" (retval) : /* no inputs */  );
+
+  return retval;
+}
+
+static inline void __set_cpsr (unsigned val)
+{
+  asm volatile (" msr  cpsr, %0" : /* no outputs */ : "r" (val)  );
+}
+
+static unsigned disableInts (void)
+{
+  unsigned _cpsr;
+
+  _cpsr = __get_cpsr ();
+
+  do
+    __set_cpsr (_cpsr | INTs_MASK);
+  while ((__get_cpsr () ^ INTs_MASK) & INTs_MASK);
+
+  return _cpsr;
+}
+
+static unsigned restoreInts (unsigned oldCPSR)
+{
+  unsigned _cpsr;
+
+  _cpsr = __get_cpsr();
+
+  do
+    __set_cpsr ((_cpsr & ~INTs_MASK) | (oldCPSR & INTs_MASK));
+  while ((__get_cpsr () ^ oldCPSR) & INTs_MASK);
+
+  return _cpsr;
+}
+
+//
+//
+//
+int iapPrepareSectors (int startingSector, int endingSector)
+{
+  unsigned int cpsr;
+
+  if (!iapIsSafeSector (startingSector) || !iapIsSafeSector (endingSector))
+    return -1;
+
+  iapCommands [0] = IAP_CMD_PREPARE;
+  iapCommands [1] = startingSector;
+  iapCommands [2] = endingSector;
+
+  cpsr = disableInts ();
+
+  iapCall ();
+
+  restoreInts (cpsr);
+
+  return ((iapErrno = iapResults [0]) == IAP_RESULT_CMD_SUCCESS) ? 0 : -1;
+}
+
+//
+//  IAP_CMD_COPYRAMTOFLASH can span multiple sectors (2, at any rate, since bufferLen
+//  must be 256, 512, 1024 or 4096, and the smallest sectors are 4096 bytes).  Although
+//  more than 2 sectors can be prepared for writing, it's useless to do so, since
+//  after each IAP_CMD_COPYRAMTOFLASH, the sectors are re-locked.
+//
+int iapWriteSectors (unsigned int address, unsigned char *buffer, int bufferLen)
+{
+  unsigned int cpsr;
+
+  iapCommands [0] = IAP_CMD_COPYRAMTOFLASH;
+  iapCommands [1] = address;
+  iapCommands [2] = (int) buffer;
+  iapCommands [3] = bufferLen;
+  iapCommands [4] = CPUCLK_IN_KHZ;
+
+  cpsr = disableInts ();
+
+  iapCall ();
+
+  restoreInts (cpsr);
+
+  if ((iapErrno = iapResults [0]) != IAP_RESULT_CMD_SUCCESS)
+    return -1;
+
+  return 0;
+}
+
+int iapFillSectors (int startingSector, int endingSector, int byte)
+{
+  int sector;
+  unsigned char buffer [256];
+
+  if (!iapIsSafeSector (startingSector) || !iapIsSafeSector (endingSector))
+    return -1;
+
+  memset (buffer, byte, sizeof (buffer));
+
+  for (sector = startingSector; sector <= endingSector; sector++)
+  {
+    int i;
+    unsigned long address;
+    int sectorSize;
+
+    if (iapSectorToAddress (sector, &address, &sectorSize))
+      return -1;
+
+    for (i = 0; i < sectorSize; i += sizeof (buffer))
+    {
+      if (iapPrepareSectors (sector, sector) == -1)
+        return -1;
+      if (iapWriteSectors (address + i, buffer, sizeof (buffer)) == -1)
+        return -1;
+      if (iapCompare (address + i, buffer, sizeof (buffer)) == -1)
+        return -1;
+    }
+  }
+
+  return 0;
+}
+
+int iapEraseSectors (int startingSector, int endingSector)
+{
+  unsigned int cpsr;
+
+  if (!iapIsSafeSector (startingSector) || !iapIsSafeSector (endingSector))
+    return -1;
+
+  if (iapPrepareSectors (startingSector, endingSector) == -1)
+    return -1;
+
+  iapCommands [0] = IAP_CMD_ERASE;
+  iapCommands [1] = startingSector;
+  iapCommands [2] = endingSector;
+  iapCommands [3] = CPUCLK_IN_KHZ;
+
+  cpsr = disableInts ();
+
+  iapCall ();
+
+  restoreInts (cpsr);
+
+  return ((iapErrno = iapResults [0]) == IAP_RESULT_CMD_SUCCESS) ? 0 : -1;
+}
+
+//
+// -1 = error (iapErrno set)
+//  0 = sector blank
+//  1 = sector not blank
+//
+int iapBlankCheckSectors (int startingSector, int endingSector)
+{
+  unsigned int cpsr;
+
+  if (!iapIsValidSector (startingSector) || !iapIsValidSector (endingSector))
+    return -1;
+
+  iapCommands [0] = IAP_CMD_BLANKCHECK;
+  iapCommands [1] = startingSector;
+  iapCommands [2] = endingSector;
+
+  cpsr = disableInts ();
+
+  iapCall ();
+
+  restoreInts (cpsr);
+
+  if ((iapErrno = iapResults [0]) == IAP_RESULT_CMD_SUCCESS)
+    return 0;
+  if (iapResults [0] == IAP_RESULT_SECTOR_NOT_BLANK)
+    return 1;
+
+  return -1;
+}
+
+//
+//
+//
+unsigned int iapReadPartID (void)
+{
+  unsigned int cpsr;
+
+  iapCommands [0] = IAP_CMD_READPARTID;
+
+  cpsr = disableInts ();
+
+  iapCall ();
+
+  restoreInts (cpsr);
+
+  return iapResults [1];
+}
+
+//
+//
+//
+unsigned int iapReadBootCodeVersion (void)
+{
+  unsigned int cpsr;
+
+  iapCommands [0] = IAP_CMD_READBOOTCODEVER;
+
+  cpsr = disableInts ();
+
+  iapCall ();
+
+  restoreInts (cpsr);
+
+  return iapResults [1];
+}
+
+//
+//
+//
+int iapCompare (unsigned int address, unsigned char *buffer, int bufferLen)
+{
+  unsigned int cpsr;
+
+  iapCommands [0] = IAP_CMD_COMPARE;
+  iapCommands [1] = address;
+  iapCommands [2] = (int) buffer;
+  iapCommands [3] = bufferLen;
+
+  cpsr = disableInts ();
+
+  iapCall ();
+
+  restoreInts (cpsr);
+
+  return ((iapErrno = iapResults [0]) == IAP_RESULT_CMD_SUCCESS) ? 0 : -1;
+}
+
+//
+//
+//
+void iapISP (void)
+{
+  int i;
+  REG32 *p;
+
+  portDISABLE_INTERRUPTS ();
+
+  VIC_IntEnClr = VIC_IntEnClr_MASK;
+
+  SCB_PLLCON = 0;
+  SCB_PLLCFG = 0;
+  SCB_PLLFEED = SCB_PLLFEED_FEED1;
+  SCB_PLLFEED = SCB_PLLFEED_FEED2;
+
+  USB_PLLCON = 0; 
+  USB_PLLCFG = 0; 
+  USB_PLLFEED = USB_PLLFEED_FEED1;
+  USB_PLLFEED = USB_PLLFEED_FEED2;
+
+  for (p = (REG32 *) T1_BASE_ADDR, i = 0; i< 0x74 / 4; i++)
+    *p++ = 0;
+
+  T1_IR = 0xff;
+
+  SCB_PCONP = 0x000003be;
+
+  UART0_IER = 0x00; 
+  UART0_LCR = 0x80; 
+  UART0_DLL = 0x01; 
+  UART0_DLM = 0x00;
+  UART0_LCR = 0x00; 
+  UART0_FCR = 0x06; 
+  UART0_FDR = 0x10;
+
+  SCB_MEMMAP = 0;
+  SCB_VPBDIV = 0;
+
+  PCB_PINSEL0 = 0x00000000;
+  PCB_PINSEL1 = 0x00000000;
+  
+  GPIO0_IODIR = 0x00004000;
+  GPIO0_IOCLR = 0x00004000;
+
+  WD_TC = 0x0ffffff; 
+  WD_MOD = 0;
+  WD_FEED = WD_FEED_FEED1;
+  WD_FEED = WD_FEED_FEED2;
+
+  iapCommands [0] = IAP_CMD_REINVOKEISP;
+
+  // disableInts ();
+  // cpuPLLDisable ();
+  // cpuT1Disable ();
+
+  iapCall ();
+}
diff --git a/iap/iap.h b/iap/iap.h
new file mode 100644 (file)
index 0000000..6b52701
--- /dev/null
+++ b/iap/iap.h
@@ -0,0 +1,32 @@
+#ifndef _IAP_H_
+#define _IAP_H_
+
+//
+//
+//
+#define IAP_RESULT_X_NOTSAFEREGION      (IAP_RESULT_LAST + 1)
+#define IAP_RESULT_X_NOSAFEREGIONAVAIL  (IAP_RESULT_LAST + 2)
+
+//
+//
+//
+void iapInit (void);
+int iapSectorToAddress (int sectorNumber, unsigned long *address, int *sectorSize);
+int iapAddressToSector (unsigned long address);
+int iapIsSafeAddress (unsigned long address);;
+int iapIsSafeSector (int sector);
+int iapFindSafeSector (void);
+int iapIsValidSector (int sector);
+int iapGetErrno (void);
+const char *iapStrerror (int err);
+int iapPrepareSectors (int startingSector, int endingSector);
+int iapFillSectors (int startingSector, int endingSector, int byte);
+int iapWriteSectors (unsigned int address, unsigned char *buffer, int bufferLen);
+int iapEraseSectors (int startingSector, int endingSector);
+int iapBlankCheckSectors (int startingSector, int endingSector);
+unsigned int iapReadPartID (void);
+unsigned int iapReadBootCodeVersion (void);
+int iapCompare (unsigned int address, unsigned char *buffer, int bufferLen);
+void iapISP (void);
+
+#endif
diff --git a/leds/Makefile b/leds/Makefile
new file mode 100644 (file)
index 0000000..984efe2
--- /dev/null
@@ -0,0 +1,25 @@
+SRC_FILES=leds.c
+
+#
+# Define all object files.
+#
+ARM_OBJ = $(SRC_FILES:.c=.o)
+
+.PHONY: all
+all: $(ARM_OBJ)
+
+$(ARM_OBJ) : %.o : %.c Makefile .depend
+       $(CC) -c $(CFLAGS) $< -o $@
+       $(AR) r $(COMMON)/common.a $@
+
+#
+#  The .depend files contains the list of header files that the
+#  various source files depend on.  By doing this, we'll only
+#  rebuild the .o's that are affected by header files changing.
+#
+.depend:
+                       $(CC) $(CFLAGS) -M $(SRC_FILES) > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff --git a/leds/leds.c b/leds/leds.c
new file mode 100644 (file)
index 0000000..15d1cd0
--- /dev/null
@@ -0,0 +1,77 @@
+//
+//
+//
+#include "FreeRTOS.h"
+#include "task.h"
+#include "queue.h"
+
+#include "../cpu/cpu.h"
+#include "leds.h"
+
+//
+//
+//
+typedef struct
+{
+  int timeOn;
+  int timeOff;
+}
+ledDutyCycles_t;
+
+static ledDutyCycles_t ledDutyCycles [] = 
+{
+  { (200 / portTICK_RATE_MS), (800 / portTICK_RATE_MS) },
+  { (400 / portTICK_RATE_MS), (600 / portTICK_RATE_MS) },
+  { (600 / portTICK_RATE_MS), (400 / portTICK_RATE_MS) },
+  { (800 / portTICK_RATE_MS), (200 / portTICK_RATE_MS) },
+};
+
+xQueueHandle xLEDQueue;
+
+//
+//
+//
+portTASK_FUNCTION (vLEDFlashTask, pvParameters __attribute__ ((unused)))
+{
+  portTickType ledTimeOn = 1;
+  portTickType ledTimeOff = 1;
+  portTickType lastTickTime;
+  int dutyCycle = 0;
+
+  //
+  //  Create the queue, turn on LED and die if we can't
+  //
+  if ((xLEDQueue = xQueueCreate (1, sizeof (dutyCycle))) == 0)
+  {
+    GPIO0_IOSET = GPIO_IO_P10;
+
+    while (1)
+      vTaskDelay (100);
+  }
+
+  //
+  //  Send ourselves a message to init the flash time
+  //
+  xQueueSend (xLEDQueue, &dutyCycle, (portTickType) 0);
+
+  //
+  //  We need to initialise lastTickTime prior to the first call to vTaskDelayUntil()
+  //
+  lastTickTime = xTaskGetTickCount ();
+
+  for (;;)
+  {
+    vTaskDelayUntil (&lastTickTime, ledTimeOn);
+    GPIO0_IOSET = GPIO_IO_P10;
+    vTaskDelayUntil (&lastTickTime, ledTimeOff);
+    GPIO0_IOCLR = GPIO_IO_P10;
+
+    if (xQueueReceive (xLEDQueue, &dutyCycle, (portTickType) 0))
+    {
+      dutyCycle %= arrsizeof (ledDutyCycles);
+
+      ledTimeOn  = ledDutyCycles [dutyCycle].timeOn;
+      ledTimeOff = ledDutyCycles [dutyCycle].timeOff;
+    }
+  }
+}
diff --git a/leds/leds.h b/leds/leds.h
new file mode 100644 (file)
index 0000000..fd37529
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef _LEDS_H_
+#define _LEDS_H_
+
+//
+//
+//
+extern xQueueHandle xLEDQueue;
+
+//
+//
+//
+portTASK_FUNCTION (vLEDFlashTask, pvParameters __attribute__ ((unused)));
+
+#endif
diff --git a/leds/leds_reuse.c b/leds/leds_reuse.c
new file mode 100644 (file)
index 0000000..07761e4
--- /dev/null
@@ -0,0 +1,58 @@
+//
+//  This code was from the original demo package.  Although it is no longer 
+//  used, it shows an excellent example of how to reuse task code with 
+//  local variables.  
+//
+//  Each time the task is create with xTaskCreate, it increment the task
+//  number, which it uses to calculate a flash rate and which LED to
+//  flash.
+//
+#include "FreeRTOS.h"
+#include "task.h"
+
+#include "../cpu/cpu.h"
+#include "leds.h"
+
+//
+//
+//
+#define ledFLASH_RATE_BASE ((portTickType) 333)
+static portBASE_TYPE uxFlashTaskNumber = 0;
+
+portTASK_FUNCTION (vLEDFlashTask, pvParameters __attribute__ ((unused)))
+{
+  portTickType xFlashRate;
+  portTickType xLastFlashTime;
+  unsigned portBASE_TYPE uxLED;
+
+  //
+  // Calculate the LED and flash rate
+  //
+  portENTER_CRITICAL ();
+  {
+    uxLED = uxFlashTaskNumber;
+    uxFlashTaskNumber++;
+  }
+  portEXIT_CRITICAL ();
+
+  xFlashRate = ledFLASH_RATE_BASE + (ledFLASH_RATE_BASE * (portTickType) uxLED);
+  xFlashRate /= portTICK_RATE_MS;
+
+  //
+  //  We will turn the LED on and off again in the delay period, so each delay is only half the total period
+  //
+  xFlashRate /= (portTickType) 2;
+
+  //
+  //  We need to initialise xLastFlashTime prior to the first call to vTaskDelayUntil()
+  //
+  xLastFlashTime = xTaskGetTickCount();
+
+  for (;;)
+  {
+    vTaskDelayUntil (&xLastFlashTime, xFlashRate);
+    cpuToggleLED (uxLED);
+    vTaskDelayUntil (&xLastFlashTime, xFlashRate);
+    cpuToggleLED (uxLED);
+  }
+}
diff --git a/lpc210x.h b/lpc210x.h
new file mode 100644 (file)
index 0000000..f740f73
--- /dev/null
+++ b/lpc210x.h
@@ -0,0 +1,2310 @@
+/*
+//  Using typedef'ed structures instead of #define's would be much cleaner.  However,
+//  it's a damn lot of work to define them all, and there were a bunch of #defines
+//  to start with, so I just expanded them.
+*/
+
+#ifndef _LPC210X_H_
+#define _LPC210X_H_
+
+#include "sysdefs.h"
+
+/*##############################################################################
+## MISC
+##############################################################################*/
+
+/* Constants for data to put in IRQ/FIQ Exception Vectors */
+#define VECTDATA_IRQ  0xe51ffff0  /* LDR PC,[PC,#-0xFF0] */
+#define VECTDATA_FIQ  /* __TODO */
+
+
+/*##############################################################################
+## VECTORED INTERRUPT CONTROLLER
+##############################################################################*/
+
+#define VIC_IRQStatus           (*(pREG32 (0xfffff000)))
+#define VIC_FIQStatus           (*(pREG32 (0xfffff004)))
+#define VIC_RawIntr             (*(pREG32 (0xfffff008)))
+#define VIC_IntSelect           (*(pREG32 (0xfffff00c)))
+#define VIC_IntEnable           (*(pREG32 (0xfffff010)))
+#define VIC_IntEnClr            (*(pREG32 (0xfffff014)))
+#define VIC_SoftInt             (*(pREG32 (0xfffff018)))
+#define VIC_SoftIntClear        (*(pREG32 (0xfffff01c)))
+#define VIC_Protection          (*(pREG32 (0xfffff020)))
+#define VIC_VectAddr            (*(pREG32 (0xfffff030)))
+#define VIC_DefVectAddr         (*(pREG32 (0xfffff034)))
+
+#define VIC_VectAddr0           (*(pREG32 (0xfffff100)))
+#define VIC_VectAddr1           (*(pREG32 (0xfffff104)))
+#define VIC_VectAddr2           (*(pREG32 (0xfffff108)))
+#define VIC_VectAddr3           (*(pREG32 (0xfffff10c)))
+#define VIC_VectAddr4           (*(pREG32 (0xfffff110)))
+#define VIC_VectAddr5           (*(pREG32 (0xfffff114)))
+#define VIC_VectAddr6           (*(pREG32 (0xfffff118)))
+#define VIC_VectAddr7           (*(pREG32 (0xfffff11c)))
+#define VIC_VectAddr8           (*(pREG32 (0xfffff120)))
+#define VIC_VectAddr9           (*(pREG32 (0xfffff124)))
+#define VIC_VectAddr10          (*(pREG32 (0xfffff128)))
+#define VIC_VectAddr11          (*(pREG32 (0xfffff12c)))
+#define VIC_VectAddr12          (*(pREG32 (0xfffff130)))
+#define VIC_VectAddr13          (*(pREG32 (0xfffff134)))
+#define VIC_VectAddr14          (*(pREG32 (0xfffff138)))
+#define VIC_VectAddr15          (*(pREG32 (0xfffff13c)))
+
+#define VIC_VectCntl0           (*(pREG32 (0xfffff200)))
+#define VIC_VectCntl1           (*(pREG32 (0xfffff204)))
+#define VIC_VectCntl2           (*(pREG32 (0xfffff208)))
+#define VIC_VectCntl3           (*(pREG32 (0xfffff20c)))
+#define VIC_VectCntl4           (*(pREG32 (0xfffff210)))
+#define VIC_VectCntl5           (*(pREG32 (0xfffff214)))
+#define VIC_VectCntl6           (*(pREG32 (0xfffff218)))
+#define VIC_VectCntl7           (*(pREG32 (0xfffff21c)))
+#define VIC_VectCntl8           (*(pREG32 (0xfffff220)))
+#define VIC_VectCntl9           (*(pREG32 (0xfffff224)))
+#define VIC_VectCntl10          (*(pREG32 (0xfffff228)))
+#define VIC_VectCntl11          (*(pREG32 (0xfffff22c)))
+#define VIC_VectCntl12          (*(pREG32 (0xfffff230)))
+#define VIC_VectCntl13          (*(pREG32 (0xfffff234)))
+#define VIC_VectCntl14          (*(pREG32 (0xfffff238)))
+#define VIC_VectCntl15          (*(pREG32 (0xfffff23c)))
+
+#define VIC_ITCR                (*(pREG32 (0xfffff300)))
+#define VIC_ITIP1               (*(pREG32 (0xfffff304)))
+#define VIC_ITIP2               (*(pREG32 (0xfffff308)))
+#define VIC_ITOP1               (*(pREG32 (0xfffff30c)))
+#define VIC_ITOP2               (*(pREG32 (0xfffff310)))
+#define VIC_PeriphID0           (*(pREG32 (0xffffffe0)))
+#define VIC_PeriphID1           (*(pREG32 (0xffffffe4)))
+#define VIC_PeriphID2           (*(pREG32 (0xffffffe8)))
+#define VIC_PeriphID3           (*(pREG32 (0xffffffec)))
+
+#define VIC_SoftInt_WDT         (0x00000001)
+#define VIC_SoftInt_ARMCore0    (0x00000004)
+#define VIC_SoftInt_ARMCore1    (0x00000008)
+#define VIC_SoftInt_Timer0      (0x00000010)
+#define VIC_SoftInt_Timer1      (0x00000020)
+#define VIC_SoftInt_UART0       (0x00000040)
+#define VIC_SoftInt_UART1       (0x00000080)
+#define VIC_SoftInt_PWM0        (0x00000100)
+#define VIC_SoftInt_I2C0        (0x00000200)
+#define VIC_SoftInt_SPI0        (0x00000400)
+#define VIC_SoftInt_SPI1        (0x00000800)
+#define VIC_SoftInt_SSP         (0x00000800)
+#define VIC_SoftInt_PLL         (0x00001000)
+#define VIC_SoftInt_RTC         (0x00002000)
+#define VIC_SoftInt_EINT0       (0x00004000)
+#define VIC_SoftInt_EINT1       (0x00008000)
+#define VIC_SoftInt_EINT2       (0x00010000)
+#define VIC_SoftInt_EINT3       (0x00020000)
+#define VIC_SoftInt_AD0         (0x00040000)
+#define VIC_SoftInt_I2C1        (0x00080000)
+#define VIC_SoftInt_BOD         (0x00100000)
+#define VIC_SoftInt_AD1         (0x00200000)
+#define VIC_SoftInt_USB         (0x00400000)
+#define VIC_SoftInt_MASK        (0x007ffffd)
+
+#define VIC_SoftIntClr_WDT      (0x00000001)
+#define VIC_SoftIntClr_ARMCore0 (0x00000004)
+#define VIC_SoftIntClr_ARMCore1 (0x00000008)
+#define VIC_SoftIntClr_Timer0   (0x00000010)
+#define VIC_SoftIntClr_Timer1   (0x00000020)
+#define VIC_SoftIntClr_UART0    (0x00000040)
+#define VIC_SoftIntClr_UART1    (0x00000080)
+#define VIC_SoftIntClr_PWM0     (0x00000100)
+#define VIC_SoftIntClr_I2C0     (0x00000200)
+#define VIC_SoftIntClr_SPI0     (0x00000400)
+#define VIC_SoftIntClr_SPI1     (0x00000800)
+#define VIC_SoftIntClr_SSP      (0x00000800)
+#define VIC_SoftIntClr_PLL      (0x00001000)
+#define VIC_SoftIntClr_RTC      (0x00002000)
+#define VIC_SoftIntClr_EINT0    (0x00004000)
+#define VIC_SoftIntClr_EINT1    (0x00008000)
+#define VIC_SoftIntClr_EINT2    (0x00010000)
+#define VIC_SoftIntClr_EINT3    (0x00020000)
+#define VIC_SoftIntClr_AD0      (0x00040000)
+#define VIC_SoftIntClr_I2C1     (0x00080000)
+#define VIC_SoftIntClr_BOD      (0x00100000)
+#define VIC_SoftIntClr_AD1      (0x00200000)
+#define VIC_SoftIntClr_USB      (0x00400000)
+#define VIC_SoftIntClr_MASK     (0x007ffffd)
+
+#define VIC_RawIntr_WDT         (0x00000001)
+#define VIC_RawIntr_ARMCore0    (0x00000004)
+#define VIC_RawIntr_ARMCore1    (0x00000008)
+#define VIC_RawIntr_Timer0      (0x00000010)
+#define VIC_RawIntr_Timer1      (0x00000020)
+#define VIC_RawIntr_UART0       (0x00000040)
+#define VIC_RawIntr_UART1       (0x00000080)
+#define VIC_RawIntr_PWM0        (0x00000100)
+#define VIC_RawIntr_I2C0        (0x00000200)
+#define VIC_RawIntr_SPI0        (0x00000400)
+#define VIC_RawIntr_SPI1        (0x00000800)
+#define VIC_RawIntr_SSP         (0x00000800)
+#define VIC_RawIntr_PLL         (0x00001000)
+#define VIC_RawIntr_RTC         (0x00002000)
+#define VIC_RawIntr_EINT0       (0x00004000)
+#define VIC_RawIntr_EINT1       (0x00008000)
+#define VIC_RawIntr_EINT2       (0x00010000)
+#define VIC_RawIntr_EINT3       (0x00020000)
+#define VIC_RawIntr_AD0         (0x00040000)
+#define VIC_RawIntr_I2C1        (0x00080000)
+#define VIC_RawIntr_BOD         (0x00100000)
+#define VIC_RawIntr_AD1         (0x00200000)
+#define VIC_RawIntr_USB         (0x00400000)
+#define VIC_RawIntr_MASK        (0x007ffffd)
+
+#define VIC_IntEnable_WDT       (0x00000001)
+#define VIC_IntEnable_ARMCore0  (0x00000004)
+#define VIC_IntEnable_ARMCore1  (0x00000008)
+#define VIC_IntEnable_Timer0    (0x00000010)
+#define VIC_IntEnable_Timer1    (0x00000020)
+#define VIC_IntEnable_UART0     (0x00000040)
+#define VIC_IntEnable_UART1     (0x00000080)
+#define VIC_IntEnable_PWM0      (0x00000100)
+#define VIC_IntEnable_I2C0      (0x00000200)
+#define VIC_IntEnable_SPI0      (0x00000400)
+#define VIC_IntEnable_SPI1      (0x00000800)
+#define VIC_IntEnable_SSP       (0x00000800)
+#define VIC_IntEnable_PLL       (0x00001000)
+#define VIC_IntEnable_RTC       (0x00002000)
+#define VIC_IntEnable_EINT0     (0x00004000)
+#define VIC_IntEnable_EINT1     (0x00008000)
+#define VIC_IntEnable_EINT2     (0x00010000)
+#define VIC_IntEnable_EINT3     (0x00020000)
+#define VIC_IntEnable_AD0       (0x00040000)
+#define VIC_IntEnable_I2C1      (0x00080000)
+#define VIC_IntEnable_BOD       (0x00100000)
+#define VIC_IntEnable_AD1       (0x00200000)
+#define VIC_IntEnable_USB       (0x00400000)
+#define VIC_IntEnable_MASK      (0x007ffffd)
+
+#define VIC_IntEnClr_WDT        (0x00000001)
+#define VIC_IntEnClr_ARMCore0   (0x00000004)
+#define VIC_IntEnClr_ARMCore1   (0x00000008)
+#define VIC_IntEnClr_Timer0     (0x00000010)
+#define VIC_IntEnClr_Timer1     (0x00000020)
+#define VIC_IntEnClr_UART0      (0x00000040)
+#define VIC_IntEnClr_UART1      (0x00000080)
+#define VIC_IntEnClr_PWM0       (0x00000100)
+#define VIC_IntEnClr_I2C0       (0x00000200)
+#define VIC_IntEnClr_SPI0       (0x00000400)
+#define VIC_IntEnClr_SPI1       (0x00000800)
+#define VIC_IntEnClr_SSP        (0x00000800)
+#define VIC_IntEnClr_PLL        (0x00001000)
+#define VIC_IntEnClr_RTC        (0x00002000)
+#define VIC_IntEnClr_EINT0      (0x00004000)
+#define VIC_IntEnClr_EINT1      (0x00008000)
+#define VIC_IntEnClr_EINT2      (0x00010000)
+#define VIC_IntEnClr_EINT3      (0x00020000)
+#define VIC_IntEnClr_AD0        (0x00040000)
+#define VIC_IntEnClr_I2C1       (0x00080000)
+#define VIC_IntEnClr_BOD        (0x00100000)
+#define VIC_IntEnClr_AD1        (0x00200000)
+#define VIC_IntEnClr_USB        (0x00400000)
+#define VIC_IntEnClr_MASK       (0x007ffffd)
+
+#define VIC_IntSelect_WDT       (0x00000001)
+#define VIC_IntSelect_ARMCore0  (0x00000004)
+#define VIC_IntSelect_ARMCore1  (0x00000008)
+#define VIC_IntSelect_Timer0    (0x00000010)
+#define VIC_IntSelect_Timer1    (0x00000020)
+#define VIC_IntSelect_UART0     (0x00000040)
+#define VIC_IntSelect_UART1     (0x00000080)
+#define VIC_IntSelect_PWM0      (0x00000100)
+#define VIC_IntSelect_I2C0      (0x00000200)
+#define VIC_IntSelect_SPI0      (0x00000400)
+#define VIC_IntSelect_SPI1      (0x00000800)
+#define VIC_IntSelect_SSP       (0x00000800)
+#define VIC_IntSelect_PLL       (0x00001000)
+#define VIC_IntSelect_RTC       (0x00002000)
+#define VIC_IntSelect_EINT0     (0x00004000)
+#define VIC_IntSelect_EINT1     (0x00008000)
+#define VIC_IntSelect_EINT2     (0x00010000)
+#define VIC_IntSelect_EINT3     (0x00020000)
+#define VIC_IntSelect_AD0       (0x00040000)
+#define VIC_IntSelect_I2C1      (0x00080000)
+#define VIC_IntSelect_BOD       (0x00100000)
+#define VIC_IntSelect_AD1       (0x00200000)
+#define VIC_IntSelect_USB       (0x00400000)
+#define VIC_IntSelect_MASK      (0x007ffffd)
+
+#define VIC_IRQStatus_WDT       (0x00000001)
+#define VIC_IRQStatus_ARMCore0  (0x00000004)
+#define VIC_IRQStatus_ARMCore1  (0x00000008)
+#define VIC_IRQStatus_Timer0    (0x00000010)
+#define VIC_IRQStatus_Timer1    (0x00000020)
+#define VIC_IRQStatus_UART0     (0x00000040)
+#define VIC_IRQStatus_UART1     (0x00000080)
+#define VIC_IRQStatus_PWM0      (0x00000100)
+#define VIC_IRQStatus_I2C0      (0x00000200)
+#define VIC_IRQStatus_SPI0      (0x00000400)
+#define VIC_IRQStatus_SPI1      (0x00000800)
+#define VIC_IRQStatus_SSP       (0x00000800)
+#define VIC_IRQStatus_PLL       (0x00001000)
+#define VIC_IRQStatus_RTC       (0x00002000)
+#define VIC_IRQStatus_EINT0     (0x00004000)
+#define VIC_IRQStatus_EINT1     (0x00008000)
+#define VIC_IRQStatus_EINT2     (0x00010000)
+#define VIC_IRQStatus_EINT3     (0x00020000)
+#define VIC_IRQStatus_AD0       (0x00040000)
+#define VIC_IRQStatus_I2C1      (0x00080000)
+#define VIC_IRQStatus_BOD       (0x00100000)
+#define VIC_IRQStatus_AD1       (0x00200000)
+#define VIC_IRQStatus_USB       (0x00400000)
+#define VIC_IRQStatus_MASK      (0x007ffffd)
+
+#define VIC_FIQStatus_WDT       (0x00000001)
+#define VIC_FIQStatus_ARMCore0  (0x00000004)
+#define VIC_FIQStatus_ARMCore1  (0x00000008)
+#define VIC_FIQStatus_Timer0    (0x00000010)
+#define VIC_FIQStatus_Timer1    (0x00000020)
+#define VIC_FIQStatus_UART0     (0x00000040)
+#define VIC_FIQStatus_UART1     (0x00000080)
+#define VIC_FIQStatus_PWM0      (0x00000100)
+#define VIC_FIQStatus_I2C0      (0x00000200)
+#define VIC_FIQStatus_SPI0      (0x00000400)
+#define VIC_FIQStatus_SPI1      (0x00000800)
+#define VIC_FIQStatus_SSP       (0x00000800)
+#define VIC_FIQStatus_PLL       (0x00001000)
+#define VIC_FIQStatus_RTC       (0x00002000)
+#define VIC_FIQStatus_EINT0     (0x00004000)
+#define VIC_FIQStatus_EINT1     (0x00008000)
+#define VIC_FIQStatus_EINT2     (0x00010000)
+#define VIC_FIQStatus_EINT3     (0x00020000)
+#define VIC_FIQStatus_AD0       (0x00040000)
+#define VIC_FIQStatus_I2C1      (0x00080000)
+#define VIC_FIQStatus_BOD       (0x00100000)
+#define VIC_FIQStatus_AD1       (0x00200000)
+#define VIC_FIQStatus_USB       (0x00400000)
+#define VIC_FIQStatus_MASK      (0x007ffffd)
+
+#define VIC_VectCntl_SLOTMASK   (0x0000001f)
+#define VIC_VectCntl_ENABLE     (0x00000020)
+
+#define VIC_Protection_ACCESS   (0x00000001)
+#define VIC_Protection_MASK     (0x00000001)
+
+#define VIC_Mask_WDT            (0x00000001)
+#define VIC_Mask_RSVD           (0x00000002)
+#define VIC_Mask_ARMCore0       (0x00000004)
+#define VIC_Mask_ARMCore1       (0x00000008)
+#define VIC_Mask_Timer0         (0x00000010)
+#define VIC_Mask_Timer1         (0x00000020)
+#define VIC_Mask_UART0          (0x00000040)
+#define VIC_Mask_UART1          (0x00000080)
+#define VIC_Mask_PWM0           (0x00000100)
+#define VIC_Mask_I2C0           (0x00000200)
+#define VIC_Mask_SPI0           (0x00000400)
+#define VIC_Mask_SPI1           (0x00000800)
+#define VIC_Mask_SSP            (0x00000800)
+#define VIC_Mask_PLL            (0x00001000)
+#define VIC_Mask_RTC            (0x00002000)
+#define VIC_Mask_EINT0          (0x00004000)
+#define VIC_Mask_EINT1          (0x00008000)
+#define VIC_Mask_EINT2          (0x00010000)
+#define VIC_Mask_EINT3          (0x00020000)
+#define VIC_Mask_AD0            (0x00040000)
+#define VIC_Mask_I2C1           (0x00080000)
+#define VIC_Mask_BOD            (0x00100000)
+#define VIC_Mask_AD1            (0x00200000)
+#define VIC_Mask_USB            (0x00400000)
+#define VIC_Mask_MASK           (0x007ffffd)
+
+#define VIC_Channel_WDT         (0)
+#define VIC_Channel_RSVD        (1)
+#define VIC_Channel_ARMCore0    (2)
+#define VIC_Channel_ARMCore1    (3)
+#define VIC_Channel_Timer0      (4)
+#define VIC_Channel_Timer1      (5)
+#define VIC_Channel_UART0       (6)
+#define VIC_Channel_UART1       (7)
+#define VIC_Channel_PWM0        (8)
+#define VIC_Channel_I2C0        (9)
+#define VIC_Channel_SPI0        (10)
+#define VIC_Channel_SPI1        (11)
+#define VIC_Channel_SSP         (11)
+#define VIC_Channel_PLL         (12)
+#define VIC_Channel_RTC         (13)
+#define VIC_Channel_EINT0       (14)
+#define VIC_Channel_EINT1       (15)
+#define VIC_Channel_EINT2       (16)
+#define VIC_Channel_EINT3       (17)
+#define VIC_Channel_AD0         (18)
+#define VIC_Channel_I2C1        (19)
+#define VIC_Channel_BOD         (20)
+#define VIC_Channel_AD1         (21)
+#define VIC_Channel_USB         (22)
+
+
+/*##############################################################################
+## PCB - Pin Connect Block
+##############################################################################*/
+
+#define PCB_PINSEL0               (*(pREG32 (0xe002c000)))
+#define PCB_PINSEL1               (*(pREG32 (0xe002c004)))
+
+#define PCB_PINSEL0_P00_GPIO      ((unsigned int) 0x00000000)
+#define PCB_PINSEL0_P00_TXD0      ((unsigned int) 0x00000001)
+#define PCB_PINSEL0_P00_PWM1      ((unsigned int) 0x00000002)
+#define PCB_PINSEL0_P00_RSVD3     ((unsigned int) 0x00000003)
+#define PCB_PINSEL0_P00_MASK      ((unsigned int) 0x00000003)
+
+#define PCB_PINSEL0_P01_GPIO      ((unsigned int) 0x00000000)
+#define PCB_PINSEL0_P01_RXD0      ((unsigned int) 0x00000004)
+#define PCB_PINSEL0_P01_PWM3      ((unsigned int) 0x00000008)
+#define PCB_PINSEL0_P01_EINT0     ((unsigned int) 0x0000000c)
+#define PCB_PINSEL0_P01_MASK      ((unsigned int) 0x0000000c)
+
+#define PCB_PINSEL0_P02_GPIO      ((unsigned int) 0x00000000)
+#define PCB_PINSEL0_P02_SCL0      ((unsigned int) 0x00000010)
+#define PCB_PINSEL0_P02_CAP00     ((unsigned int) 0x00000020)
+#define PCB_PINSEL0_P02_RSVD3     ((unsigned int) 0x00000030)
+#define PCB_PINSEL0_P02_MASK      ((unsigned int) 0x00000030)
+
+#define PCB_PINSEL0_P03_GPIO      ((unsigned int) 0x00000000)
+#define PCB_PINSEL0_P03_SDA0      ((unsigned int) 0x00000040)
+#define PCB_PINSEL0_P03_MAT00     ((unsigned int) 0x00000080)
+#define PCB_PINSEL0_P03_EINT1     ((unsigned int) 0x000000c0)
+#define PCB_PINSEL0_P03_MASK      ((unsigned int) 0x000000c0)
+
+#define PCB_PINSEL0_P04_GPIO      ((unsigned int) 0x00000000)
+#define PCB_PINSEL0_P04_SCK0      ((unsigned int) 0x00000100)
+#define PCB_PINSEL0_P04_CAP01     ((unsigned int) 0x00000200)
+#define PCB_PINSEL0_P04_RSVD3     ((unsigned int) 0x00000300)
+#define PCB_PINSEL0_P04_MASK      ((unsigned int) 0x00000300)
+
+#define PCB_PINSEL0_P05_GPIO      ((unsigned int) 0x00000000)
+#define PCB_PINSEL0_P05_MISO0     ((unsigned int) 0x00000400)
+#define PCB_PINSEL0_P05_MAT01     ((unsigned int) 0x00000800)
+#define PCB_PINSEL0_P05_AD06      ((unsigned int) 0x00000c00)
+#define PCB_PINSEL0_P05_MASK      ((unsigned int) 0x00000c00)
+
+#define PCB_PINSEL0_P06_GPIO      ((unsigned int) 0x00000000)
+#define PCB_PINSEL0_P06_MOSI0     ((unsigned int) 0x00001000)
+#define PCB_PINSEL0_P06_CAP02     ((unsigned int) 0x00002000)
+#define PCB_PINSEL0_P06_AD10      ((unsigned int) 0x00003000)
+#define PCB_PINSEL0_P06_MASK      ((unsigned int) 0x00003000)
+
+#define PCB_PINSEL0_P07_GPIO      ((unsigned int) 0x00000000)
+#define PCB_PINSEL0_P07_SSEL0     ((unsigned int) 0x00004000)
+#define PCB_PINSEL0_P07_PWM2      ((unsigned int) 0x00008000)
+#define PCB_PINSEL0_P07_EINT2     ((unsigned int) 0x0000c000)
+#define PCB_PINSEL0_P07_MASK      ((unsigned int) 0x0000c000)
+
+#define PCB_PINSEL0_P08_GPIO      ((unsigned int) 0x00000000)
+#define PCB_PINSEL0_P08_TXD1      ((unsigned int) 0x00010000)
+#define PCB_PINSEL0_P08_PWM4      ((unsigned int) 0x00020000)
+#define PCB_PINSEL0_P08_AD11      ((unsigned int) 0x00030000)
+#define PCB_PINSEL0_P08_MASK      ((unsigned int) 0x00030000)
+
+#define PCB_PINSEL0_P09_GPIO      ((unsigned int) 0x00000000)
+#define PCB_PINSEL0_P09_RXD1      ((unsigned int) 0x00040000)
+#define PCB_PINSEL0_P09_PWM6      ((unsigned int) 0x00080000)
+#define PCB_PINSEL0_P09_EINT3     ((unsigned int) 0x000c0000)
+#define PCB_PINSEL0_P09_MASK      ((unsigned int) 0x000c0000)
+
+#define PCB_PINSEL0_P010_GPIO     ((unsigned int) 0x00000000)
+#define PCB_PINSEL0_P010_RTS1     ((unsigned int) 0x00100000)
+#define PCB_PINSEL0_P010_CAP10    ((unsigned int) 0x00200000)
+#define PCB_PINSEL0_P010_AD12     ((unsigned int) 0x00300000)
+#define PCB_PINSEL0_P010_MASK     ((unsigned int) 0x00300000)
+
+#define PCB_PINSEL0_P011_GPIO     ((unsigned int) 0x00000000)
+#define PCB_PINSEL0_P011_CTS1     ((unsigned int) 0x00400000)
+#define PCB_PINSEL0_P011_CAP11    ((unsigned int) 0x00800000)
+#define PCB_PINSEL0_P011_SCL1     ((unsigned int) 0x00c00000)
+#define PCB_PINSEL0_P011_MASK     ((unsigned int) 0x00c00000)
+
+#define PCB_PINSEL0_P012_GPIO     ((unsigned int) 0x00000000)
+#define PCB_PINSEL0_P012_DSR1     ((unsigned int) 0x01000000)
+#define PCB_PINSEL0_P012_MAT10    ((unsigned int) 0x02000000)
+#define PCB_PINSEL0_P012_AD13     ((unsigned int) 0x03000000)
+#define PCB_PINSEL0_P012_MASK     ((unsigned int) 0x03000000)
+
+#define PCB_PINSEL0_P013_GPIO     ((unsigned int) 0x00000000)
+#define PCB_PINSEL0_P013_DTR1     ((unsigned int) 0x04000000)
+#define PCB_PINSEL0_P013_MAT11    ((unsigned int) 0x08000000)
+#define PCB_PINSEL0_P013_AD14     ((unsigned int) 0x0c000000)
+#define PCB_PINSEL0_P013_MASK     ((unsigned int) 0x0c000000)
+
+#define PCB_PINSEL0_P014_GPIO     ((unsigned int) 0x00000000)
+#define PCB_PINSEL0_P014_DCD1     ((unsigned int) 0x10000000)
+#define PCB_PINSEL0_P014_EINT1    ((unsigned int) 0x20000000)
+#define PCB_PINSEL0_P014_SDA1     ((unsigned int) 0x30000000)
+#define PCB_PINSEL0_P014_MASK     ((unsigned int) 0x30000000)
+
+#define PCB_PINSEL0_P015_GPIO     ((unsigned int) 0x00000000)
+#define PCB_PINSEL0_P015_RI1      ((unsigned int) 0x40000000)
+#define PCB_PINSEL0_P015_EINT2    ((unsigned int) 0x80000000)
+#define PCB_PINSEL0_P015_AD15     ((unsigned int) 0xc0000000)
+#define PCB_PINSEL0_P015_MASK     ((unsigned int) 0xc0000000)
+
+#define PCB_PINSEL1_P016_GPIO     ((unsigned int) 0x00000000)
+#define PCB_PINSEL1_P016_EINT0    ((unsigned int) 0x00000001)
+#define PCB_PINSEL1_P016_MAT02    ((unsigned int) 0x00000002)
+#define PCB_PINSEL1_P016_CAP02    ((unsigned int) 0x00000003)
+#define PCB_PINSEL1_P016_MASK     ((unsigned int) 0x00000003)
+
+#define PCB_PINSEL1_P017_GPIO     ((unsigned int) 0x00000000)
+#define PCB_PINSEL1_P017_CAP12    ((unsigned int) 0x00000004)
+#define PCB_PINSEL1_P017_SCK1     ((unsigned int) 0x00000008)
+#define PCB_PINSEL1_P017_MAT12    ((unsigned int) 0x0000000c)
+#define PCB_PINSEL1_P017_MASK     ((unsigned int) 0x0000000c)
+
+#define PCB_PINSEL1_P018_GPIO     ((unsigned int) 0x00000000)
+#define PCB_PINSEL1_P018_CAP13    ((unsigned int) 0x00000010)
+#define PCB_PINSEL1_P018_MISO1    ((unsigned int) 0x00000020)
+#define PCB_PINSEL1_P018_MAT13    ((unsigned int) 0x00000030)
+#define PCB_PINSEL1_P018_MASK     ((unsigned int) 0x00000030)
+
+#define PCB_PINSEL1_P019_GPIO     ((unsigned int) 0x00000000)
+#define PCB_PINSEL1_P019_MAT12    ((unsigned int) 0x00000040)
+#define PCB_PINSEL1_P019_MOSI1    ((unsigned int) 0x00000080)
+#define PCB_PINSEL1_P019_CAP12    ((unsigned int) 0x000000c0)
+
+#define PCB_PINSEL1_P020_GPIO     ((unsigned int) 0x00000000)
+#define PCB_PINSEL1_P020_MAT13    ((unsigned int) 0x00000100)
+#define PCB_PINSEL1_P020_SSEL1    ((unsigned int) 0x00000200)
+#define PCB_PINSEL1_P020_EINT3    ((unsigned int) 0x00000300)
+#define PCB_PINSEL1_P020_MASK     ((unsigned int) 0x00000300)
+
+#define PCB_PINSEL1_P021_GPIO     ((unsigned int) 0x00000000)
+#define PCB_PINSEL1_P021_PWM5     ((unsigned int) 0x00000400)
+#define PCB_PINSEL1_P021_AD16     ((unsigned int) 0x00000800)
+#define PCB_PINSEL1_P021_CAP13    ((unsigned int) 0x00000c00)
+#define PCB_PINSEL1_P021_MASK     ((unsigned int) 0x00000c00)
+
+#define PCB_PINSEL1_P022_GPIO     ((unsigned int) 0x00000000)
+#define PCB_PINSEL1_P022_AD17     ((unsigned int) 0x00001000)
+#define PCB_PINSEL1_P022_CAP00    ((unsigned int) 0x00002000)
+#define PCB_PINSEL1_P022_MAT00    ((unsigned int) 0x00003000)
+#define PCB_PINSEL1_P022_MASK     ((unsigned int) 0x00003000)
+
+#define PCB_PINSEL1_P023_GPIO     ((unsigned int) 0x00000000)
+#define PCB_PINSEL1_P023_VBUS     ((unsigned int) 0x00004000)
+#define PCB_PINSEL1_P023_RSVD2    ((unsigned int) 0x00008000)
+#define PCB_PINSEL1_P023_RSVD3    ((unsigned int) 0x0000c000)
+#define PCB_PINSEL1_P023_MASK     ((unsigned int) 0x0000c000)
+
+#define PCB_PINSEL1_P024_RSVD0    ((unsigned int) 0x00000000)
+#define PCB_PINSEL1_P024_RSVD1    ((unsigned int) 0x00010000)
+#define PCB_PINSEL1_P024_RSVD2    ((unsigned int) 0x00020000)
+#define PCB_PINSEL1_P024_RSVD3    ((unsigned int) 0x00030000)
+#define PCB_PINSEL1_P024_MASK     ((unsigned int) 0x00030000)
+
+#define PCB_PINSEL1_P025_GPIO     ((unsigned int) 0x00000000)
+#define PCB_PINSEL1_P025_AD04     ((unsigned int) 0x00040000)
+#define PCB_PINSEL1_P025_AOUT     ((unsigned int) 0x00080000)
+#define PCB_PINSEL1_P025_RSVD3    ((unsigned int) 0x000c0000)
+#define PCB_PINSEL1_P025_MASK     ((unsigned int) 0x000c0000)
+
+#define PCB_PINSEL1_P026_RSVD0    ((unsigned int) 0x00000000)
+#define PCB_PINSEL1_P026_RSVD1    ((unsigned int) 0x00100000)
+#define PCB_PINSEL1_P026_RSVD2    ((unsigned int) 0x00200000)
+#define PCB_PINSEL1_P026_RSVD3    ((unsigned int) 0x00300000)
+#define PCB_PINSEL1_P026_MASK     ((unsigned int) 0x00300000)
+
+#define PCB_PINSEL1_P027_RSVD0    ((unsigned int) 0x00000000)
+#define PCB_PINSEL1_P027_RSVD1    ((unsigned int) 0x00400000)
+#define PCB_PINSEL1_P027_RSVD2    ((unsigned int) 0x00800000)
+#define PCB_PINSEL1_P027_RSVD3    ((unsigned int) 0x00c00000)
+#define PCB_PINSEL1_P027_MASK     ((unsigned int) 0x00c00000)
+
+#define PCB_PINSEL1_P028_GPIO     ((unsigned int) 0x00000000)
+#define PCB_PINSEL1_P028_AD01     ((unsigned int) 0x01000000)
+#define PCB_PINSEL1_P028_CAP02    ((unsigned int) 0x02000000)
+#define PCB_PINSEL1_P028_MAT02    ((unsigned int) 0x03000000)
+#define PCB_PINSEL1_P028_MASK     ((unsigned int) 0x03000000)
+
+#define PCB_PINSEL1_P029_GPIO     ((unsigned int) 0x00000000)
+#define PCB_PINSEL1_P029_AD02     ((unsigned int) 0x04000000)
+#define PCB_PINSEL1_P029_CAP03    ((unsigned int) 0x08000000)
+#define PCB_PINSEL1_P029_MAT03    ((unsigned int) 0x0c000000)
+#define PCB_PINSEL1_P029_MASK     ((unsigned int) 0x0c000000)
+
+#define PCB_PINSEL1_P030_GPIO     ((unsigned int) 0x00000000)
+#define PCB_PINSEL1_P030_AD03     ((unsigned int) 0x10000000)
+#define PCB_PINSEL1_P030_EINT3    ((unsigned int) 0x20000000)
+#define PCB_PINSEL1_P030_CAP00    ((unsigned int) 0x30000000)
+#define PCB_PINSEL1_P030_MASK     ((unsigned int) 0x30000000)
+
+#define PCB_PINSEL1_P031_GPIO     ((unsigned int) 0x00000000)
+#define PCB_PINSEL1_P031_UPLED    ((unsigned int) 0x40000000)
+#define PCB_PINSEL1_P031_CONNECT  ((unsigned int) 0x80000000)
+#define PCB_PINSEL1_P031_RSVD3    ((unsigned int) 0xc0000000)
+#define PCB_PINSEL1_P031_MASK     ((unsigned int) 0xc0000000)
+
+
+/*##############################################################################
+## GPIO - General Purpose I/O
+##############################################################################*/
+
+#define GPIO0_IOPIN     (*(pREG32 (0xe0028000)))
+#define GPIO0_IOSET     (*(pREG32 (0xe0028004)))
+#define GPIO0_IODIR     (*(pREG32 (0xe0028008)))
+#define GPIO0_IOCLR     (*(pREG32 (0xe002800c)))
+#define GPIO1_IOPIN     (*(pREG32 (0xe0028010)))
+#define GPIO1_IOSET     (*(pREG32 (0xe0028014)))
+#define GPIO1_IODIR     (*(pREG32 (0xe0028018)))
+#define GPIO1_IOCLR     (*(pREG32 (0xe002801c)))
+
+#define GPIO_IO_P0      ((unsigned int) 0x00000001)
+#define GPIO_IO_P1      ((unsigned int) 0x00000002)
+#define GPIO_IO_P2      ((unsigned int) 0x00000004)
+#define GPIO_IO_P3      ((unsigned int) 0x00000008)
+#define GPIO_IO_P4      ((unsigned int) 0x00000010)
+#define GPIO_IO_P5      ((unsigned int) 0x00000020)
+#define GPIO_IO_P6      ((unsigned int) 0x00000040)
+#define GPIO_IO_P7      ((unsigned int) 0x00000080)
+#define GPIO_IO_P8      ((unsigned int) 0x00000100)
+#define GPIO_IO_P9      ((unsigned int) 0x00000200)
+#define GPIO_IO_P10     ((unsigned int) 0x00000400)
+#define GPIO_IO_P11     ((unsigned int) 0x00000800)
+#define GPIO_IO_P12     ((unsigned int) 0x00001000)
+#define GPIO_IO_P13     ((unsigned int) 0x00002000)
+#define GPIO_IO_P14     ((unsigned int) 0x00004000)
+#define GPIO_IO_P15     ((unsigned int) 0x00008000)
+#define GPIO_IO_P16     ((unsigned int) 0x00010000)
+#define GPIO_IO_P17     ((unsigned int) 0x00020000)
+#define GPIO_IO_P18     ((unsigned int) 0x00040000)
+#define GPIO_IO_P19     ((unsigned int) 0x00080000)
+#define GPIO_IO_P20     ((unsigned int) 0x00100000)
+#define GPIO_IO_P21     ((unsigned int) 0x00200000)
+#define GPIO_IO_P22     ((unsigned int) 0x00400000)
+#define GPIO_IO_P23     ((unsigned int) 0x00800000)
+#define GPIO_IO_P24     ((unsigned int) 0x01000000)
+#define GPIO_IO_P25     ((unsigned int) 0x02000000)
+#define GPIO_IO_P26     ((unsigned int) 0x04000000)
+#define GPIO_IO_P27     ((unsigned int) 0x08000000)
+#define GPIO_IO_P28     ((unsigned int) 0x10000000)
+#define GPIO_IO_P29     ((unsigned int) 0x20000000)
+#define GPIO_IO_P30     ((unsigned int) 0x40000000)
+#define GPIO_IO_P31     ((unsigned int) 0x80000000)
+#define GPIO_IO_JTAG    ((unsigned int) 0x003e0000)
+
+
+/*##############################################################################
+## UART0 / UART1
+##############################################################################*/
+
+#define UART0_RBR       (*(pREG32 (0xe000c000)))
+#define UART0_THR       (*(pREG32 (0xe000c000)))
+#define UART0_IER       (*(pREG32 (0xe000c004)))
+#define UART0_IIR       (*(pREG32 (0xe000c008)))
+#define UART0_FCR       (*(pREG32 (0xe000c008)))
+#define UART0_LCR       (*(pREG32 (0xe000c00c)))
+#define UART0_LSR       (*(pREG32 (0xe000c014)))
+#define UART0_SCR       (*(pREG32 (0xe000c01c)))
+#define UART0_ACR       (*(pREG32 (0xe0000020)))
+#define UART0_FDR       (*(pREG32 (0xe0000028)))
+#define UART0_TER       (*(pREG32 (0xe0000030)))
+#define UART0_DLL       (*(pREG32 (0xe000c000)))
+#define UART0_DLM       (*(pREG32 (0xe000c004)))
+
+#define UART1_RBR       (*(pREG32 (0xe0010000)))
+#define UART1_THR       (*(pREG32 (0xe0010000)))
+#define UART1_IER       (*(pREG32 (0xe0010004)))
+#define UART1_IIR       (*(pREG32 (0xe0010008)))
+#define UART1_FCR       (*(pREG32 (0xe0010008)))
+#define UART1_LCR       (*(pREG32 (0xe001000c)))
+#define UART1_LSR       (*(pREG32 (0xe0010014)))
+#define UART1_SCR       (*(pREG32 (0xe001001c)))
+#define UART1_ACR       (*(pREG32 (0xe0010020)))
+#define UART1_FDR       (*(pREG32 (0xe0010028)))
+#define UART1_TER       (*(pREG32 (0xe0010030)))
+#define UART1_DLL       (*(pREG32 (0xe0010000)))
+#define UART1_DLM       (*(pREG32 (0xe0010004)))
+#define UART1_MCR       (*(pREG32 (0xe0010010)))
+#define UART1_MSR       (*(pREG32 (0xe0010018)))
+
+#define UART_LCR_DLAB   (0x00000080)
+#define UART_LCR_NOPAR  (0x00000000)
+#define UART_LCR_1STOP  (0x00000000)
+#define UART_LCR_8BITS  (0x00000003)
+#define UART_IER_EI     (0x00000003)
+#define UART_FCR_EN     (0x00000001)
+#define UART_FCR_CLR    (0x00000006)
+
+
+/*##############################################################################
+## I2C
+##############################################################################*/
+
+#define I2C0_CONSET         (*(pREG32 (0xe001c000)))
+#define I2C0_STAT           (*(pREG32 (0xe001c004)))
+#define I2C0_DAT            (*(pREG32 (0xe001c008)))
+#define I2C0_ADR            (*(pREG32 (0xe001c00c)))
+#define I2C0_SCLH           (*(pREG32 (0xe001c010)))
+#define I2C0_SCLL           (*(pREG32 (0xe001c014)))
+#define I2C0_CONCLR         (*(pREG32 (0xe001c018)))
+
+#define I2C1_CONSET         (*(pREG32 (0xe005c000)))
+#define I2C1_STAT           (*(pREG32 (0xe005c004)))
+#define I2C1_DAT            (*(pREG32 (0xe005c008)))
+#define I2C1_ADR            (*(pREG32 (0xe005c00c)))
+#define I2C1_SCLH           (*(pREG32 (0xe005c010)))
+#define I2C1_SCLL           (*(pREG32 (0xe005c014)))
+#define I2C1_CONCLR         (*(pREG32 (0xe005c018)))
+
+#define I2C_CONSET_AA       (0x00000004)
+#define I2C_CONSET_SI       (0x00000008)
+#define I2C_CONSET_STO      (0x00000010)
+#define I2C_CONSET_STA      (0x00000020)
+#define I2C_CONSET_I2EN     (0x00000040)
+#define I2C_CONSET_MASK     (0x0000007c)
+
+#define I2C_STAT_STATMASK   (0x000000f8)
+#define I2C_STAT_STATSHIFT  (3)
+
+#define I2C_ADDR_GC         (0x00000001)
+#define I2C_ADDR_ADDRMASK   (0x000000fe)
+#define I2C_ADDR_ADDRSHIFT  (1)
+
+#define I2C_CONCLR_AAC      (0x00000004)
+#define I2C_CONCLR_SIC      (0x00000008)
+#define I2C_CONCLR_STAC     (0x00000020)
+#define I2C_CONCLR_I2ENC    (0x00000040)
+#define I2C_CONCLR_MASK     (0x0000006c)
+
+
+/*##############################################################################
+## SPI - Serial Peripheral Interface
+##############################################################################*/
+
+#define SPI_SPCR        (*(pREG32 (0xe0020000)))
+#define SPI_SPSR        (*(pREG32 (0xe0020004)))
+#define SPI_SPDR        (*(pREG32 (0xe0020008)))
+#define SPI_SPCCR       (*(pREG32 (0xe002000c)))
+#define SPI_SPTCR       (*(pREG32 (0xe0020010)))
+#define SPI_SPTSR       (*(pREG32 (0xe0020014)))
+#define SPI_SPTOR       (*(pREG32 (0xe0020018)))
+#define SPI_SPINT       (*(pREG32 (0xe002001c)))
+
+
+/*##############################################################################
+## SSP - Synchronous Serial Port
+##############################################################################*/
+
+#define SSP_CR0         (*(pREG32 (0xe0068000)))
+#define SSP_CR1         (*(pREG32 (0xe0068004)))
+#define SSP_DR          (*(pREG32 (0xe0068008)))
+#define SSP_SR          (*(pREG32 (0xe006800C)))
+#define SSP_CPSR        (*(pREG32 (0xe0068010)))
+#define SSP_IMSC        (*(pREG32 (0xe0068014)))
+#define SSP_RIS         (*(pREG32 (0xe0068018)))
+#define SSP_MIS         (*(pREG32 (0xe006801C)))
+#define SSP_ICR         (*(pREG32 (0xe0068020)))
+
+#define SSP_FIFO_DEPTH  (8)
+
+#define SSP_CR0_DSS_4   ((unsigned int) 0x00000003)
+#define SSP_CR0_DSS_5   ((unsigned int) 0x00000004)
+#define SSP_CR0_DSS_6   ((unsigned int) 0x00000005)
+#define SSP_CR0_DSS_7   ((unsigned int) 0x00000006)
+#define SSP_CR0_DSS_8   ((unsigned int) 0x00000007)
+#define SSP_CR0_DSS_9   ((unsigned int) 0x00000008)
+#define SSP_CR0_DSS 10  ((unsigned int) 0x00000009)
+#define SSP_CR0_DSS_11  ((unsigned int) 0x0000000a)
+#define SSP_CR0_DSS_12  ((unsigned int) 0x0000000b)
+#define SSP_CR0_DSS_13  ((unsigned int) 0x0000000c)
+#define SSP_CR0_DSS_14  ((unsigned int) 0x0000000d)
+#define SSP_CR0_DSS_15  ((unsigned int) 0x0000000e)
+#define SSP_CR0_DSS_16  ((unsigned int) 0x0000000f)
+#define SSP_CR0_FRF_SPI ((unsigned int) 0x00000000)
+#define SSP_CR0_FRF_SSI ((unsigned int) 0x00000010)
+#define SSP_CR0_FRF_MW  ((unsigned int) 0x00000020)
+#define SSP_CR0_CPOL    ((unsigned int) 0x00000040)
+#define SSP_CR0_CPHA    ((unsigned int) 0x00000080)
+#define SSP_CR0_SCR     ((unsigned int) 0x0000ff00)
+
+#define SSP_CR1_LBM     ((unsigned int) 0x00000001)
+#define SSP_CR1_SSE     ((unsigned int) 0x00000002)
+#define SSP_CR1_MS      ((unsigned int) 0x00000004)
+#define SSP_CR1_SOD     ((unsigned int) 0x00000008)
+
+#define SSP_SR_TFE      ((unsigned int) 0x00000001)
+#define SSP_SR_TNF      ((unsigned int) 0x00000002)
+#define SSP_SR_RNE      ((unsigned int) 0x00000004)
+#define SSP_SR_RFF      ((unsigned int) 0x00000008)
+#define SSP_SR_BSY      ((unsigned int) 0x00000010)
+
+#define SSP_IMSC_RORIM  ((unsigned int) 0x00000001)
+#define SSP_IMSC_RTIM   ((unsigned int) 0x00000002)
+#define SSP_IMSC_RXIM   ((unsigned int) 0x00000004)
+#define SSP_IMSC_TXIM   ((unsigned int) 0x00000008)
+
+#define SSP_RIS_RORRIS  ((unsigned int) 0x00000001)
+#define SSP_RIS_RTRIS   ((unsigned int) 0x00000002)
+#define SSP_RIS_RXRIS   ((unsigned int) 0x00000004)
+#define SSP_RIS_TXRIS   ((unsigned int) 0x00000008)
+
+#define SSP_MIS_RORMIS  ((unsigned int) 0x00000001)
+#define SSP_MIS_RTMIS   ((unsigned int) 0x00000002)
+#define SSP_MIS_RXMIS   ((unsigned int) 0x00000004)
+#define SSP_MIS_TXMIS   ((unsigned int) 0x00000008)
+
+#define SSP_ICR_RORIC   ((unsigned int) 0x00000001)
+#define SSP_ICR_RTIC    ((unsigned int) 0x00000002)
+
+
+/*##############################################################################
+## Timer 0 and Timer 1
+##############################################################################*/
+
+#define T0_BASE_ADDR        (pREG32 (0xe0004000))
+#define T0_IR               (*(pREG32 (0xe0004000)))
+#define T0_TCR              (*(pREG32 (0xe0004004)))
+#define T0_TC               (*(pREG32 (0xe0004008)))
+#define T0_PR               (*(pREG32 (0xe000400c)))
+#define T0_PC               (*(pREG32 (0xe0004010)))
+#define T0_MCR              (*(pREG32 (0xe0004014)))
+#define T0_MR0              (*(pREG32 (0xe0004018)))
+#define T0_MR1              (*(pREG32 (0xe000401c)))
+#define T0_MR2              (*(pREG32 (0xe0004020)))
+#define T0_MR3              (*(pREG32 (0xe0004024)))
+#define T0_CCR              (*(pREG32 (0xe0004028)))
+#define T0_CR0              (*(pREG32 (0xe000402c)))
+#define T0_CR1              (*(pREG32 (0xe0004030)))
+#define T0_CR2              (*(pREG32 (0xe0004034)))
+#define T0_CR3              (*(pREG32 (0xe0004038)))
+#define T0_EMR              (*(pREG32 (0xe000403c)))
+#define T0_CTCR             (*(pREG32 (0xe0004070)))
+
+#define T1_BASE_ADDR        (pREG32 (0xe0008000))
+#define T1_IR               (*(pREG32 (0xe0008000)))
+#define T1_TCR              (*(pREG32 (0xe0008004)))
+#define T1_TC               (*(pREG32 (0xe0008008)))
+#define T1_PR               (*(pREG32 (0xe000800c)))
+#define T1_PC               (*(pREG32 (0xe0008010)))
+#define T1_MCR              (*(pREG32 (0xe0008014)))
+#define T1_MR0              (*(pREG32 (0xe0008018)))
+#define T1_MR1              (*(pREG32 (0xe000801c)))
+#define T1_MR2              (*(pREG32 (0xe0008020)))
+#define T1_MR3              (*(pREG32 (0xe0008024)))
+#define T1_CCR              (*(pREG32 (0xe0008028)))
+#define T1_CR0              (*(pREG32 (0xe000802c)))
+#define T1_CR1              (*(pREG32 (0xe0008030)))
+#define T1_CR2              (*(pREG32 (0xe0008034)))
+#define T1_CR3              (*(pREG32 (0xe0008038)))
+#define T1_EMR              (*(pREG32 (0xe000803c)))
+#define T1_CTCR             (*(pREG32 (0xe0008070)))
+
+#define T_IR_MR0            (0x00000001)
+#define T_IR_MR1            (0x00000002)
+#define T_IR_MR2            (0x00000004)
+#define T_IR_MR3            (0x00000008)
+#define T_IR_CR0            (0x00000010)
+#define T_IR_CR1            (0x00000020)
+#define T_IR_CR2            (0x00000040)
+#define T_IR_CR3            (0x00000080)
+#define T_IR_MASK           (0x000000ff)
+
+#define T_TCR_CE            (0x00000001)
+#define T_TCR_CR            (0x00000002)
+
+#define T_CTCR_MODE_PCLK    (0x00000000)
+#define T_CTCR_MODE_CAPRISE (0x00000001)
+#define T_CTCR_MODE_CAPFALL (0x00000002)
+#define T_CTCR_MODE_CAPBOTH (0x00000003)
+#define T_CTCR_MODE_MASK    (0x00000003)
+#define T_CTCR_CIS_CAPN0    (0x00000000)
+#define T_CTCR_CIS_CAPN1    (0x00000004)
+#define T_CTCR_CIS_CAPN2    (0x00000008)
+#define T_CTCR_CIS_CAPN3    (0x0000000c)
+#define T_CTCR_CIS_MASK     (0x0000000c)
+
+#define T_MCR_MR0I          (0x00000001)
+#define T_MCR_MR0R          (0x00000002)
+#define T_MCR_MR0S          (0x00000004)
+#define T_MCR_MR1I          (0x00000008)
+#define T_MCR_MR1R          (0x00000010)
+#define T_MCR_MR1S          (0x00000020)
+#define T_MCR_MR2I          (0x00000040)
+#define T_MCR_MR2R          (0x00000080)
+#define T_MCR_MR2S          (0x00000100)
+#define T_MCR_MR3I          (0x00000200)
+#define T_MCR_MR3R          (0x00000400)
+#define T_MCR_MR3S          (0x00000800)
+
+#define T_CCR_CAP0RE        (0x00000001)
+#define T_CCR_CAP0FE        (0x00000002)
+#define T_CCR_CAP0I         (0x00000004)
+#define T_CCR_CAP1RE        (0x00000008)
+#define T_CCR_CAP1FE        (0x00000010)
+#define T_CCR_CAP1I         (0x00000020)
+#define T_CCR_CAP2RE        (0x00000040)
+#define T_CCR_CAP2FE        (0x00000080)
+#define T_CCR_CAP2I         (0x00000100)
+#define T_CCR_CAP3RE        (0x00000200)
+#define T_CCR_CAP3FE        (0x00000400)
+#define T_CCR_CAP3I         (0x00000800)
+
+#define T_EMR_EM0           (0x00000001)
+#define T_EMR_EM1           (0x00000002)
+#define T_EMR_EM2           (0x00000004)
+#define T_EMR_EM3           (0x00000008)
+#define T_EMR_EMC0_NONE     (0x00000000)
+#define T_EMR_EMC0_CLEAR    (0x00000010)
+#define T_EMR_EMC0_SET      (0x00000020)
+#define T_EMR_EMC0_TOGGLE   (0x00000030)
+#define T_EMR_EMC0_MASK     (0x00000030)
+#define T_EMR_EMC1_NONE     (0x00000000)
+#define T_EMR_EMC1_CLEAR    (0x00000040)
+#define T_EMR_EMC1_SET      (0x00000080)
+#define T_EMR_EMC1_TOGGLE   (0x000000c0)
+#define T_EMR_EMC1_MASK     (0x000000c0)
+#define T_EMR_EMC2_NONE     (0x00000000)
+#define T_EMR_EMC2_CLEAR    (0x00000100)
+#define T_EMR_EMC2_SET      (0x00000200)
+#define T_EMR_EMC2_TOGGLE   (0x00000300)
+#define T_EMR_EMC2_MASK     (0x00000300)
+#define T_EMR_EMC3_NONE     (0x00000000)
+#define T_EMR_EMC3_CLEAR    (0x00000400)
+#define T_EMR_EMC3_SET      (0x00000800)
+#define T_EMR_EMC3_TOGGLE   (0x00000c00)
+#define T_EMR_EMC3_MASK     (0x00000c00)
+
+
+/*##############################################################################
+## ADC
+##############################################################################*/
+
+#define AD0_CR              (*(pREG32 (0xe0034000)))
+#define AD0_GDR             (*(pREG32 (0xe0034004)))
+#define AD0_STAT            (*(pREG32 (0xe0034030)))
+#define AD0_GSR             (*(pREG32 (0xe0034008)))
+#define AD0_INTEN           (*(pREG32 (0xe003400c)))
+#define AD0_DR0             (*(pREG32 (0xe0034010)))
+#define AD0_DR1             (*(pREG32 (0xe0034014)))
+#define AD0_DR2             (*(pREG32 (0xe0034018)))
+#define AD0_DR3             (*(pREG32 (0xe003401c)))
+#define AD0_DR4             (*(pREG32 (0xe0034020)))
+#define AD0_DR5             (*(pREG32 (0xe0034024)))
+#define AD0_DR6             (*(pREG32 (0xe0034028)))
+#define AD0_DR7             (*(pREG32 (0xe003402c)))
+
+#define AD1_CR              (*(pREG32 (0xe0064000)))
+#define AD1_GDR             (*(pREG32 (0xe0064004)))
+#define AD1_STAT            (*(pREG32 (0xe0064030)))
+#define AD1_GSR             (*(pREG32 (0xe0034008)))
+#define AD1_INTEN           (*(pREG32 (0xe006400c)))
+#define AD1_DR0             (*(pREG32 (0xe0064010)))
+#define AD1_DR1             (*(pREG32 (0xe0064014)))
+#define AD1_DR2             (*(pREG32 (0xe0064018)))
+#define AD1_DR3             (*(pREG32 (0xe006401c)))
+#define AD1_DR4             (*(pREG32 (0xe0064020)))
+#define AD1_DR5             (*(pREG32 (0xe0064024)))
+#define AD1_DR6             (*(pREG32 (0xe0064028)))
+#define AD1_DR7             (*(pREG32 (0xe006402c)))
+
+#define AD_CR_SEL0          (0x00000001)
+#define AD_CR_SEL1          (0x00000002)
+#define AD_CR_SEL2          (0x00000004)
+#define AD_CR_SEL3          (0x00000008)
+#define AD_CR_SEL4          (0x00000010)
+#define AD_CR_SEL5          (0x00000020)
+#define AD_CR_SEL6          (0x00000040)
+#define AD_CR_SEL7          (0x00000080)
+#define AD_CR_CLKDIV        (0x0000ff00)
+#define AD_CR_CLKDIVMASK    (0x0000ff00)
+#define AD_CR_CLKDIVSHIFT   (8)
+#define AD_CR_BURST         (0x00010000)
+#define AD_CR_CLKS10        (0x00000000)
+#define AD_CR_CLKS9         (0x00020000)
+#define AD_CR_CLKS8         (0x00040000)
+#define AD_CR_CLKS7         (0x00060000)
+#define AD_CR_CLKS6         (0x00080000)
+#define AD_CR_CLKS5         (0x000a0000)
+#define AD_CR_CLKS4         (0x000c0000)
+#define AD_CR_CLKS3         (0x000e0000)
+#define AD_CR_PDN           (0x00200000)
+#define AD_CR_START_NONE    (0x00000000)
+#define AD_CR_START_NOW     (0x01000000)
+#define AD_CR_START_P016    (0x02000000)
+#define AD_CR_START_P022    (0x03000000)
+#define AD_CR_START_MAT01   (0x04000000)
+#define AD_CR_START_MAT03   (0x05000000)
+#define AD_CR_START_MAT10   (0x06000000)
+#define AD_CR_START_MAT11   (0x07000000)
+#define AD_CR_EDGE          (0x08000000)
+#define AD_CR_MASK          (0x0f2fffff)
+
+#define AD_GDR_RESULT       (0x0000ffc0)
+#define AD_GDR_CHN          (0x07000000)
+#define AD_GDR_CHNMASK      (0x07000000)
+#define AD_GDR_CHNSHIFT     (24)
+#define AD_GDR_OVERRUN      (0x40000000)
+#define AD_GDR_DONE         (0x80000000)
+#define AD_GDR_MASK         (0xc700ffc0)
+
+#define AD_GSR_BURST        (0x00010000)
+#define AD_GSR_START_NONE   (0x00000000)
+#define AD_GSR_START_NOW    (0x01000000)
+#define AD_GSR_START_P016   (0x02000000)
+#define AD_GSR_START_P022   (0x03000000)
+#define AD_GSR_START_MAT01  (0x04000000)
+#define AD_GSR_START_MAT03  (0x05000000)
+#define AD_GSR_START_MAT10  (0x06000000)
+#define AD_GSR_START_MAT11  (0x07000000)
+#define AD_GSR_EDGE         (0x08000000)
+#define AD_GSR_MASK         (0x0f010000)
+
+#define AD_STAT_RSVD        (0x00000001)
+#define AD_STAT_DONE0       (0x00000001)
+#define AD_STAT_DONE1       (0x00000002)
+#define AD_STAT_DONE2       (0x00000004)
+#define AD_STAT_DONE3       (0x00000008)
+#define AD_STAT_DONE4       (0x00000010)
+#define AD_STAT_DONE5       (0x00000020)
+#define AD_STAT_DONE6       (0x00000040)
+#define AD_STAT_DONE7       (0x00000080)
+#define AD_STAT_OVERRUN0    (0x00000100)
+#define AD_STAT_OVERRUN1    (0x00000200)
+#define AD_STAT_OVERRUN2    (0x00000400)
+#define AD_STAT_OVERRUN3    (0x00000800)
+#define AD_STAT_OVERRUN4    (0x00001000)
+#define AD_STAT_OVERRUN5    (0x00002000)
+#define AD_STAT_OVERRUN6    (0x00004000)
+#define AD_STAT_OVERRUN7    (0x00008000)
+#define AD_STAT_ADINT       (0x00010000)
+#define AD_STAT_MASK        (0x0001ffff)
+
+#define AD_INTEN_AD0        (0x00000001)
+#define AD_INTEN_AD1        (0x00000002)
+#define AD_INTEN_AD2        (0x00000004)
+#define AD_INTEN_AD3        (0x00000008)
+#define AD_INTEN_AD4        (0x00000010)
+#define AD_INTEN_AD5        (0x00000020)
+#define AD_INTEN_AD6        (0x00000040)
+#define AD_INTEN_AD7        (0x00000080)
+#define AD_INTEN_DONE       (0x00000100)
+#define AD_INTEN_MASK       (0x000001ff)
+
+#define AD_DR_RESULT        (0x0000ffc0)
+#define AD_DR_RESULTMASK    (0x0000ffc0)
+#define AD_DR_RESULTSHIFT   (6)
+#define AD_DR_OVERRUN       (0x40000000)
+#define AD_DR_DONE          (0x80000000)
+#define AD_DR_MASK          (0xc000ffc0)
+
+
+/*##############################################################################
+## DAC
+##############################################################################*/
+
+#define DAC_CR            (*(pREG32 (0xe006c000)))
+
+#define DAC_CR_VALUE      (0x0000ffc0)
+#define DAC_CR_VALUEMASK  (0x0000ffc0)
+#define DAC_CR_VALUESHIFT (6)
+#define DAC_CR_BIAS       (0x00010000)
+#define DAC_CR_MASK       (0x0001ffc0)
+
+
+/*##############################################################################
+## PWM
+##############################################################################*/
+
+#define PWM_IR          (*(pREG32 (0xe0014000)))
+#define PWM_TCR         (*(pREG32 (0xe0014004)))
+#define PWM_TC          (*(pREG32 (0xe0014008)))
+#define PWM_PR          (*(pREG32 (0xe001400c)))
+#define PWM_PC          (*(pREG32 (0xe0014010)))
+#define PWM_MCR         (*(pREG32 (0xe0014014)))
+#define PWM_MR0         (*(pREG32 (0xe0014018)))
+#define PWM_MR1         (*(pREG32 (0xe001401c)))
+#define PWM_MR2         (*(pREG32 (0xe0014020)))
+#define PWM_MR3         (*(pREG32 (0xe0014024)))
+#define PWM_MR4         (*(pREG32 (0xe0014040)))
+#define PWM_MR5         (*(pREG32 (0xe0014044)))
+#define PWM_MR6         (*(pREG32 (0xe0014048)))
+#define PWM_EMR         (*(pREG32 (0xe001403c)))
+#define PWM_PCR         (*(pREG32 (0xe001404c)))
+#define PWM_LER         (*(pREG32 (0xe0014050)))
+#define PWM_CCR         (*(pREG32 (0xe0014028)))
+#define PWM_CR0         (*(pREG32 (0xe001402c)))
+#define PWM_CR1         (*(pREG32 (0xe0014030)))
+#define PWM_CR2         (*(pREG32 (0xe0014034)))
+#define PWM_CR3         (*(pREG32 (0xe0014038)))
+
+
+/*##############################################################################
+## RTC
+##############################################################################*/
+
+#define RTC_ILR         (*(pREG32 (0xe0024000)))
+#define RTC_CTC         (*(pREG32 (0xe0024004)))
+#define RTC_CCR         (*(pREG32 (0xe0024008)))  
+#define RTC_CIIR        (*(pREG32 (0xe002400c)))
+#define RTC_AMR         (*(pREG32 (0xe0024010)))
+#define RTC_CTIME0      (*(pREG32 (0xe0024014)))
+#define RTC_CTIME1      (*(pREG32 (0xe0024018)))
+#define RTC_CTIME2      (*(pREG32 (0xe002401c)))
+
+#define RTC_SEC         (*(pREG32 (0xe0024020)))
+#define RTC_MIN         (*(pREG32 (0xe0024024)))
+#define RTC_HOUR        (*(pREG32 (0xe0024028)))
+#define RTC_DOM         (*(pREG32 (0xe002402c)))
+#define RTC_DOW         (*(pREG32 (0xe0024030)))
+#define RTC_DOY         (*(pREG32 (0xe0024034)))
+#define RTC_MONTH       (*(pREG32 (0xe0024038)))
+#define RTC_YEAR        (*(pREG32 (0xe002403c)))
+
+#define RTC_ALSEC       (*(pREG32 (0xe0024060)))
+#define RTC_ALMIN       (*(pREG32 (0xe0024064)))
+#define RTC_ALHOUR      (*(pREG32 (0xe0024068)))
+#define RTC_ALDOM       (*(pREG32 (0xe002406c)))
+#define RTC_ALDOW       (*(pREG32 (0xe0024070)))
+#define RTC_ALDOY       (*(pREG32 (0xe0024074)))
+#define RTC_ALMON       (*(pREG32 (0xe0024078)))
+#define RTC_ALYEAR      (*(pREG32 (0xe002407c)))
+
+#define RTC_PREINT      (*(pREG32 (0xe0024080)))
+#define RTC_PREFRAC     (*(pREG32 (0xe0024084)))
+
+#define RTC_ILR_RTCCIF  (0x00000001)
+#define RTC_ILR_RTCALF  (0x00000002)
+#define RTC_ILR_MASK    (0x00000003)
+
+#define RTC_CCR_CLKEN   (0x00000001)
+#define RTC_CCR_CTCRST  (0x00000002)
+#define RTC_CCR_TEST    (0x0000000c)
+#define RTC_CCR_CLKSRC  (0x00000010)
+
+#define RTC_CIIR_IMSEC  (0x00000001)
+#define RTC_CIIR_IMMIN  (0x00000002)
+#define RTC_CIIR_IMHOUR (0x00000004)
+#define RTC_CIIR_IMDOM  (0x00000008)
+#define RTC_CIIR_IMDOW  (0x00000010)
+#define RTC_CIIR_IMDOY  (0x00000020)
+#define RTC_CIIR_IMMON  (0x00000040)
+#define RTC_CIIR_IMYEAR (0x00000080)
+#define RTC_CIIR_IMMASK (0x000000ff)
+
+#define RTC_AMR_AMRSEC  (0x00000001)
+#define RTC_AMR_AMRMIN  (0x00000002)
+#define RTC_AMR_AMRHOUR (0x00000004)
+#define RTC_AMR_AMRDOM  (0x00000008)
+#define RTC_AMR_AMRDOW  (0x00000010)
+#define RTC_AMR_AMRDOY  (0x00000020)
+#define RTC_AMR_AMRMON  (0x00000040)
+#define RTC_AMR_AMRYEAR (0x00000080)
+#define RTC_AMR_AMRMASK (0x000000ff)
+
+typedef struct __attribute__ ((packed)) 
+{
+  union
+  {
+    struct
+    {
+      unsigned int counter   : 14;
+      unsigned int rsvd15_31 : 18;
+    };
+
+    unsigned int i;
+  };
+}
+rtcCTC_t;
+
+typedef struct __attribute__ ((packed)) 
+{
+  union
+  {
+    struct 
+    {
+      unsigned int seconds   : 6;
+      unsigned int rsvd7_6   : 2;
+      unsigned int minutes   : 6;
+      unsigned int rsvd14_15 : 2;
+      unsigned int hours     : 5;
+      unsigned int rsvd21_23 : 3;
+      unsigned int dow       : 3;
+      unsigned int rsvd27_31 : 5;
+    };
+
+    unsigned int i;
+  };
+}
+rtcCTIME0_t;
+
+typedef struct __attribute__ ((packed)) 
+{
+  union
+  {
+    struct
+    {
+      unsigned int dom       : 5;
+      unsigned int rsvd5_7   : 3;
+      unsigned int month     : 4;
+      unsigned int rsvd12_15 : 4;
+      unsigned int year      : 12;
+      unsigned int rsvd28_31 : 4;
+    };
+
+    unsigned int i;
+  };
+}
+rtcCTIME1_t;
+
+typedef struct __attribute__ ((packed)) 
+{
+  union
+  {
+    struct 
+    {
+      unsigned int doy       : 12;
+      unsigned int rsvd12_31 : 20;
+    };
+
+    unsigned int i;
+  };
+}
+rtcCTIME2_t;
+
+
+/*##############################################################################
+## WD - Watchdog
+##############################################################################*/
+
+#define WD_MOD        (*(pREG32 (0xe0000000)))
+#define WD_TC         (*(pREG32 (0xe0000004)))
+#define WD_FEED       (*(pREG32 (0xe0000008)))
+#define WD_TV         (*(pREG32 (0xe000000c)))
+
+#define WD_MOD_WDEN   (0x00000001)
+#define WD_MOD_RESET  (0x00000002)
+#define WD_MOD_TOF    (0x00000004)
+#define WD_MOD_INT    (0x00000008)
+#define WD_MOD_MASK   (0x0000000f)
+
+#define WD_FEED_FEED1 (0x000000aa)
+#define WD_FEED_FEED2 (0x00000055)
+
+
+/*##############################################################################
+## System Control Block
+##############################################################################*/
+
+#define SCB_MEMMAP          (*(pREG32 (0xe01fc040)))
+#define SCB_PLLCON          (*(pREG32 (0xe01fc080)))
+#define SCB_PLLCFG          (*(pREG32 (0xe01fc084)))
+#define SCB_PLLSTAT         (*(pREG32 (0xe01fc088)))
+#define SCB_PLLFEED         (*(pREG32 (0xe01fc08c)))
+#define SCB_PCON            (*(pREG32 (0xe01fc0c0)))
+#define SCB_PCONP           (*(pREG32 (0xe01fc0c4)))
+#define SCB_VPBDIV          (*(pREG32 (0xe01fc100)))
+#define SCB_EXTINT          (*(pREG32 (0xe01fc140)))
+#define SCB_INTWAKE         (*(pREG32 (0xe01fc144)))
+#define SCB_EXTMODE         (*(pREG32 (0xe01fc148)))
+#define SCB_EXTPOLAR        (*(pREG32 (0xe01fc14c)))
+#define SCB_RSIR            (*(pREG32 (0xe01fc180)))
+#define SCB_CSPR            (*(pREG32 (0xe01fc184)))
+#define SCB_SCS             (*(pREG32 (0xe01fc1a0)))
+
+#define SCB_MEMMAP_BLM      (0x00000000)
+#define SCB_MEMMAP_UFL      (0x00000001)
+#define SCB_MEMMAP_URM      (0x00000002)
+#define SCB_MEMMAP_RSVD     (0x00000003)
+#define SCB_MEMMAP_MASK     (0x00000003)
+
+#define SCB_PLLCON_PLLE     (0x00000001)
+#define SCB_PLLCON_PLLC     (0x00000002)
+#define SCB_PLLCON_MASK     (0x00000003)
+
+#define SCB_PLLCFG_MSEL     (0x0000001f)
+#define SCB_PLLCFG_PSEL     (0x00000060)
+#define SCB_PLLCFG_MUL1     (0x00000000)
+#define SCB_PLLCFG_MUL2     (0x00000001)
+#define SCB_PLLCFG_MUL3     (0x00000002)
+#define SCB_PLLCFG_MUL4     (0x00000003)
+#define SCB_PLLCFG_MUL5     (0x00000004)
+#define SCB_PLLCFG_MUL6     (0x00000005)
+#define SCB_PLLCFG_MUL7     (0x00000006)
+#define SCB_PLLCFG_MUL8     (0x00000007)
+#define SCB_PLLCFG_MUL9     (0x00000008)
+#define SCB_PLLCFG_MUL10    (0x00000009)
+#define SCB_PLLCFG_MUL11    (0x0000000a)
+#define SCB_PLLCFG_MUL12    (0x0000000b)
+#define SCB_PLLCFG_MUL13    (0x0000000c)
+#define SCB_PLLCFG_MUL14    (0x0000000d)
+#define SCB_PLLCFG_MUL15    (0x0000000e)
+#define SCB_PLLCFG_MUL16    (0x0000000f)
+#define SCB_PLLCFG_MUL17    (0x00000010)
+#define SCB_PLLCFG_MUL18    (0x00000011)
+#define SCB_PLLCFG_MUL19    (0x00000012)
+#define SCB_PLLCFG_MUL20    (0x00000013)
+#define SCB_PLLCFG_MUL21    (0x00000014)
+#define SCB_PLLCFG_MUL22    (0x00000015)
+#define SCB_PLLCFG_MUL23    (0x00000016)
+#define SCB_PLLCFG_MUL24    (0x00000017)
+#define SCB_PLLCFG_MUL25    (0x00000018)
+#define SCB_PLLCFG_MUL26    (0x00000019)
+#define SCB_PLLCFG_MUL27    (0x0000001a)
+#define SCB_PLLCFG_MUL28    (0x0000001b)
+#define SCB_PLLCFG_MUL29    (0x0000001c)
+#define SCB_PLLCFG_MUL30    (0x0000001d)
+#define SCB_PLLCFG_MUL31    (0x0000001e)
+#define SCB_PLLCFG_MUL32    (0x0000001f)
+#define SCB_PLLCFG_DIV1     (0x00000000)
+#define SCB_PLLCFG_DIV2     (0x00000020)
+#define SCB_PLLCFG_DIV4     (0x00000040)
+#define SCB_PLLCFG_DIV8     (0x00000060)
+#define SCB_PLLCFG_MASK     (0x0000007f)
+
+#define SCB_PLLSTAT_MSEL    (0x0000001f)
+#define SCB_PLLSTAT_PSEL    (0x00000060)
+#define SCB_PLLSTAT_PLLE    (0x00000100)
+#define SCB_PLLSTAT_PLLC    (0x00000200)
+#define SCB_PLLSTAT_PLOCK   (0x00000400)
+
+#define SCB_PLLFEED_FEED1   (0x000000aa)
+#define SCB_PLLFEED_FEED2   (0x00000055)
+
+#define SCB_PCON_IDL        (0x00000001)
+#define SCB_PCON_PD         (0x00000002)
+#define SCB_PCON_PDBOD      (0x00000004)
+#define SCB_PCON_BODPDM     (0x00000008)
+#define SCB_PCON_BOGD       (0x00000010)
+#define SCB_PCON_BORD       (0x00000020)
+#define SCB_PCON_MASK       (0x0000003f)
+
+#define SCB_PCONP_PCTIM0    (0x00000002)
+#define SCB_PCONP_PCTIM1    (0x00000004)
+#define SCB_PCONP_PCUART0   (0x00000008)
+#define SCB_PCONP_PCUART1   (0x00000010)
+#define SCB_PCONP_PCPWM0    (0x00000020)
+#define SCB_PCONP_PCI2C0    (0x00000080)
+#define SCB_PCONP_PCSPI0    (0x00000100)
+#define SCB_PCONP_PCRTC     (0x00000200)
+#define SCB_PCONP_PCSPI1    (0x00000400)
+#define SCB_PCONP_PCAD0     (0x00001000)
+#define SCB_PCONP_PCI2C1    (0x00080000)
+#define SCB_PCONP_PCAD1     (0x00100000)
+#define SCB_PCONP_PUSB      (0x80000000)
+#define SCB_PCONP_MASK      (0x801817be)
+
+#define SCB_VPBDIV_25       (0x00000000)
+#define SCB_VPBDIV_100      (0x00000001)
+#define SCB_VPBDIV_50       (0x00000002)
+#define SCB_VPBDIV_RSVD     (0x00000003)
+#define SCB_VPBDIV_MASK     (0x00000003)
+
+#define SCB_EXTINT_EINT0    (0x00000001)
+#define SCB_EXTINT_EINT1    (0x00000002)
+#define SCB_EXTINT_EINT2    (0x00000004)
+#define SCB_EXTINT_EINT3    (0x00000008)
+#define SCB_EXTINT_MASK     (0x0000000f)
+
+#define SCB_INTWAKE_EINT0   (0x00000001)
+#define SCB_INTWAKE_EINT1   (0x00000002)
+#define SCB_INTWAKE_EINT2   (0x00000004)
+#define SCB_INTWAKE_EINT3   (0x00000008)
+#define SCB_INTWAKE_USB     (0x00000020)
+#define SCB_INTWAKE_BOD     (0x00004000)
+#define SCB_INTWAKE_RTC     (0x00008000)
+#define SCB_INTWAKE_MASK    (0x0000c02f)
+
+#define SCB_EXTMODE_EINT0   (0x00000001)
+#define SCB_EXTMODE_EINT1   (0x00000002)
+#define SCB_EXTMODE_EINT2   (0x00000004)
+#define SCB_EXTMODE_EINT3   (0x00000008)
+#define SCB_EXTMODE_MASK    (0x0000000f)
+
+#define SCB_EXTPOLAR_EINT0  (0x00000001)
+#define SCB_EXTPOLAR_EINT1  (0x00000002)
+#define SCB_EXTPOLAR_EINT2  (0x00000004)
+#define SCB_EXTPOLAR_EINT3  (0x00000008)
+#define SCB_EXTPOLAR_MASK   (0x0000000f)
+
+#define SCB_RSIR_POR        (0x00000001)
+#define SCB_RSIR_EXTR       (0x00000002)
+#define SCB_RSIR_WDTR       (0x00000004)
+#define SCB_RSIR_BODR       (0x00000008)
+#define SCB_RSIR_MASK       (0x0000000f)
+
+#define SCB_SCS_GPIO0M      (0x00000001)
+#define SCB_SCS_GPIO1M      (0x00000002)
+#define SCB_SCS_MASK        (0x00000003)
+
+
+/*##############################################################################
+## System Control Block (USB)
+##############################################################################*/
+
+#define USB_PLLCON                (*(pREG32 (0xe01fc0a0)))
+#define USB_PLLCFG                (*(pREG32 (0xe01fc0a4)))
+#define USB_PLLSTAT               (*(pREG32 (0xe01fc0a8)))
+#define USB_PLLFEED               (*(pREG32 (0xe01fc0ac)))
+
+#define USB_IntSt                 (*(pREG32 (0xe01fc1c0)))
+
+#define USB_DevIntSt              (*(pREG32 (0xe0090000)))
+#define USB_DevIntEn              (*(pREG32 (0xe0090004)))
+#define USB_DevIntClr             (*(pREG32 (0xe0090008)))
+#define USB_DevIntSet             (*(pREG32 (0xe009000c)))
+#define USB_DevIntPri             (*(pREG32 (0xe009002c)))
+
+#define USB_EpIntSt               (*(pREG32 (0xe0090030)))
+#define USB_EpIntEn               (*(pREG32 (0xe0090034)))
+#define USB_EpIntClr              (*(pREG32 (0xe0090038)))
+#define USB_EpIntSet              (*(pREG32 (0xe009003c)))
+#define USB_EpIntPri              (*(pREG32 (0xe0090040)))
+
+#define USB_ReEP                  (*(pREG32 (0xe0090044)))
+#define USB_EpInd                 (*(pREG32 (0xe0090048)))
+#define USB_MaxPSize              (*(pREG32 (0xe009004c)))
+
+#define USB_RxData                (*(pREG32 (0xe0090018)))
+#define USB_RxPLen                (*(pREG32 (0xe0090020)))
+#define USB_TxData                (*(pREG32 (0xe009001c)))
+#define USB_TxPLen                (*(pREG32 (0xe0090024)))
+#define USB_Ctrl                  (*(pREG32 (0xe0090028)))
+
+#define USB_CmdCode               (*(pREG32 (0xe0090010)))
+#define USB_CmdData               (*(pREG32 (0xe0090014)))
+
+#define USB_DMARSt                (*(pREG32 (0xe0090050)))
+#define USB_DMARClr               (*(pREG32 (0xe0090054)))
+#define USB_DMARSet               (*(pREG32 (0xe0090058)))
+#define USB_UDCAH                 (*(pREG32 (0xe0090080)))
+#define USB_EpDMASt               (*(pREG32 (0xe0090084)))
+#define USB_EpDMAEn               (*(pREG32 (0xe0090088)))
+#define USB_EpDMADis              (*(pREG32 (0xe009008c)))
+#define USB_DMAIntSt              (*(pREG32 (0xe0090090)))
+#define USB_DMAIntEn              (*(pREG32 (0xe0090094)))
+#define USB_EoTIntSt              (*(pREG32 (0xe00900a0)))
+#define USB_EoTIntClr             (*(pREG32 (0xe00900a4)))
+#define USB_EoTIntSet             (*(pREG32 (0xe00900a8)))
+#define USB_NDDRIntSt             (*(pREG32 (0xe00900ac)))
+#define USB_NDDRIntClr            (*(pREG32 (0xe00900b0)))
+#define USB_NDDRIntSet            (*(pREG32 (0xe00900b4)))
+#define USB_SysErrIntSt           (*(pREG32 (0xe00900b8)))
+#define USB_SysErrIntClr          (*(pREG32 (0xe00900bc)))
+#define USB_SysErrIntSet          (*(pREG32 (0xe00900c0)))
+
+#define USB_PLLCON_PLLE           (0x00000001)
+#define USB_PLLCON_PLLC           (0x00000002)
+#define USB_PLLCON_MASK           (0x00000003)
+
+#define USB_PLLCFG_MSEL           (0x0000001f)
+#define USB_PLLCFG_PSEL           (0x00000060)
+#define USB_PLLCFG_MUL1           (0x00000000)
+#define USB_PLLCFG_MUL2           (0x00000001)
+#define USB_PLLCFG_MUL3           (0x00000002)
+#define USB_PLLCFG_MUL4           (0x00000003)
+#define USB_PLLCFG_MUL5           (0x00000004)
+#define USB_PLLCFG_MUL6           (0x00000005)
+#define USB_PLLCFG_MUL7           (0x00000006)
+#define USB_PLLCFG_MUL8           (0x00000007)
+#define USB_PLLCFG_MUL9           (0x00000008)
+#define USB_PLLCFG_MUL10          (0x00000009)
+#define USB_PLLCFG_MUL11          (0x0000000a)
+#define USB_PLLCFG_MUL12          (0x0000000b)
+#define USB_PLLCFG_MUL13          (0x0000000c)
+#define USB_PLLCFG_MUL14          (0x0000000d)
+#define USB_PLLCFG_MUL15          (0x0000000e)
+#define USB_PLLCFG_MUL16          (0x0000000f)
+#define USB_PLLCFG_MUL17          (0x00000010)
+#define USB_PLLCFG_MUL18          (0x00000011)
+#define USB_PLLCFG_MUL19          (0x00000012)
+#define USB_PLLCFG_MUL20          (0x00000013)
+#define USB_PLLCFG_MUL21          (0x00000014)
+#define USB_PLLCFG_MUL22          (0x00000015)
+#define USB_PLLCFG_MUL23          (0x00000016)
+#define USB_PLLCFG_MUL24          (0x00000017)
+#define USB_PLLCFG_MUL25          (0x00000018)
+#define USB_PLLCFG_MUL26          (0x00000019)
+#define USB_PLLCFG_MUL27          (0x0000001a)
+#define USB_PLLCFG_MUL28          (0x0000001b)
+#define USB_PLLCFG_MUL29          (0x0000001c)
+#define USB_PLLCFG_MUL30          (0x0000001d)
+#define USB_PLLCFG_MUL31          (0x0000001e)
+#define USB_PLLCFG_MUL32          (0x0000001f)
+#define USB_PLLCFG_DIV1           (0x00000000)
+#define USB_PLLCFG_DIV2           (0x00000020)
+#define USB_PLLCFG_DIV4           (0x00000040)
+#define USB_PLLCFG_DIV8           (0x00000060)
+#define USB_PLLCFG_MASK           (0x0000007f)
+
+#define USB_PLLSTAT_MSEL          (0x0000001f)
+#define USB_PLLSTAT_PSEL          (0x00000060)
+#define USB_PLLSTAT_PLLE          (0x00000100)
+#define USB_PLLSTAT_PLLC          (0x00000200)
+#define USB_PLLSTAT_PLOCK         (0x00000400)
+
+#define USB_PLLFEED_FEED1         (0x000000aa)
+#define USB_PLLFEED_FEED2         (0x00000055)
+
+#define USB_IntSt_REQLP           (0x00000001)
+#define USB_IntSt_REQHP           (0x00000002)
+#define USB_IntSt_REQDMA          (0x00000004)
+#define USB_IntSt_NeedClock       (0x00000100)
+#define USB_IntSt_EnUSBInts       (0x80000000)
+#define USB_IntSt_MASK            (0x80000107)
+
+#define USB_DevIntSt_FRAME        (0x00000001)
+#define USB_DevIntSt_EPFAST       (0x00000002)
+#define USB_DevIntSt_EPSLOW       (0x00000004)
+#define USB_DevIntSt_DEVSTAT      (0x00000008)
+#define USB_DevIntSt_CCEMTY       (0x00000010)
+#define USB_DevIntSt_CDFULL       (0x00000020)
+#define USB_DevIntSt_RxENDPKT     (0x00000040)
+#define USB_DevIntSt_TxENDPKT     (0x00000080)
+#define USB_DevIntSt_EPRLZED      (0x00000100)
+#define USB_DevIntSt_EPRINT       (0x00000200)
+#define USB_DevIntSt_MASK         (0x000003ff)
+
+#define USB_DevIntEn_NONE         (0x00000000)
+#define USB_DevIntEn_FRAME        (0x00000001)
+#define USB_DevIntEn_EPFAST       (0x00000002)
+#define USB_DevIntEn_EPSLOW       (0x00000004)
+#define USB_DevIntEn_DEVSTAT      (0x00000008)
+#define USB_DevIntEn_CCEMTY       (0x00000010)
+#define USB_DevIntEn_CDFULL       (0x00000020)
+#define USB_DevIntEn_RxENDPKT     (0x00000040)
+#define USB_DevIntEn_TxENDPKT     (0x00000080)
+#define USB_DevIntEn_EPRLZED      (0x00000100)
+#define USB_DevIntEn_EPRINT       (0x00000200)
+#define USB_DevIntEn_MASK         (0x000003ff)
+
+#define USB_DevIntClr_FRAME       (0x00000001)
+#define USB_DevIntClr_EPFAST      (0x00000002)
+#define USB_DevIntClr_EPSLOW      (0x00000004)
+#define USB_DevIntClr_DEVSTAT     (0x00000008)
+#define USB_DevIntClr_CCEMTY      (0x00000010)
+#define USB_DevIntClr_CDFULL      (0x00000020)
+#define USB_DevIntClr_RxENDPKT    (0x00000040)
+#define USB_DevIntClr_TxENDPKT    (0x00000080)
+#define USB_DevIntClr_EPRLZED     (0x00000100)
+#define USB_DevIntClr_EPRINT      (0x00000200)
+#define USB_DevIntClr_ALL         (0x000003ff)
+#define USB_DevIntClr_MASK        (0x000003ff)
+
+#define USB_DevIntSet_FRAME       (0x00000001)
+#define USB_DevIntSet_EPFAST      (0x00000002)
+#define USB_DevIntSet_EPSLOW      (0x00000004)
+#define USB_DevIntSet_DEVSTAT     (0x00000008)
+#define USB_DevIntSet_CCEMTY      (0x00000010)
+#define USB_DevIntSet_CDFULL      (0x00000020)
+#define USB_DevIntSet_RxENDPKT    (0x00000040)
+#define USB_DevIntSet_TxENDPKT    (0x00000080)
+#define USB_DevIntSet_EPRLZED     (0x00000100)
+#define USB_DevIntSet_EPRINT      (0x00000200)
+#define USB_DevIntSet_MASK        (0x000003ff)
+
+#define USB_DevIntPri_FRAME       (0x00000001)
+#define USB_DevIntPri_EPFAST      (0x00000002)
+#define USB_DevIntPri_MASK        (0x00000003)
+
+#define USB_EpIntSt_EP0RX         (0x00000001)
+#define USB_EpIntSt_EP0TX         (0x00000002)
+#define USB_EpIntSt_EP1RX         (0x00000004)
+#define USB_EpIntSt_EP1TX         (0x00000008)
+#define USB_EpIntSt_EP2RX         (0x00000010)
+#define USB_EpIntSt_EP2TX         (0x00000020)
+#define USB_EpIntSt_EP3RX         (0x00000040)
+#define USB_EpIntSt_EP3TX         (0x00000080)
+#define USB_EpIntSt_EP4RX         (0x00000100)
+#define USB_EpIntSt_EP4TX         (0x00000200)
+#define USB_EpIntSt_EP5RX         (0x00000400)
+#define USB_EpIntSt_EP5TX         (0x00000800)
+#define USB_EpIntSt_EP6RX         (0x00001000)
+#define USB_EpIntSt_EP6TX         (0x00002000)
+#define USB_EpIntSt_EP7RX         (0x00004000)
+#define USB_EpIntSt_EP7TX         (0x00008000)
+#define USB_EpIntSt_EP8RX         (0x00010000)
+#define USB_EpIntSt_EP8TX         (0x00020000)
+#define USB_EpIntSt_EP9RX         (0x00040000)
+#define USB_EpIntSt_EP9TX         (0x00080000)
+#define USB_EpIntSt_EP10RX        (0x00100000)
+#define USB_EpIntSt_EP10TX        (0x00200000)
+#define USB_EpIntSt_EP11RX        (0x00400000)
+#define USB_EpIntSt_EP11TX        (0x00800000)
+#define USB_EpIntSt_EP12RX        (0x01000000)
+#define USB_EpIntSt_EP12TX        (0x02000000)
+#define USB_EpIntSt_EP13RX        (0x04000000)
+#define USB_EpIntSt_EP13TX        (0x08000000)
+#define USB_EpIntSt_EP14RX        (0x10000000)
+#define USB_EpIntSt_EP14TX        (0x20000000)
+#define USB_EpIntSt_EP15RX        (0x40000000)
+#define USB_EpIntSt_EP15TX        (0x80000000)
+#define USB_EpIntSt_MASK          (0xffffffff)
+
+#define USB_EpIntEn_NONE          (0x00000000)
+#define USB_EpIntEn_EP0RX         (0x00000001)
+#define USB_EpIntEn_EP0TX         (0x00000002)
+#define USB_EpIntEn_EP1RX         (0x00000004)
+#define USB_EpIntEn_EP1TX         (0x00000008)
+#define USB_EpIntEn_EP2RX         (0x00000010)
+#define USB_EpIntEn_EP2TX         (0x00000020)
+#define USB_EpIntEn_EP3RX         (0x00000040)
+#define USB_EpIntEn_EP3TX         (0x00000080)
+#define USB_EpIntEn_EP4RX         (0x00000100)
+#define USB_EpIntEn_EP4TX         (0x00000200)
+#define USB_EpIntEn_EP5RX         (0x00000400)
+#define USB_EpIntEn_EP5TX         (0x00000800)
+#define USB_EpIntEn_EP6RX         (0x00001000)
+#define USB_EpIntEn_EP6TX         (0x00002000)
+#define USB_EpIntEn_EP7RX         (0x00004000)
+#define USB_EpIntEn_EP7TX         (0x00008000)
+#define USB_EpIntEn_EP8RX         (0x00010000)
+#define USB_EpIntEn_EP8TX         (0x00020000)
+#define USB_EpIntEn_EP9RX         (0x00040000)
+#define USB_EpIntEn_EP9TX         (0x00080000)
+#define USB_EpIntEn_EP10RX        (0x00100000)
+#define USB_EpIntEn_EP10TX        (0x00200000)
+#define USB_EpIntEn_EP11RX        (0x00400000)
+#define USB_EpIntEn_EP11TX        (0x00800000)
+#define USB_EpIntEn_EP12RX        (0x01000000)
+#define USB_EpIntEn_EP12TX        (0x02000000)
+#define USB_EpIntEn_EP13RX        (0x04000000)
+#define USB_EpIntEn_EP13TX        (0x08000000)
+#define USB_EpIntEn_EP14RX        (0x10000000)
+#define USB_EpIntEn_EP14TX        (0x20000000)
+#define USB_EpIntEn_EP15RX        (0x40000000)
+#define USB_EpIntEn_EP15TX        (0x80000000)
+#define USB_EpIntEn_MASK          (0xffffffff)
+
+#define USB_EpIntClr_EP0RX        (0x00000001)
+#define USB_EpIntClr_EP0TX        (0x00000002)
+#define USB_EpIntClr_EP1RX        (0x00000004)
+#define USB_EpIntClr_EP1TX        (0x00000008)
+#define USB_EpIntClr_EP2RX        (0x00000010)
+#define USB_EpIntClr_EP2TX        (0x00000020)
+#define USB_EpIntClr_EP3RX        (0x00000040)
+#define USB_EpIntClr_EP3TX        (0x00000080)
+#define USB_EpIntClr_EP4RX        (0x00000100)
+#define USB_EpIntClr_EP4TX        (0x00000200)
+#define USB_EpIntClr_EP5RX        (0x00000400)
+#define USB_EpIntClr_EP5TX        (0x00000800)
+#define USB_EpIntClr_EP6RX        (0x00001000)
+#define USB_EpIntClr_EP6TX        (0x00002000)
+#define USB_EpIntClr_EP7RX        (0x00004000)
+#define USB_EpIntClr_EP7TX        (0x00008000)
+#define USB_EpIntClr_EP8RX        (0x00010000)
+#define USB_EpIntClr_EP8TX        (0x00020000)
+#define USB_EpIntClr_EP9RX        (0x00040000)
+#define USB_EpIntClr_EP9TX        (0x00080000)
+#define USB_EpIntClr_EP10RX       (0x00100000)
+#define USB_EpIntClr_EP10TX       (0x00200000)
+#define USB_EpIntClr_EP11RX       (0x00400000)
+#define USB_EpIntClr_EP11TX       (0x00800000)
+#define USB_EpIntClr_EP12RX       (0x01000000)
+#define USB_EpIntClr_EP12TX       (0x02000000)
+#define USB_EpIntClr_EP13RX       (0x04000000)
+#define USB_EpIntClr_EP13TX       (0x08000000)
+#define USB_EpIntClr_EP14RX       (0x10000000)
+#define USB_EpIntClr_EP14TX       (0x20000000)
+#define USB_EpIntClr_EP15RX       (0x40000000)
+#define USB_EpIntClr_EP15TX       (0x80000000)
+#define USB_EpIntClr_ALL          (0xffffffff)
+#define USB_EpIntClr_MASK         (0xffffffff)
+
+#define USB_EpIntSet_EP0RX        (0x00000001)
+#define USB_EpIntSet_EP0TX        (0x00000002)
+#define USB_EpIntSet_EP1RX        (0x00000004)
+#define USB_EpIntSet_EP1TX        (0x00000008)
+#define USB_EpIntSet_EP2RX        (0x00000010)
+#define USB_EpIntSet_EP2TX        (0x00000020)
+#define USB_EpIntSet_EP3RX        (0x00000040)
+#define USB_EpIntSet_EP3TX        (0x00000080)
+#define USB_EpIntSet_EP4RX        (0x00000100)
+#define USB_EpIntSet_EP4TX        (0x00000200)
+#define USB_EpIntSet_EP5RX        (0x00000400)
+#define USB_EpIntSet_EP5TX        (0x00000800)
+#define USB_EpIntSet_EP6RX        (0x00001000)
+#define USB_EpIntSet_EP6TX        (0x00002000)
+#define USB_EpIntSet_EP7RX        (0x00004000)
+#define USB_EpIntSet_EP7TX        (0x00008000)
+#define USB_EpIntSet_EP8RX        (0x00010000)
+#define USB_EpIntSet_EP8TX        (0x00020000)
+#define USB_EpIntSet_EP9RX        (0x00040000)
+#define USB_EpIntSet_EP9TX        (0x00080000)
+#define USB_EpIntSet_EP10RX       (0x00100000)
+#define USB_EpIntSet_EP10TX       (0x00200000)
+#define USB_EpIntSet_EP11RX       (0x00400000)
+#define USB_EpIntSet_EP11TX       (0x00800000)
+#define USB_EpIntSet_EP12RX       (0x01000000)
+#define USB_EpIntSet_EP12TX       (0x02000000)
+#define USB_EpIntSet_EP13RX       (0x04000000)
+#define USB_EpIntSet_EP13TX       (0x08000000)
+#define USB_EpIntSet_EP14RX       (0x10000000)
+#define USB_EpIntSet_EP14TX       (0x20000000)
+#define USB_EpIntSet_EP15RX       (0x40000000)
+#define USB_EpIntSet_EP15TX       (0x80000000)
+#define USB_EpIntSet_MASK         (0xffffffff)
+
+#define USB_EpIntPri_EP0RX        (0x00000001)
+#define USB_EpIntPri_EP0TX        (0x00000002)
+#define USB_EpIntPri_EP1RX        (0x00000004)
+#define USB_EpIntPri_EP1TX        (0x00000008)
+#define USB_EpIntPri_EP2RX        (0x00000010)
+#define USB_EpIntPri_EP2TX        (0x00000020)
+#define USB_EpIntPri_EP3RX        (0x00000040)
+#define USB_EpIntPri_EP3TX        (0x00000080)
+#define USB_EpIntPri_EP4RX        (0x00000100)
+#define USB_EpIntPri_EP4TX        (0x00000200)
+#define USB_EpIntPri_EP5RX        (0x00000400)
+#define USB_EpIntPri_EP5TX        (0x00000800)
+#define USB_EpIntPri_EP6RX        (0x00001000)
+#define USB_EpIntPri_EP6TX        (0x00002000)
+#define USB_EpIntPri_EP7RX        (0x00004000)
+#define USB_EpIntPri_EP7TX        (0x00008000)
+#define USB_EpIntPri_EP8RX        (0x00010000)
+#define USB_EpIntPri_EP8TX        (0x00020000)
+#define USB_EpIntPri_EP9RX        (0x00040000)
+#define USB_EpIntPri_EP9TX        (0x00080000)
+#define USB_EpIntPri_EP10RX       (0x00100000)
+#define USB_EpIntPri_EP10TX       (0x00200000)
+#define USB_EpIntPri_EP11RX       (0x00400000)
+#define USB_EpIntPri_EP11TX       (0x00800000)
+#define USB_EpIntPri_EP12RX       (0x01000000)
+#define USB_EpIntPri_EP12TX       (0x02000000)
+#define USB_EpIntPri_EP13RX       (0x04000000)
+#define USB_EpIntPri_EP13TX       (0x08000000)
+#define USB_EpIntPri_EP14RX       (0x10000000)
+#define USB_EpIntPri_EP14TX       (0x20000000)
+#define USB_EpIntPri_EP15RX       (0x40000000)
+#define USB_EpIntPri_EP15TX       (0x80000000)
+#define USB_EpIntPri_MASK         (0xffffffff)
+
+#define USB_EpRE_EP0              (0x00000001)
+#define USB_EpRE_EP1              (0x00000002)
+#define USB_EpRE_EP2              (0x00000004)
+#define USB_EpRE_EP3              (0x00000008)
+#define USB_EpRE_EP4              (0x00000010)
+#define USB_EpRE_EP5              (0x00000020)
+#define USB_EpRE_EP6              (0x00000040)
+#define USB_EpRE_EP7              (0x00000080)
+#define USB_EpRE_EP8              (0x00000100)
+#define USB_EpRE_EP9              (0x00000200)
+#define USB_EpRE_EP10             (0x00000400)
+#define USB_EpRE_EP11             (0x00000800)
+#define USB_EpRE_EP12             (0x00001000)
+#define USB_EpRE_EP13             (0x00002000)
+#define USB_EpRE_EP14             (0x00004000)
+#define USB_EpRE_EP15             (0x00008000)
+#define USB_EpRE_EP16             (0x00010000)
+#define USB_EpRE_EP17             (0x00020000)
+#define USB_EpRE_EP18             (0x00040000)
+#define USB_EpRE_EP19             (0x00080000)
+#define USB_EpRE_EP20             (0x00100000)
+#define USB_EpRE_EP21             (0x00200000)
+#define USB_EpRE_EP22             (0x00400000)
+#define USB_EpRE_EP23             (0x00800000)
+#define USB_EpRE_EP24             (0x01000000)
+#define USB_EpRE_EP25             (0x02000000)
+#define USB_EpRE_EP26             (0x04000000)
+#define USB_EpRE_EP27             (0x08000000)
+#define USB_EpRE_EP28             (0x10000000)
+#define USB_EpRE_EP29             (0x20000000)
+#define USB_EpRE_EP30             (0x40000000)
+#define USB_EpRE_EP31             (0x80000000)
+#define USB_EpRE_MASK             (0xffffffff)
+
+#define USB_EpIn_MASK             (0x0000001f)
+
+#define USB_MaxPSize_MASK         (0x000003ff)
+
+#define USB_RxPLen_PKTLENGTH      (0x000003ff)
+#define USB_RxPLen_PKTLENGTH_MASK (0x000003ff)
+#define USB_RxPLen_DV             (0x00000400)
+#define USB_RxPLen_PKTRDY         (0x00000800)
+#define USB_RxPLen_MASK           (0x00000fff)
+
+#define USB_TxPLen_PKTLENGTH      (0x000003ff)
+#define USB_TxPLen_MASK           (0x000003ff)
+
+#define USB_Ctrl_RDEN             (0x00000001)
+#define USB_Ctrl_WREN             (0x00000002)
+#define USB_Ctrl_LOGENDPOINT      (0x0000003c)
+#define USB_Ctrl_MASK             (0x0000003f)
+
+#define USB_CmdCode_CMDPHASE      (0x0000ff00)
+#define USB_CmdCode_CMDCODE       (0x00ff0000)
+#define USB_CmdCode_MASK          (0x00ffff00)
+
+#define USB_CmdData_MASK          (0x000000ff)
+
+#define USB_DMARSt_EP0            (0x00000001)
+#define USB_DMARSt_EP1            (0x00000002)
+#define USB_DMARSt_EP2            (0x00000004)
+#define USB_DMARSt_EP3            (0x00000008)
+#define USB_DMARSt_EP4            (0x00000010)
+#define USB_DMARSt_EP5            (0x00000020)
+#define USB_DMARSt_EP6            (0x00000040)
+#define USB_DMARSt_EP7            (0x00000080)
+#define USB_DMARSt_EP8            (0x00000100)
+#define USB_DMARSt_EP9            (0x00000200)
+#define USB_DMARSt_EP10           (0x00000400)
+#define USB_DMARSt_EP11           (0x00000800)
+#define USB_DMARSt_EP12           (0x00001000)
+#define USB_DMARSt_EP13           (0x00002000)
+#define USB_DMARSt_EP14           (0x00004000)
+#define USB_DMARSt_EP15           (0x00008000)
+#define USB_DMARSt_EP16           (0x00010000)
+#define USB_DMARSt_EP17           (0x00020000)
+#define USB_DMARSt_EP18           (0x00040000)
+#define USB_DMARSt_EP19           (0x00080000)
+#define USB_DMARSt_EP20           (0x00100000)
+#define USB_DMARSt_EP21           (0x00200000)
+#define USB_DMARSt_EP22           (0x00400000)
+#define USB_DMARSt_EP23           (0x00800000)
+#define USB_DMARSt_EP24           (0x01000000)
+#define USB_DMARSt_EP25           (0x02000000)
+#define USB_DMARSt_EP26           (0x04000000)
+#define USB_DMARSt_EP27           (0x08000000)
+#define USB_DMARSt_EP28           (0x10000000)
+#define USB_DMARSt_EP29           (0x20000000)
+#define USB_DMARSt_EP30           (0x40000000)
+#define USB_DMARSt_EP31           (0x80000000)
+#define USB_DMARSt_MASK           (0xffffffff)
+
+#define USB_DMARClr_EP0           (0x00000001)
+#define USB_DMARClr_EP1           (0x00000002)
+#define USB_DMARClr_EP2           (0x00000004)
+#define USB_DMARClr_EP3           (0x00000008)
+#define USB_DMARClr_EP4           (0x00000010)
+#define USB_DMARClr_EP5           (0x00000020)
+#define USB_DMARClr_EP6           (0x00000040)
+#define USB_DMARClr_EP7           (0x00000080)
+#define USB_DMARClr_EP8           (0x00000100)
+#define USB_DMARClr_EP9           (0x00000200)
+#define USB_DMARClr_EP10          (0x00000400)
+#define USB_DMARClr_EP11          (0x00000800)
+#define USB_DMARClr_EP12          (0x00001000)
+#define USB_DMARClr_EP13          (0x00002000)
+#define USB_DMARClr_EP14          (0x00004000)
+#define USB_DMARClr_EP15          (0x00008000)
+#define USB_DMARClr_EP16          (0x00010000)
+#define USB_DMARClr_EP17          (0x00020000)
+#define USB_DMARClr_EP18          (0x00040000)
+#define USB_DMARClr_EP19          (0x00080000)
+#define USB_DMARClr_EP20          (0x00100000)
+#define USB_DMARClr_EP21          (0x00200000)
+#define USB_DMARClr_EP22          (0x00400000)
+#define USB_DMARClr_EP23          (0x00800000)
+#define USB_DMARClr_EP24          (0x01000000)
+#define USB_DMARClr_EP25          (0x02000000)
+#define USB_DMARClr_EP26          (0x04000000)
+#define USB_DMARClr_EP27          (0x08000000)
+#define USB_DMARClr_EP28          (0x10000000)
+#define USB_DMARClr_EP29          (0x20000000)
+#define USB_DMARClr_EP30          (0x40000000)
+#define USB_DMARClr_EP31          (0x80000000)
+#define USB_DMARClr_MASK          (0xffffffff)
+
+#define USB_DMARSet_EP0           (0x00000001)
+#define USB_DMARSet_EP1           (0x00000002)
+#define USB_DMARSet_EP2           (0x00000004)
+#define USB_DMARSet_EP3           (0x00000008)
+#define USB_DMARSet_EP4           (0x00000010)
+#define USB_DMARSet_EP5           (0x00000020)
+#define USB_DMARSet_EP6           (0x00000040)
+#define USB_DMARSet_EP7           (0x00000080)
+#define USB_DMARSet_EP8           (0x00000100)
+#define USB_DMARSet_EP9           (0x00000200)
+#define USB_DMARSet_EP10          (0x00000400)
+#define USB_DMARSet_EP11          (0x00000800)
+#define USB_DMARSet_EP12          (0x00001000)
+#define USB_DMARSet_EP13          (0x00002000)
+#define USB_DMARSet_EP14          (0x00004000)
+#define USB_DMARSet_EP15          (0x00008000)
+#define USB_DMARSet_EP16          (0x00010000)
+#define USB_DMARSet_EP17          (0x00020000)
+#define USB_DMARSet_EP18          (0x00040000)
+#define USB_DMARSet_EP19          (0x00080000)
+#define USB_DMARSet_EP20          (0x00100000)
+#define USB_DMARSet_EP21          (0x00200000)
+#define USB_DMARSet_EP22          (0x00400000)
+#define USB_DMARSet_EP23          (0x00800000)
+#define USB_DMARSet_EP24          (0x01000000)
+#define USB_DMARSet_EP25          (0x02000000)
+#define USB_DMARSet_EP26          (0x04000000)
+#define USB_DMARSet_EP27          (0x08000000)
+#define USB_DMARSet_EP28          (0x10000000)
+#define USB_DMARSet_EP29          (0x20000000)
+#define USB_DMARSet_EP30          (0x40000000)
+#define USB_DMARSet_EP31          (0x80000000)
+#define USB_DMARSet_MASK          (0xffffffff)
+
+#define USB_EpDMASt_EP0           (0x00000001)
+#define USB_EpDMASt_EP1           (0x00000002)
+#define USB_EpDMASt_EP2           (0x00000004)
+#define USB_EpDMASt_EP3           (0x00000008)
+#define USB_EpDMASt_EP4           (0x00000010)
+#define USB_EpDMASt_EP5           (0x00000020)
+#define USB_EpDMASt_EP6           (0x00000040)
+#define USB_EpDMASt_EP7           (0x00000080)
+#define USB_EpDMASt_EP8           (0x00000100)
+#define USB_EpDMASt_EP9           (0x00000200)
+#define USB_EpDMASt_EP10          (0x00000400)
+#define USB_EpDMASt_EP11          (0x00000800)
+#define USB_EpDMASt_EP12          (0x00001000)
+#define USB_EpDMASt_EP13          (0x00002000)
+#define USB_EpDMASt_EP14          (0x00004000)
+#define USB_EpDMASt_EP15          (0x00008000)
+#define USB_EpDMASt_EP16          (0x00010000)
+#define USB_EpDMASt_EP17          (0x00020000)
+#define USB_EpDMASt_EP18          (0x00040000)
+#define USB_EpDMASt_EP19          (0x00080000)
+#define USB_EpDMASt_EP20          (0x00100000)
+#define USB_EpDMASt_EP21          (0x00200000)
+#define USB_EpDMASt_EP22          (0x00400000)
+#define USB_EpDMASt_EP23          (0x00800000)
+#define USB_EpDMASt_EP24          (0x01000000)
+#define USB_EpDMASt_EP25          (0x02000000)
+#define USB_EpDMASt_EP26          (0x04000000)
+#define USB_EpDMASt_EP27          (0x08000000)
+#define USB_EpDMASt_EP28          (0x10000000)
+#define USB_EpDMASt_EP29          (0x20000000)
+#define USB_EpDMASt_EP30          (0x40000000)
+#define USB_EpDMASt_EP31          (0x80000000)
+#define USB_EpDMASt_MASK          (0xffffffff)
+
+#define USB_EpDMAEn_EP0           (0x00000001)
+#define USB_EpDMAEn_EP1           (0x00000002)
+#define USB_EpDMAEn_EP2           (0x00000004)
+#define USB_EpDMAEn_EP3           (0x00000008)
+#define USB_EpDMAEn_EP4           (0x00000010)
+#define USB_EpDMAEn_EP5           (0x00000020)
+#define USB_EpDMAEn_EP6           (0x00000040)
+#define USB_EpDMAEn_EP7           (0x00000080)
+#define USB_EpDMAEn_EP8           (0x00000100)
+#define USB_EpDMAEn_EP9           (0x00000200)
+#define USB_EpDMAEn_EP10          (0x00000400)
+#define USB_EpDMAEn_EP11          (0x00000800)
+#define USB_EpDMAEn_EP12          (0x00001000)
+#define USB_EpDMAEn_EP13          (0x00002000)
+#define USB_EpDMAEn_EP14          (0x00004000)
+#define USB_EpDMAEn_EP15          (0x00008000)
+#define USB_EpDMAEn_EP16          (0x00010000)
+#define USB_EpDMAEn_EP17          (0x00020000)
+#define USB_EpDMAEn_EP18          (0x00040000)
+#define USB_EpDMAEn_EP19          (0x00080000)
+#define USB_EpDMAEn_EP20          (0x00100000)
+#define USB_EpDMAEn_EP21          (0x00200000)
+#define USB_EpDMAEn_EP22          (0x00400000)
+#define USB_EpDMAEn_EP23          (0x00800000)
+#define USB_EpDMAEn_EP24          (0x01000000)
+#define USB_EpDMAEn_EP25          (0x02000000)
+#define USB_EpDMAEn_EP26          (0x04000000)
+#define USB_EpDMAEn_EP27          (0x08000000)
+#define USB_EpDMAEn_EP28          (0x10000000)
+#define USB_EpDMAEn_EP29          (0x20000000)
+#define USB_EpDMAEn_EP30          (0x40000000)
+#define USB_EpDMAEn_EP31          (0x80000000)
+#define USB_EpDMAEn_MASK          (0xffffffff)
+
+#define USB_EpDMADis_EP0          (0x00000001)
+#define USB_EpDMADis_EP1          (0x00000002)
+#define USB_EpDMADis_EP2          (0x00000004)
+#define USB_EpDMADis_EP3          (0x00000008)
+#define USB_EpDMADis_EP4          (0x00000010)
+#define USB_EpDMADis_EP5          (0x00000020)
+#define USB_EpDMADis_EP6          (0x00000040)
+#define USB_EpDMADis_EP7          (0x00000080)
+#define USB_EpDMADis_EP8          (0x00000100)
+#define USB_EpDMADis_EP9          (0x00000200)
+#define USB_EpDMADis_EP10         (0x00000400)
+#define USB_EpDMADis_EP11         (0x00000800)
+#define USB_EpDMADis_EP12         (0x00001000)
+#define USB_EpDMADis_EP13         (0x00002000)
+#define USB_EpDMADis_EP14         (0x00004000)
+#define USB_EpDMADis_EP15         (0x00008000)
+#define USB_EpDMADis_EP16         (0x00010000)
+#define USB_EpDMADis_EP17         (0x00020000)
+#define USB_EpDMADis_EP18         (0x00040000)
+#define USB_EpDMADis_EP19         (0x00080000)
+#define USB_EpDMADis_EP20         (0x00100000)
+#define USB_EpDMADis_EP21         (0x00200000)
+#define USB_EpDMADis_EP22         (0x00400000)
+#define USB_EpDMADis_EP23         (0x00800000)
+#define USB_EpDMADis_EP24         (0x01000000)
+#define USB_EpDMADis_EP25         (0x02000000)
+#define USB_EpDMADis_EP26         (0x04000000)
+#define USB_EpDMADis_EP27         (0x08000000)
+#define USB_EpDMADis_EP28         (0x10000000)
+#define USB_EpDMADis_EP29         (0x20000000)
+#define USB_EpDMADis_EP30         (0x40000000)
+#define USB_EpDMADis_EP31         (0x80000000)
+#define USB_EpDMADis_MASK         (0xffffffff)
+
+#define USB_DMAInstSt_EOT         (0x00000001)
+#define USB_DMAInstSt_NDDR        (0x00000002)
+#define USB_DMAInstSt_SE          (0x00000004)
+#define USB_DMAInstSt_MASK        (0x00000007)
+
+#define USB_DMAInstEn_EOT         (0x00000001)
+#define USB_DMAInstEn_NDDR        (0x00000002)
+#define USB_DMAInstEn_SE          (0x00000004)
+#define USB_DMAInstEn_MASK        (0x00000007)
+
+#define USB_EoTIntSt_EP0          (0x00000001)
+#define USB_EoTIntSt_EP1          (0x00000002)
+#define USB_EoTIntSt_EP2          (0x00000004)
+#define USB_EoTIntSt_EP3          (0x00000008)
+#define USB_EoTIntSt_EP4          (0x00000010)
+#define USB_EoTIntSt_EP5          (0x00000020)
+#define USB_EoTIntSt_EP6          (0x00000040)
+#define USB_EoTIntSt_EP7          (0x00000080)
+#define USB_EoTIntSt_EP8          (0x00000100)
+#define USB_EoTIntSt_EP9          (0x00000200)
+#define USB_EoTIntSt_EP10         (0x00000400)
+#define USB_EoTIntSt_EP11         (0x00000800)
+#define USB_EoTIntSt_EP12         (0x00001000)
+#define USB_EoTIntSt_EP13         (0x00002000)
+#define USB_EoTIntSt_EP14         (0x00004000)
+#define USB_EoTIntSt_EP15         (0x00008000)
+#define USB_EoTIntSt_EP16         (0x00010000)
+#define USB_EoTIntSt_EP17         (0x00020000)
+#define USB_EoTIntSt_EP18         (0x00040000)
+#define USB_EoTIntSt_EP19         (0x00080000)
+#define USB_EoTIntSt_EP20         (0x00100000)
+#define USB_EoTIntSt_EP21         (0x00200000)
+#define USB_EoTIntSt_EP22         (0x00400000)
+#define USB_EoTIntSt_EP23         (0x00800000)
+#define USB_EoTIntSt_EP24         (0x01000000)
+#define USB_EoTIntSt_EP25         (0x02000000)
+#define USB_EoTIntSt_EP26         (0x04000000)
+#define USB_EoTIntSt_EP27         (0x08000000)
+#define USB_EoTIntSt_EP28         (0x10000000)
+#define USB_EoTIntSt_EP29         (0x20000000)
+#define USB_EoTIntSt_EP30         (0x40000000)
+#define USB_EoTIntSt_EP31         (0x80000000)
+#define USB_EoTIntSt_MASK         (0xffffffff)
+
+#define USB_EoTIntClr_EP0         (0x00000001)
+#define USB_EoTIntClr_EP1         (0x00000002)
+#define USB_EoTIntClr_EP2         (0x00000004)
+#define USB_EoTIntClr_EP3         (0x00000008)
+#define USB_EoTIntClr_EP4         (0x00000010)
+#define USB_EoTIntClr_EP5         (0x00000020)
+#define USB_EoTIntClr_EP6         (0x00000040)
+#define USB_EoTIntClr_EP7         (0x00000080)
+#define USB_EoTIntClr_EP8         (0x00000100)
+#define USB_EoTIntClr_EP9         (0x00000200)
+#define USB_EoTIntClr_EP10        (0x00000400)
+#define USB_EoTIntClr_EP11        (0x00000800)
+#define USB_EoTIntClr_EP12        (0x00001000)
+#define USB_EoTIntClr_EP13        (0x00002000)
+#define USB_EoTIntClr_EP14        (0x00004000)
+#define USB_EoTIntClr_EP15        (0x00008000)
+#define USB_EoTIntClr_EP16        (0x00010000)
+#define USB_EoTIntClr_EP17        (0x00020000)
+#define USB_EoTIntClr_EP18        (0x00040000)
+#define USB_EoTIntClr_EP19        (0x00080000)
+#define USB_EoTIntClr_EP20        (0x00100000)
+#define USB_EoTIntClr_EP21        (0x00200000)
+#define USB_EoTIntClr_EP22        (0x00400000)
+#define USB_EoTIntClr_EP23        (0x00800000)
+#define USB_EoTIntClr_EP24        (0x01000000)
+#define USB_EoTIntClr_EP25        (0x02000000)
+#define USB_EoTIntClr_EP26        (0x04000000)
+#define USB_EoTIntClr_EP27        (0x08000000)
+#define USB_EoTIntClr_EP28        (0x10000000)
+#define USB_EoTIntClr_EP29        (0x20000000)
+#define USB_EoTIntClr_EP30        (0x40000000)
+#define USB_EoTIntClr_EP31        (0x80000000)
+#define USB_EoTIntClr_MASK        (0xffffffff)
+
+#define USB_EoTIntSet_EP0         (0x00000001)
+#define USB_EoTIntSet_EP1         (0x00000002)
+#define USB_EoTIntSet_EP2         (0x00000004)
+#define USB_EoTIntSet_EP3         (0x00000008)
+#define USB_EoTIntSet_EP4         (0x00000010)
+#define USB_EoTIntSet_EP5         (0x00000020)
+#define USB_EoTIntSet_EP6         (0x00000040)
+#define USB_EoTIntSet_EP7         (0x00000080)
+#define USB_EoTIntSet_EP8         (0x00000100)
+#define USB_EoTIntSet_EP9         (0x00000200)
+#define USB_EoTIntSet_EP10        (0x00000400)
+#define USB_EoTIntSet_EP11        (0x00000800)
+#define USB_EoTIntSet_EP12        (0x00001000)
+#define USB_EoTIntSet_EP13        (0x00002000)
+#define USB_EoTIntSet_EP14        (0x00004000)
+#define USB_EoTIntSet_EP15        (0x00008000)
+#define USB_EoTIntSet_EP16        (0x00010000)
+#define USB_EoTIntSet_EP17        (0x00020000)
+#define USB_EoTIntSet_EP18        (0x00040000)
+#define USB_EoTIntSet_EP19        (0x00080000)
+#define USB_EoTIntSet_EP20        (0x00100000)
+#define USB_EoTIntSet_EP21        (0x00200000)
+#define USB_EoTIntSet_EP22        (0x00400000)
+#define USB_EoTIntSet_EP23        (0x00800000)
+#define USB_EoTIntSet_EP24        (0x01000000)
+#define USB_EoTIntSet_EP25        (0x02000000)
+#define USB_EoTIntSet_EP26        (0x04000000)
+#define USB_EoTIntSet_EP27        (0x08000000)
+#define USB_EoTIntSet_EP28        (0x10000000)
+#define USB_EoTIntSet_EP29        (0x20000000)
+#define USB_EoTIntSet_EP30        (0x40000000)
+#define USB_EoTIntSet_EP31        (0x80000000)
+#define USB_EoTIntSet_MASK        (0xffffffff)
+
+#define USB_NDDRIntSt_EP0         (0x00000001)
+#define USB_NDDRIntSt_EP1         (0x00000002)
+#define USB_NDDRIntSt_EP2         (0x00000004)
+#define USB_NDDRIntSt_EP3         (0x00000008)
+#define USB_NDDRIntSt_EP4         (0x00000010)
+#define USB_NDDRIntSt_EP5         (0x00000020)
+#define USB_NDDRIntSt_EP6         (0x00000040)
+#define USB_NDDRIntSt_EP7         (0x00000080)
+#define USB_NDDRIntSt_EP8         (0x00000100)
+#define USB_NDDRIntSt_EP9         (0x00000200)
+#define USB_NDDRIntSt_EP10        (0x00000400)
+#define USB_NDDRIntSt_EP11        (0x00000800)
+#define USB_NDDRIntSt_EP12        (0x00001000)
+#define USB_NDDRIntSt_EP13        (0x00002000)
+#define USB_NDDRIntSt_EP14        (0x00004000)
+#define USB_NDDRIntSt_EP15        (0x00008000)
+#define USB_NDDRIntSt_EP16        (0x00010000)
+#define USB_NDDRIntSt_EP17        (0x00020000)
+#define USB_NDDRIntSt_EP18        (0x00040000)
+#define USB_NDDRIntSt_EP19        (0x00080000)
+#define USB_NDDRIntSt_EP20        (0x00100000)
+#define USB_NDDRIntSt_EP21        (0x00200000)
+#define USB_NDDRIntSt_EP22        (0x00400000)
+#define USB_NDDRIntSt_EP23        (0x00800000)
+#define USB_NDDRIntSt_EP24        (0x01000000)
+#define USB_NDDRIntSt_EP25        (0x02000000)
+#define USB_NDDRIntSt_EP26        (0x04000000)
+#define USB_NDDRIntSt_EP27        (0x08000000)
+#define USB_NDDRIntSt_EP28        (0x10000000)
+#define USB_NDDRIntSt_EP29        (0x20000000)
+#define USB_NDDRIntSt_EP30        (0x40000000)
+#define USB_NDDRIntSt_EP31        (0x80000000)
+#define USB_NDDRIntSt_MASK        (0xffffffff)
+
+#define USB_NDDRIntClr_EP0        (0x00000001)
+#define USB_NDDRIntClr_EP1        (0x00000002)
+#define USB_NDDRIntClr_EP2        (0x00000004)
+#define USB_NDDRIntClr_EP3        (0x00000008)
+#define USB_NDDRIntClr_EP4        (0x00000010)
+#define USB_NDDRIntClr_EP5        (0x00000020)
+#define USB_NDDRIntClr_EP6        (0x00000040)
+#define USB_NDDRIntClr_EP7        (0x00000080)
+#define USB_NDDRIntClr_EP8        (0x00000100)
+#define USB_NDDRIntClr_EP9        (0x00000200)
+#define USB_NDDRIntClr_EP10       (0x00000400)
+#define USB_NDDRIntClr_EP11       (0x00000800)
+#define USB_NDDRIntClr_EP12       (0x00001000)
+#define USB_NDDRIntClr_EP13       (0x00002000)
+#define USB_NDDRIntClr_EP14       (0x00004000)
+#define USB_NDDRIntClr_EP15       (0x00008000)
+#define USB_NDDRIntClr_EP16       (0x00010000)
+#define USB_NDDRIntClr_EP17       (0x00020000)
+#define USB_NDDRIntClr_EP18       (0x00040000)
+#define USB_NDDRIntClr_EP19       (0x00080000)
+#define USB_NDDRIntClr_EP20       (0x00100000)
+#define USB_NDDRIntClr_EP21       (0x00200000)
+#define USB_NDDRIntClr_EP22       (0x00400000)
+#define USB_NDDRIntClr_EP23       (0x00800000)
+#define USB_NDDRIntClr_EP24       (0x01000000)
+#define USB_NDDRIntClr_EP25       (0x02000000)
+#define USB_NDDRIntClr_EP26       (0x04000000)
+#define USB_NDDRIntClr_EP27       (0x08000000)
+#define USB_NDDRIntClr_EP28       (0x10000000)
+#define USB_NDDRIntClr_EP29       (0x20000000)
+#define USB_NDDRIntClr_EP30       (0x40000000)
+#define USB_NDDRIntClr_EP31       (0x80000000)
+#define USB_NDDRIntClr_MASK       (0xffffffff)
+
+#define USB_NDDRIntSet_EP0        (0x00000001)
+#define USB_NDDRIntSet_EP1        (0x00000002)
+#define USB_NDDRIntSet_EP2        (0x00000004)
+#define USB_NDDRIntSet_EP3        (0x00000008)
+#define USB_NDDRIntSet_EP4        (0x00000010)
+#define USB_NDDRIntSet_EP5        (0x00000020)
+#define USB_NDDRIntSet_EP6        (0x00000040)
+#define USB_NDDRIntSet_EP7        (0x00000080)
+#define USB_NDDRIntSet_EP8        (0x00000100)
+#define USB_NDDRIntSet_EP9        (0x00000200)
+#define USB_NDDRIntSet_EP10       (0x00000400)
+#define USB_NDDRIntSet_EP11       (0x00000800)
+#define USB_NDDRIntSet_EP12       (0x00001000)
+#define USB_NDDRIntSet_EP13       (0x00002000)
+#define USB_NDDRIntSet_EP14       (0x00004000)
+#define USB_NDDRIntSet_EP15       (0x00008000)
+#define USB_NDDRIntSet_EP16       (0x00010000)
+#define USB_NDDRIntSet_EP17       (0x00020000)
+#define USB_NDDRIntSet_EP18       (0x00040000)
+#define USB_NDDRIntSet_EP19       (0x00080000)
+#define USB_NDDRIntSet_EP20       (0x00100000)
+#define USB_NDDRIntSet_EP21       (0x00200000)
+#define USB_NDDRIntSet_EP22       (0x00400000)
+#define USB_NDDRIntSet_EP23       (0x00800000)
+#define USB_NDDRIntSet_EP24       (0x01000000)
+#define USB_NDDRIntSet_EP25       (0x02000000)
+#define USB_NDDRIntSet_EP26       (0x04000000)
+#define USB_NDDRIntSet_EP27       (0x08000000)
+#define USB_NDDRIntSet_EP28       (0x10000000)
+#define USB_NDDRIntSet_EP29       (0x20000000)
+#define USB_NDDRIntSet_EP30       (0x40000000)
+#define USB_NDDRIntSet_EP31       (0x80000000)
+#define USB_NDDRIntSet_MASK       (0xffffffff)
+
+#define USB_SysErrIntSt_EP0       (0x00000001)
+#define USB_SysErrIntSt_EP1       (0x00000002)
+#define USB_SysErrIntSt_EP2       (0x00000004)
+#define USB_SysErrIntSt_EP3       (0x00000008)
+#define USB_SysErrIntSt_EP4       (0x00000010)
+#define USB_SysErrIntSt_EP5       (0x00000020)
+#define USB_SysErrIntSt_EP6       (0x00000040)
+#define USB_SysErrIntSt_EP7       (0x00000080)
+#define USB_SysErrIntSt_EP8       (0x00000100)
+#define USB_SysErrIntSt_EP9       (0x00000200)
+#define USB_SysErrIntSt_EP10      (0x00000400)
+#define USB_SysErrIntSt_EP11      (0x00000800)
+#define USB_SysErrIntSt_EP12      (0x00001000)
+#define USB_SysErrIntSt_EP13      (0x00002000)
+#define USB_SysErrIntSt_EP14      (0x00004000)
+#define USB_SysErrIntSt_EP15      (0x00008000)
+#define USB_SysErrIntSt_EP16      (0x00010000)
+#define USB_SysErrIntSt_EP17      (0x00020000)
+#define USB_SysErrIntSt_EP18      (0x00040000)
+#define USB_SysErrIntSt_EP19      (0x00080000)
+#define USB_SysErrIntSt_EP20      (0x00100000)
+#define USB_SysErrIntSt_EP21      (0x00200000)
+#define USB_SysErrIntSt_EP22      (0x00400000)
+#define USB_SysErrIntSt_EP23      (0x00800000)
+#define USB_SysErrIntSt_EP24      (0x01000000)
+#define USB_SysErrIntSt_EP25      (0x02000000)
+#define USB_SysErrIntSt_EP26      (0x04000000)
+#define USB_SysErrIntSt_EP27      (0x08000000)
+#define USB_SysErrIntSt_EP28      (0x10000000)
+#define USB_SysErrIntSt_EP29      (0x20000000)
+#define USB_SysErrIntSt_EP30      (0x40000000)
+#define USB_SysErrIntSt_EP31      (0x80000000)
+#define USB_SysErrIntSt_MASK      (0xffffffff)
+
+#define USB_SysErrIntClr_EP0      (0x00000001)
+#define USB_SysErrIntClr_EP1      (0x00000002)
+#define USB_SysErrIntClr_EP2      (0x00000004)
+#define USB_SysErrIntClr_EP3      (0x00000008)
+#define USB_SysErrIntClr_EP4      (0x00000010)
+#define USB_SysErrIntClr_EP5      (0x00000020)
+#define USB_SysErrIntClr_EP6      (0x00000040)
+#define USB_SysErrIntClr_EP7      (0x00000080)
+#define USB_SysErrIntClr_EP8      (0x00000100)
+#define USB_SysErrIntClr_EP9      (0x00000200)
+#define USB_SysErrIntClr_EP10     (0x00000400)
+#define USB_SysErrIntClr_EP11     (0x00000800)
+#define USB_SysErrIntClr_EP12     (0x00001000)
+#define USB_SysErrIntClr_EP13     (0x00002000)
+#define USB_SysErrIntClr_EP14     (0x00004000)
+#define USB_SysErrIntClr_EP15     (0x00008000)
+#define USB_SysErrIntClr_EP16     (0x00010000)
+#define USB_SysErrIntClr_EP17     (0x00020000)
+#define USB_SysErrIntClr_EP18     (0x00040000)
+#define USB_SysErrIntClr_EP19     (0x00080000)
+#define USB_SysErrIntClr_EP20     (0x00100000)
+#define USB_SysErrIntClr_EP21     (0x00200000)
+#define USB_SysErrIntClr_EP22     (0x00400000)
+#define USB_SysErrIntClr_EP23     (0x00800000)
+#define USB_SysErrIntClr_EP24     (0x01000000)
+#define USB_SysErrIntClr_EP25     (0x02000000)
+#define USB_SysErrIntClr_EP26     (0x04000000)
+#define USB_SysErrIntClr_EP27     (0x08000000)
+#define USB_SysErrIntClr_EP28     (0x10000000)
+#define USB_SysErrIntClr_EP29     (0x20000000)
+#define USB_SysErrIntClr_EP30     (0x40000000)
+#define USB_SysErrIntClr_EP31     (0x80000000)
+#define USB_SysErrIntClr_MASK     (0xffffffff)
+
+#define USB_SysErrIntSet_EP0      (0x00000001)
+#define USB_SysErrIntSet_EP1      (0x00000002)
+#define USB_SysErrIntSet_EP2      (0x00000004)
+#define USB_SysErrIntSet_EP3      (0x00000008)
+#define USB_SysErrIntSet_EP4      (0x00000010)
+#define USB_SysErrIntSet_EP5      (0x00000020)
+#define USB_SysErrIntSet_EP6      (0x00000040)
+#define USB_SysErrIntSet_EP7      (0x00000080)
+#define USB_SysErrIntSet_EP8      (0x00000100)
+#define USB_SysErrIntSet_EP9      (0x00000200)
+#define USB_SysErrIntSet_EP10     (0x00000400)
+#define USB_SysErrIntSet_EP11     (0x00000800)
+#define USB_SysErrIntSet_EP12     (0x00001000)
+#define USB_SysErrIntSet_EP13     (0x00002000)
+#define USB_SysErrIntSet_EP14     (0x00004000)
+#define USB_SysErrIntSet_EP15     (0x00008000)
+#define USB_SysErrIntSet_EP16     (0x00010000)
+#define USB_SysErrIntSet_EP17     (0x00020000)
+#define USB_SysErrIntSet_EP18     (0x00040000)
+#define USB_SysErrIntSet_EP19     (0x00080000)
+#define USB_SysErrIntSet_EP20     (0x00100000)
+#define USB_SysErrIntSet_EP21     (0x00200000)
+#define USB_SysErrIntSet_EP22     (0x00400000)
+#define USB_SysErrIntSet_EP23     (0x00800000)
+#define USB_SysErrIntSet_EP24     (0x01000000)
+#define USB_SysErrIntSet_EP25     (0x02000000)
+#define USB_SysErrIntSet_EP26     (0x04000000)
+#define USB_SysErrIntSet_EP27     (0x08000000)
+#define USB_SysErrIntSet_EP28     (0x10000000)
+#define USB_SysErrIntSet_EP29     (0x20000000)
+#define USB_SysErrIntSet_EP30     (0x40000000)
+#define USB_SysErrIntSet_EP31     (0x80000000)
+#define USB_SysErrIntSet_MASK     (0xffffffff)
+
+
+/*##############################################################################
+## Memory Accelerator Module (MAM)
+##############################################################################*/
+
+#define MAM_CR            (*(pREG32 (0xe01fc000)))
+#define MAM_TIM           (*(pREG32 (0xe01fc004)))
+
+#define MAM_CR_DISABLE    (0x000000000)
+#define MAM_CR_PARTIAL    (0x000000001)
+#define MAM_CR_FULL       (0x000000002)
+#define MAM_CR_RSVD       (0x000000003)
+#define MAM_CR_MASK       (0x000000003)
+
+#define MAM_TIM_RSVD      (0x000000000)
+#define MAM_TIM_1         (0x000000001)
+#define MAM_TIM_2         (0x000000002)
+#define MAM_TIM_3         (0x000000003)
+#define MAM_TIM_4         (0x000000004)
+#define MAM_TIM_5         (0x000000005)
+#define MAM_TIM_6         (0x000000006)
+#define MAM_TIM_7         (0x000000007)
+#define MAM_TIM_MASK      (0x000000007)
+
+
+/*##############################################################################
+## IAP/ISP
+##############################################################################*/
+
+#define IAP_LOCATION            (0x7ffffff1)
+#define IAP_CMD_PREPARE         (50)
+#define IAP_CMD_COPYRAMTOFLASH  (51)
+#define IAP_CMD_ERASE           (52)
+#define IAP_CMD_BLANKCHECK      (53)
+#define IAP_CMD_READPARTID      (54)
+#define IAP_CMD_READBOOTCODEVER (55)
+#define IAP_CMD_COMPARE         (56)
+#define IAP_CMD_REINVOKEISP     (57)
+
+#define IAP_RESULT_CMD_SUCCESS          (0)
+#define IAP_RESULT_INVALID_COMMAND      (1)
+#define IAP_RESULT_SRC_ADDR_ERROR       (2)
+#define IAP_RESULT_DST_ADDR_ERROR       (3)
+#define IAP_RESULT_SRC_ADDR_NOT_MAPPED  (4)
+#define IAP_RESULT_DST_ADDR_NOT_MAPPED  (5)
+#define IAP_RESULT_COUNT_ERROR          (6)
+#define IAP_RESULT_INVALID_SECTOR       (7)
+#define IAP_RESULT_SECTOR_NOT_BLANK     (8)
+#define IAP_RESULT_SECTOR_NOT_PREPARED  (9)
+#define IAP_RESULT_COMPARE_ERROR        (10)
+#define IAP_RESULT_BUSY                 (11)
+#define IAP_RESULT_PARAM_ERROR          (12)
+#define IAP_RESULT_ADDR_ERROR           (13)
+#define IAP_RESULT_ADDR_NOT_MAPPED      (14)
+#define IAP_RESULT_CMD_LOCKED           (15)
+#define IAP_RESULT_INVALID_CODE         (16)
+#define IAP_RESULT_INVALID_BAUD_RATE    (17)
+#define IAP_RESULT_ANVALID_STOP_BIT     (18)
+#define IAP_RESULT_CRP_ENABLED          (19)
+#define IAP_RESULT_LAST                 (19)
+
+#endif
diff --git a/lpc2148-rom.ld b/lpc2148-rom.ld
new file mode 100644 (file)
index 0000000..ec63759
--- /dev/null
@@ -0,0 +1,70 @@
+MEMORY 
+{
+       flash   : ORIGIN = 0, LENGTH = 500K
+       ram             : ORIGIN = 0x40000000, LENGTH = 32K - 32
+}
+
+__stack_end__ = 0x40000000 + 32K - 36;
+
+SECTIONS 
+{
+       . = 0;
+       startup : 
+  { 
+    __start_of_startup__ = .;
+    *(.startup)
+    __end_of_startup__ = .;
+  } >flash
+
+       prog : 
+       {
+    __start_of_text__ = .;
+    __start_of_prog__ = .;
+               *(.text)
+    __end_of_prog__ = .;
+    __start_of_rodata__ = .;
+               *(.rodata)
+               *(.rodata*)
+    __end_of_rodata__ = .;
+    __start_of_glue7__ = .;
+               *(.glue_7)
+               *(.glue_7t)
+    __end_of_glue7__ = .;
+       } >flash
+
+       __end_of_text__ = .;
+
+  .protected :
+  {
+    __protected_beg__ = .;
+    *(.protected)
+    __protected_end__ = .;
+  } >ram
+  
+       .data : 
+       {
+               __data_beg__ = .;
+               __data_beg_src__ = __end_of_text__;
+               *(.data)
+               __data_end__ = .;
+       } >ram AT>flash
+
+       .bss : 
+       {
+               __bss_beg__ = .;
+               *(.bss)
+       } >ram
+
+       /* Align here to ensure that the .bss section occupies space up to
+       _end.  Align after .bss to ensure correct alignment even if the
+       .bss section disappears because there are no input sections.  */
+       . = ALIGN(32 / 8);
+}
+       . = ALIGN(32 / 8);
+       _end = .;
+       _bss_end__ = .; 
+  __bss_end__ = .; 
+  __heap_beg__ = .;
+  __heap_end__ = .;
+  __end__ = . ;
+       PROVIDE (end = .);
diff --git a/lpc2148_demo.fms b/lpc2148_demo.fms
new file mode 100755 (executable)
index 0000000..53a41f3
--- /dev/null
@@ -0,0 +1,183 @@
+[main]
+interface=None (ISP)
+comport=COM 1
+baudrate=9600
+oscfrequency=16.000000
+i2caddr=26
+device=LPC2148
+hexfile=F:\Katana\LPC2148_Demo\lpc2148.hex
+blocknum=27
+block0=0
+block1=0
+block2=0
+block3=0
+block4=0
+block5=0
+block6=0
+block7=0
+block8=0
+block9=0
+block10=0
+block11=0
+block12=0
+block13=0
+block14=0
+block15=0
+block16=0
+block17=0
+block18=0
+block19=0
+block20=0
+block21=0
+block22=0
+block23=0
+block24=0
+block25=0
+block26=0
+allflash=0
+neededflash=1
+verify=0
+fill=0
+checksums=0
+securitybit1=0
+securitybit2=0
+securitybit3=0
+clocks=0
+reset=0
+securitybitslist0=0
+securitybitslist1=0
+securitybitslist2=0
+securitybitslist3=0
+securitybitslist4=0
+securitybitslist5=0
+securitybitslist6=0
+securitybitslist7=0
+securitybitslist8=0
+securitybitslist9=0
+securitybitslist10=0
+securitybitslist11=0
+securitybitslist12=0
+securitybitslist13=0
+securitybitslist14=0
+securitybitslist15=0
+securitybitslist16=0
+securitybitslist17=0
+securitybitslist18=0
+securitybitslist19=0
+securitybitslist20=0
+securitybitslist21=0
+securitybitslist22=0
+securitybitslist23=0
+securitybitslist24=0
+securitybitslist25=0
+securitybitslist26=0
+securitybitslist27=0
+securitybitslist28=0
+securitybitslist29=0
+securitybitslist30=0
+securitybitslist31=0
+securitybitslist32=0
+securitybitslist33=0
+securitybitslist34=0
+securitybitslist35=0
+securitybitslist36=0
+securitybitslist37=0
+securitybitslist38=0
+securitybitslist39=0
+securitybitslist40=0
+securitybitslist41=0
+securitybitslist42=0
+securitybitslist43=0
+securitybitslist44=0
+securitybitslist45=0
+securitybitslist46=0
+securitybitslist47=0
+securitybitslist48=0
+securitybitslist49=0
+securitybitslist50=0
+securitybitslist51=0
+securitybitslist52=0
+securitybitslist53=0
+securitybitslist54=0
+securitybitslist55=0
+securitybitslist56=0
+securitybitslist57=0
+securitybitslist58=0
+securitybitslist59=0
+securitybitslist60=0
+securitybitslist61=0
+securitybitslist62=0
+securitybitslist63=0
+securitybitslist64=0
+securitybitslist65=0
+securitybitslist66=0
+securitybitslist67=0
+securitybitslist68=0
+securitybitslist69=0
+securitybitslist70=0
+securitybitslist71=0
+securitybitslist72=0
+securitybitslist73=0
+securitybitslist74=0
+securitybitslist75=0
+securitybitslist76=0
+securitybitslist77=0
+securitybitslist78=0
+securitybitslist79=0
+securitybitslist80=0
+securitybitslist81=0
+securitybitslist82=0
+securitybitslist83=0
+securitybitslist84=0
+securitybitslist85=0
+securitybitslist86=0
+securitybitslist87=0
+securitybitslist88=0
+securitybitslist89=0
+securitybitslist90=0
+securitybitslist91=0
+securitybitslist92=0
+securitybitslist93=0
+securitybitslist94=0
+securitybitslist95=0
+[advanced]
+highspeed=0
+highspeedmax=230400
+clocks6=1
+clocks12=0
+halfduplex=0
+hwenable=1
+hwbootexecrts=0
+hwassert=0
+hwassertlpc=0
+hwt1=50
+hwt2=100
+hwbootlpc=1
+hwbootlpcselector=0
+protectisp=1
+playwav=0
+wavfile=
+jitmodule=
+jitoptions=
+jittimeout=
+mytimeouts=0
+regulartimeout=4
+longtimeout=60
+disablesignature=0
+[startbootrom]
+command=boot
+baudrate=9600
+append=noctrl
+send=command
+[terminal]
+comport=1
+baudrate=9600
+modifycomport=0
+dtrrts=0
+usedelaychar=0
+delaychar=35
+chardelay=1000
+newline=1
+[eeprom]
+hexfile=
+crchexfilesnum=0
diff --git a/main.c b/main.c
new file mode 100644 (file)
index 0000000..7f668d0
--- /dev/null
+++ b/main.c
@@ -0,0 +1,87 @@
+//
+//  Standard includes
+//
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+//
+// Scheduler includes
+//
+#include "FreeRTOS.h"
+#include "task.h"
+
+//
+//  Demo application includes
+//
+#include "main.h"
+#include "adc/adc.h"
+#include "cpu/cpu.h"
+#include "dac/dac.h"
+#include "eints/eints.h"
+#include "gps/gps.h"
+#include "fiq/fiq.h"
+#include "i2c/i2c.h"
+#include "iap/iap.h"
+#include "leds/leds.h"
+#include "monitor/monitor.h"
+#include "rtc/rtc.h"
+#include "sensors/sensors.h"
+#include "uart/uart.h"
+#include "usbser/usbser.h"
+#include "usbmass/usbmass.h"
+
+//
+//
+//
+#define BAUD_UART0 115200
+#define BAUD_UART1 4800
+
+#ifdef CFG_CONSOLE_UART1
+#undef BAUD_UART1
+#define BAUD_UART1 115200
+#endif
+
+#if defined CFG_CONSOLE_USB && defined CFG_USB_MSC
+#error Cannot have USB console and MSC defined at the same time
+#endif
+
+//
+//
+//
+xTaskHandle taskHandles [TASKHANDLE_LAST];
+
+//
+//
+//
+int main (void)
+{
+  cpuSetupHardware ();
+  uartInit (0, BAUD_UART0, 64);
+  uartInit (1, BAUD_UART1, 64);
+#ifndef CFG_USB_MSC
+  usbserInit ();
+#else
+  usbmassInit ();
+#endif
+  rtcInit ();
+  adcInit ();
+  dacInit ();
+  i2cInit ();
+  eintsInit ();
+  fiqInit ();
+  iapInit ();
+
+  memset (taskHandles, 0, sizeof (taskHandles));
+
+  xTaskCreate (vSensorsTask,  (const signed portCHAR * const) "Sensors",  512,                      NULL, (configMAX_PRIORITIES - 2), &taskHandles [TASKHANDLE_SENSORS]);
+#ifndef CFG_CONSOLE_UART1
+  xTaskCreate (vGPSTask,      (const signed portCHAR * const) "GPS",      768,                      NULL, (tskIDLE_PRIORITY + 1),     &taskHandles [TASKHANDLE_GPS]);
+#endif
+  xTaskCreate (vMonitorTask,  (const signed portCHAR * const) "Monitor",  1024,                     NULL, (tskIDLE_PRIORITY + 1),     &taskHandles [TASKHANDLE_MONITOR]);
+  xTaskCreate (vLEDFlashTask, (const signed portCHAR * const) "LEDx",     configMINIMAL_STACK_SIZE, NULL, (tskIDLE_PRIORITY + 1),     &taskHandles [TASKHANDLE_LED]);
+  vTaskStartScheduler ();
+
+  return 0;
+}
diff --git a/main.h b/main.h
new file mode 100644 (file)
index 0000000..c509d15
--- /dev/null
+++ b/main.h
@@ -0,0 +1,24 @@
+#ifndef _MAIN_H_
+#define _MAIN_H_
+
+//
+//
+//
+#define __VERSION "1.20"
+
+//
+//
+//
+typedef enum
+{
+  TASKHANDLE_GPS = 0,
+  TASKHANDLE_SENSORS,
+  TASKHANDLE_MONITOR,
+  TASKHANDLE_LED,
+  TASKHANDLE_LAST
+}
+taskHandle_e;
+
+extern xTaskHandle taskHandles [TASKHANDLE_LAST];
+
+#endif
diff --git a/monitor/Makefile b/monitor/Makefile
new file mode 100644 (file)
index 0000000..e843bc1
--- /dev/null
@@ -0,0 +1,25 @@
+SRC_FILES=args.c monitor.c
+
+#
+# Define all object files.
+#
+ARM_OBJ = $(SRC_FILES:.c=.o)
+
+.PHONY: all
+all: $(ARM_OBJ)
+
+$(ARM_OBJ) : %.o : %.c Makefile .depend
+       $(CC) -c $(CFLAGS) $< -o $@
+       $(AR) r $(COMMON)/common.a $@
+
+#
+#  The .depend files contains the list of header files that the
+#  various source files depend on.  By doing this, we'll only
+#  rebuild the .o's that are affected by header files changing.
+#
+.depend:
+                       $(CC) $(CFLAGS) -M $(SRC_FILES) > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff --git a/monitor/args.c b/monitor/args.c
new file mode 100644 (file)
index 0000000..29669d6
--- /dev/null
@@ -0,0 +1,167 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+
+//
+// Scheduler includes
+//
+#include "FreeRTOS.h"
+#include "args.h"
+
+//
+//
+//
+static char *strtrim (char *s)
+{
+  char *t = s + strlen (s) - 1;
+
+  while (t >= s && *t && isspace (*t))
+    *t-- = '\0';
+
+  while (*s && isspace (*s))
+    s++;
+
+  return s;
+}
+
+//
+//  bufferLength includes the space reserved for the \0
+//
+int argsGetLine (int fd __attribute__ ((unused)), U8 *buffer, int bufferLength)
+{
+  U8 *p;
+
+  p = buffer;
+  *p = '\0';
+
+  while (1)
+  {
+    U8 c;
+    
+    fflush (stdout);
+
+    if (read (fd, &c, sizeof (c)) == sizeof (c))
+    {
+      switch (c)
+      {
+        case '\n' :
+        case '\r' :
+          printf ("\n");
+          return strlen ((char *) buffer);
+
+        case '\b' :
+          if (p > buffer)
+            *--p = '\0';
+          printf ("\b \b");
+          break;
+
+        case 0x15 : // CTRL-U
+          while (p != buffer)
+          {
+            printf ("\b \b");
+            --p;
+          }
+          *p = '\0';
+          break;
+
+        case 0xfe :
+        case 0xff :
+          *buffer++ = c;
+          *buffer = '\0';
+          return 1;
+
+        default : 
+          if (p < buffer + bufferLength - 1 && c >= ' ' && c < 0x7f)
+          { 
+            *p++ = c;
+            *p = '\0';
+            printf ("%c", c); 
+          }
+          else
+            printf ("%c", c); 
+
+          break;
+      }
+    }
+  }
+
+  return 0;
+}
+
+//
+//
+//
+typedef enum
+{
+  P_EATWHITESPACE = 0,
+  P_GETCHARFIRST,
+  P_GETCHAR,
+  P_QUOTEDGETCHAR
+}
+PSTATE;
+
+int argsParse (char *cmd, char **argv, int sizeofArgv, int *argc)
+{
+  int maxArgs = (sizeofArgv / sizeof (argv [0])) - 1;
+  char *s = strtrim (cmd);
+  PSTATE pstate = P_EATWHITESPACE;
+
+  *argc = 0;
+  memset (argv, 0, sizeofArgv);
+
+  while (*s)
+  {
+    switch (pstate)
+    {
+      case P_EATWHITESPACE :
+        {
+          if (!isspace (*s))
+            pstate = P_GETCHARFIRST;
+          else
+            s++;
+        }
+        break;
+
+      case P_GETCHARFIRST :
+        {
+          *argv++ = s;
+
+          if (++*argc == maxArgs)
+            return 1;
+          if (*s == '"')
+            pstate = P_QUOTEDGETCHAR;
+          else
+            pstate = P_GETCHAR;
+
+          s++;
+        }
+        break;
+
+      case P_GETCHAR :
+        {
+          if (isspace (*s)) {
+            pstate = P_EATWHITESPACE;
+            *s = '\0';
+          } 
+          else if (*s == '"')
+            pstate = P_QUOTEDGETCHAR;
+
+          s++;
+        }
+        break;
+
+      case P_QUOTEDGETCHAR :
+        {
+          if (*s == '"')
+            pstate = P_GETCHAR;
+
+          s++;
+        }
+        break;
+    }
+  }
+
+  return 0;
+}
diff --git a/monitor/args.h b/monitor/args.h
new file mode 100644 (file)
index 0000000..3767fc8
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef _ARGS_H_
+#define _ARGS_H_
+
+int argsGetLine (int fd, U8 *buffer, int bufferLength);
+int argsParse (char *cmd, char **argv, int sizeofArgv, int *argc);
+
+#endif
diff --git a/monitor/monitor.c b/monitor/monitor.c
new file mode 100644 (file)
index 0000000..ba5292b
--- /dev/null
@@ -0,0 +1,2426 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <time.h>
+#include <errno.h>
+#include <malloc.h>
+#include <sys/time.h>
+#include <sys/times.h>
+
+#include "FreeRTOS.h"
+#include "task.h"
+
+#include "args.h"
+#include "../fatfs/diskio.h"
+#include "../fatfs/ff.h"
+#include "../fiq/fiq.h"
+#include "../gps/gps.h"
+#include "../i2c/eeprom.h"
+#include "../i2c/i2c.h"
+#include "../i2c/lm75.h"
+#include "../iap/iap.h"
+#include "../main.h"
+#include "../rtc/rtc.h"
+#include "../sensors/sensors.h"
+#include "../swi/swi.h"
+#include "monitor.h"
+
+//
+//
+//
+typedef enum
+{
+  CMDTYPE_CMDLIST = 0,
+  CMDTYPE_FUNCTION
+}
+cmdType_e;
+
+typedef struct abortDat_s
+{
+  unsigned int dummy;
+  unsigned int sigil;
+  unsigned int count;
+  unsigned int type;
+  unsigned int pc;
+  unsigned int opcode;
+  unsigned int cpsr;
+  unsigned int lr;
+  unsigned int sp;
+  unsigned int r0;
+  unsigned int r1;
+  unsigned int r2;
+  unsigned int r3;
+  unsigned int r4;
+  unsigned int r5;
+  unsigned int r6;
+  unsigned int r7;
+  unsigned int r8;
+  unsigned int r9;
+  unsigned int r10;
+  unsigned int r11;
+  unsigned int r12;
+  unsigned int stack [8];
+}
+__attribute__ ((packed)) abortDat_t;
+
+typedef struct commandList_s
+{
+  const portCHAR *command;
+  portCHAR minArgs;
+  portCHAR maxArgs;
+  cmdType_e cmdType;
+  union
+  {
+    void *trickGCC;
+    int (*handler) (int argc, portCHAR **argv);
+    struct commandList_s *commandList;
+  };
+  const portCHAR *description;
+  const portCHAR *parameters;
+}
+commandList_t;
+
+//
+//  Prototypes
+//
+static int monitorHelp (int argc, portCHAR **argv);
+static int monitorDiskInit (int argc, portCHAR **argv);
+static int monitorDiskMount (int argc, portCHAR **argv);
+static int monitorFileMkfs (int argc, portCHAR **argv);
+static int monitorFileDf (int argc, portCHAR **argv);
+static int monitorFileLs (int argc, portCHAR **argv);
+static int monitorFileMkdir (int argc, portCHAR **argv);
+static int monitorFileRmdir (int argc, portCHAR **argv);
+static int monitorFileRm (int argc, portCHAR **argv);
+static int monitorFileMv (int argc, portCHAR **argv);
+static int monitorFileCp (int argc, portCHAR **argv);
+static int monitorFileCpCon (int argc, portCHAR **argv);
+static int monitorFileChmod (int argc, portCHAR **argv);
+static int monitorFileSync (int argc, portCHAR **argv);
+static int monitorFileThruPut (int argc, portCHAR **argv);
+static int monitorGPS (int argc, portCHAR **argv);
+static int monitorSensors (int argc, portCHAR **argv);
+static int monitorMd (int argc, portCHAR **argv);
+static int monitorAbortRegs (int argc, portCHAR **argv);
+static int monitorAbortClear (int argc, portCHAR **argv);
+static int monitorAbortDirty (int argc, portCHAR **argv);
+static int monitorAbortUndef (int argc, portCHAR **argv);
+static int monitorAbortPabort (int argc, portCHAR **argv);
+static int monitorAbortDabort (int argc, portCHAR **argv);
+static int monitorEEAddr (int argc, portCHAR **argv);
+static int monitorEERead (int argc, portCHAR **argv);
+static int monitorEEReadAddr (int argc, portCHAR **argv);
+static int monitorEEWrite (int argc, portCHAR **argv);
+static int monitorEEWriteAddr (int argc, portCHAR **argv);
+static int monitorEEFillAddr (int argc, portCHAR **argv);
+static int monitorFIQOn (int argc, portCHAR **argv);
+static int monitorFIQOff (int argc, portCHAR **argv);
+static int monitorFIQCount (int argc, portCHAR **argv);
+static int monitorFIQClear (int argc, portCHAR **argv);
+static int monitorI2CRead (int argc, portCHAR **argv);
+static int monitorI2CWrite (int argc, portCHAR **argv);
+static int monitorI2CWriteRead (int argc, portCHAR **argv);
+static int monitorI2CDump (int argc, portCHAR **argv);
+static int monitorI2CErrno (int argc, portCHAR **argv);
+static int monitorIAPFSS (int argc, portCHAR **argv);
+static int monitorIAPSTOA (int argc, portCHAR **argv);
+static int monitorIAPFill (int argc, portCHAR **argv);
+static int monitorIAPErase (int argc, portCHAR **argv);
+static int monitorIAPBlank (int argc, portCHAR **argv);
+static int monitorIAPID (int argc, portCHAR **argv);
+static int monitorIAPVer(int argc, portCHAR **argv);
+static int monitorIAPISP (int argc, portCHAR **argv);
+static int monitorLM75Init (int argc, portCHAR **argv);
+static int monitorLM75Mode (int argc, portCHAR **argv);
+static int monitorLM75Addr (int argc, portCHAR **argv);
+static int monitorLM75ReRead (int argc, portCHAR **argv);
+static int monitorLM75Temp (int argc, portCHAR **argv);
+static int monitorLM75Config (int argc, portCHAR **argv);
+static int monitorLM75Thyst (int argc, portCHAR **argv);
+static int monitorLM75Tos (int argc, portCHAR **argv);
+static int monitorMemTask (int argc, portCHAR **argv);
+static int monitorMemMap (int argc, portCHAR **argv);
+static int monitorMemAlloc (int argc, portCHAR **argv);
+static int monitorMemRealloc (int argc, portCHAR **argv);
+static int monitorMemFree (int argc, portCHAR **argv);
+static int monitorMemList (int argc, portCHAR **argv);
+static int monitorMiscSizeof (int argc, portCHAR **argv);
+static int monitorRTCGet (int argc, portCHAR **argv);
+static int monitorRTCSet (int argc, portCHAR **argv);
+static int monitorRTCAlarm (int argc, portCHAR **argv);
+static int monitorRTCPeriodic (int argc, portCHAR **argv);
+static int monitorSWISetAsm (int argc, portCHAR **argv);
+static int monitorSWIOnAsm (int argc, portCHAR **argv);
+static int monitorSWIOffAsm (int argc, portCHAR **argv);
+static int monitorSWIToggleAsm (int argc, portCHAR **argv);
+static int monitorSWISetC (int argc, portCHAR **argv);
+static int monitorSWIOnC (int argc, portCHAR **argv);
+static int monitorSWIOffC (int argc, portCHAR **argv);
+static int monitorSWIToggleC (int argc, portCHAR **argv);
+static int monitorWDTTest (int argc, portCHAR **argv);
+static int monitorWDTStatus (int argc, portCHAR **argv);
+static int monitorWDTClear (int argc, portCHAR **argv);
+static int monitorVersion (int argc, portCHAR **argv);
+
+//
+//  Ye olde globals
+//
+static commandList_t commandListAbort [] =
+{
+  { "help",     0,  0, CMDTYPE_FUNCTION,  { monitorHelp        }, "This help list",               "'help' has no parameters" },
+  { "regs",     0,  0, CMDTYPE_FUNCTION,  { monitorAbortRegs   }, "Print abort registers",        "'regs' has no parameters" },
+  { "clear",    0,  0, CMDTYPE_FUNCTION,  { monitorAbortClear  }, "Clear abort registers",        "'clear' has no parameters" },
+  { "dirty",    0,  0, CMDTYPE_FUNCTION,  { monitorAbortDirty  }, "Dirty sigil flag",             "'dirty' has no parameters" },
+  { "undef",    0,  0, CMDTYPE_FUNCTION,  { monitorAbortUndef  }, "Execute undefined instruction","'undef' has no parameters" },
+  { "pabort",   0,  0, CMDTYPE_FUNCTION,  { monitorAbortPabort }, "Cause prefetch abort",         "'pabort' has no parameters" },
+  { "dabort",   0,  0, CMDTYPE_FUNCTION,  { monitorAbortDabort }, "Cause data abort",             "'dabort' has no parameters" },
+  { NULL,       0,  0, CMDTYPE_FUNCTION,  { NULL               }, NULL,                           NULL },
+};
+
+static commandList_t commandListEE [] =
+{
+  { "help",     0,  0, CMDTYPE_FUNCTION,  { monitorHelp        }, "This help list",               "'help' has no parameters" },
+  { "a",        1,  1, CMDTYPE_FUNCTION,  { monitorEEAddr      }, "Set eeprom r/w address",       "'ee <address>'" },
+  { "r",        0,  1, CMDTYPE_FUNCTION,  { monitorEERead      }, "Read from current address",    "'r <# bytes>'" },
+  { "ra",       1,  2, CMDTYPE_FUNCTION,  { monitorEEReadAddr  }, "Read EEPROM",                  "'ra <address> <# bytes>'" },
+  { "w",        1, 16, CMDTYPE_FUNCTION,  { monitorEEWrite     }, "Write to current address",     "'w <byte> [<byte> [...<byte>]]'" },
+  { "wa",       2, 17, CMDTYPE_FUNCTION,  { monitorEEWriteAddr }, "Write EEPOM",                  "'wa <address> <byte> [<byte> [...<byte>]]'" },
+  { "fa",       3,  3, CMDTYPE_FUNCTION,  { monitorEEFillAddr  }, "Fill EEPOM",                   "'fa <address> <len> <byte>'" },
+  { NULL,       0,  0, CMDTYPE_FUNCTION,  { NULL               }, NULL,                           NULL },
+};
+
+static commandList_t commandListFIQ [] =
+{
+  { "help",     0,  0, CMDTYPE_FUNCTION,  { monitorHelp        }, "This help list",                 "'help' has no parameters" },
+  { "on",       0,  0, CMDTYPE_FUNCTION,  { monitorFIQOn       }, "Enable FIQ interrupt",           "'on' has no parameters" },
+  { "off",      0,  0, CMDTYPE_FUNCTION,  { monitorFIQOff      }, "Disable FIQ interrupt",          "'off' has no parameters" },
+  { "count",    0,  0, CMDTYPE_FUNCTION,  { monitorFIQCount    }, "Show number of FIQ interrupts",  "'show' has no parameters" },
+  { "clear",    0,  0, CMDTYPE_FUNCTION,  { monitorFIQClear    }, "Clear FIQ interrupt counter",    "'clear' has no parameters" },
+  { NULL,       0,  0, CMDTYPE_FUNCTION,  { NULL               }, NULL,                             NULL },
+};
+
+static commandList_t commandListI2C [] =
+{
+  { "help",     0,  0, CMDTYPE_FUNCTION,  { monitorHelp        }, "This help list",                     "'help' has no parameters" },
+  { "r",        2,  2, CMDTYPE_FUNCTION,  { monitorI2CRead     }, "Read from I2C device",               "'r <address> <# bytes>'" },
+  { "w",        2, 17, CMDTYPE_FUNCTION,  { monitorI2CWrite    }, "Write to I2C device",                "'w <address> <byte> [<byte> [...<byte>]]'" },
+  { "wr",       2, 18, CMDTYPE_FUNCTION,  { monitorI2CWriteRead}, "Write to then read from I2C device", "'wr <address> <byte> [<byte> [...<byte>]] <# bytes to read>'" },
+  { "dump",     0,  0, CMDTYPE_FUNCTION,  { monitorI2CDump     }, "Dump I2C Debug Buffer",              "'dump' has no parameters" },
+  { "errno",    0,  0, CMDTYPE_FUNCTION,  { monitorI2CErrno    }, "Display i2cErrno value",             "'errno' has no parameters" },
+  { NULL,       0,  0, CMDTYPE_FUNCTION,  { NULL               }, NULL,                                 NULL },
+};
+
+static commandList_t commandListIAP [] =
+{
+  { "help",     0,  0, CMDTYPE_FUNCTION,  { monitorHelp        }, "This help list",                     "'help' has no parameters" },
+  { "fss",      0,  0, CMDTYPE_FUNCTION,  { monitorIAPFSS      }, "Find safe sector",                   "'fss' has no parameters" },
+  { "stoa",     1,  1, CMDTYPE_FUNCTION,  { monitorIAPSTOA     }, "Convert sector to address for 'md'", "'fss' has no parameters" },
+  { "fill",     2,  2, CMDTYPE_FUNCTION,  { monitorIAPFill     }, "Fill sector with byte",              "'fill <sector> <byte>'" },
+  { "erase",    1,  1, CMDTYPE_FUNCTION,  { monitorIAPErase    }, "Erase sector",                       "'erase <sector>'" },
+  { "blank",    1,  1, CMDTYPE_FUNCTION,  { monitorIAPBlank    }, "Blank check sector",                 "'blank <sector>'" },
+  { "id",       0,  0, CMDTYPE_FUNCTION,  { monitorIAPID       }, "Read part ID",                       "'id' has no parameters" },
+  { "ver",      0,  0, CMDTYPE_FUNCTION,  { monitorIAPVer      }, "Read boot loader version",           "'ver' has no parameters" },
+  { "isp",      0,  0, CMDTYPE_FUNCTION,  { monitorIAPISP      }, "Restart into ISP bootloader",        "'isp' has no parameters" },
+  { NULL,       0,  0, CMDTYPE_FUNCTION,  { NULL               }, NULL,                                 NULL },
+};
+
+static commandList_t commandListLM75 [] =
+{
+  { "help",     0,  0, CMDTYPE_FUNCTION,  { monitorHelp        }, "This help list",               "'help' has no parameters" },
+  { "init",     0,  0, CMDTYPE_FUNCTION,  { monitorLM75Init    }, "Initialize LM75",              "'init' has no parameters" },
+  { "mode",     1,  1, CMDTYPE_FUNCTION,  { monitorLM75Mode    }, "Set LM75 mode",                "'mode <value>'" },
+  { "addr",     1,  1, CMDTYPE_FUNCTION,  { monitorLM75Addr    }, "Set LM75 address",             "'addr <value>'" },
+  { "reread",   0,  0, CMDTYPE_FUNCTION,  { monitorLM75ReRead  }, "Re-read last register",        "'reread' has no parameters" },
+  { "temp",     0,  0, CMDTYPE_FUNCTION,  { monitorLM75Temp    }, "Read LM75 temperature",        "'temp' has no parameters" },
+  { "config",   0,  1, CMDTYPE_FUNCTION,  { monitorLM75Config  }, "Read part ID",                 "'id' has no parameters" },
+  { "thyst",    0,  1, CMDTYPE_FUNCTION,  { monitorLM75Thyst   }, "Read or set THYST register",   "'thyst [value]'" },
+  { "tos",      0,  1, CMDTYPE_FUNCTION,  { monitorLM75Tos     }, "Read or set TOS register",     "'tos [value]'" },
+  { NULL,       0,  0, CMDTYPE_FUNCTION,  { NULL               }, NULL,                           NULL },
+};
+
+static commandList_t commandListMem [] =
+{
+  { "help",     0,  0, CMDTYPE_FUNCTION,  { monitorHelp        }, "This help list",               "'help' has no parameters" },
+  { "task",     0,  0, CMDTYPE_FUNCTION,  { monitorMemTask     }, "Show FreeRTOS task memory",    "'task' has no parameters" },
+  { "map",      0,  0, CMDTYPE_FUNCTION,  { monitorMemMap      }, "Show various addresses",       "'map' has no parameters" },
+  { "alloc",    2,  2, CMDTYPE_FUNCTION,  { monitorMemAlloc    }, "Allocate memory",              "'alloc <slot> <size>'" },
+  { "realloc",  2,  2, CMDTYPE_FUNCTION,  { monitorMemRealloc  }, "Reallocate memory",            "'realloc <slot> <size>'" },
+  { "free",     1,  1, CMDTYPE_FUNCTION,  { monitorMemFree     }, "Free memory",                  "'free <slot>'" },
+  { "list",     0,  0, CMDTYPE_FUNCTION,  { monitorMemList     }, "List memory",                  "'list' has no parameters" },
+  { NULL,       0,  0, CMDTYPE_FUNCTION,  { NULL               }, NULL,                           NULL },
+};
+
+static commandList_t commandListMisc [] =
+{
+  { "help",     0,  0, CMDTYPE_FUNCTION,  { monitorHelp        }, "This help list",               "'help' has no parameters" },
+  { "sizeof",   0,  0, CMDTYPE_FUNCTION,  { monitorMiscSizeof  }, "Sizeof() variable data types", "'sizeof' has no parameters" },
+  { NULL,       0,  0, CMDTYPE_FUNCTION,  { NULL               }, NULL,                           NULL },
+};
+
+static commandList_t commandListRTC [] =
+{
+  { "help",     0,  0, CMDTYPE_FUNCTION,  { monitorHelp        }, "This help list",               "'help' has no parameters" },
+  { "get",      0,  0, CMDTYPE_FUNCTION,  { monitorRTCGet      }, "Display system date/time",     "'get' has no parameters" },
+  { "set",      1,  2, CMDTYPE_FUNCTION,  { monitorRTCSet      }, "Set system date/time",         "'set <gps|YYYY/MM/DD HH:MM:SS>'" },
+  { "alarm",    0,  2, CMDTYPE_FUNCTION,  { monitorRTCAlarm    }, "Set date/time for alarm",      "'alarm <off|YYYY/MM/DD HH:MM:SS>'" },
+  { "periodic", 0,  1, CMDTYPE_FUNCTION,  { monitorRTCPeriodic }, "Alarm every minute change",    "'periodic <on|off>'" },
+  { NULL,       0,  0, CMDTYPE_FUNCTION,  { NULL               }, NULL,                           NULL },
+};
+
+static commandList_t commandListSWI [] =
+{
+  { "help",     0,  0, CMDTYPE_FUNCTION,  { monitorHelp        }, "This help list",               "'help' has no parameters" },
+  { "aset",     1,  1, CMDTYPE_FUNCTION,  { monitorSWISetAsm   }, "Set LED2 state (asm)",         "'aset <on|of>'" },
+  { "aon",      0,  0, CMDTYPE_FUNCTION,  { monitorSWIOnAsm    }, "Turn LED2 on (asm)",           "'aon' has no parameters" },
+  { "aoff",     0,  0, CMDTYPE_FUNCTION,  { monitorSWIOffAsm   }, "Turn LED2 off (asm)",          "'aoff' has no parameters" },
+  { "atoggle",  0,  0, CMDTYPE_FUNCTION,  { monitorSWIToggleAsm}, "Toggle LED2 state (asm)",      "'atoggle' has no parameters" },
+  { "cset",     1,  1, CMDTYPE_FUNCTION,  { monitorSWISetC     }, "Set LED2 state (C)",           "'cset <on|off>'" },
+  { "con",      0,  0, CMDTYPE_FUNCTION,  { monitorSWIOnC      }, "Turn LED2 on (C)",             "'con' has no parameters" },
+  { "coff",     0,  0, CMDTYPE_FUNCTION,  { monitorSWIOffC     }, "Turn LED2 off (C)",            "'coff' has no parameters" },
+  { "ctoggle",  0,  0, CMDTYPE_FUNCTION,  { monitorSWIToggleC  }, "Toggle LED2 state (C)",        "'ctoggle' has no parameters" },
+  { NULL,       0,  0, CMDTYPE_FUNCTION,  { NULL               }, NULL,                           NULL },
+};
+
+static commandList_t commandListWDT [] =
+{
+  { "help",     0,  0, CMDTYPE_FUNCTION,  { monitorHelp        }, "This help list",               "'help' has no parameters" },
+  { "test",     0,  0, CMDTYPE_FUNCTION,  { monitorWDTTest     }, "Test watchdog",                "'test' has no parameters" },
+  { "status",   0,  0, CMDTYPE_FUNCTION,  { monitorWDTStatus   }, "Display RSIR register",        "'status' has no parameters" },
+  { "clear",    0,  0, CMDTYPE_FUNCTION,  { monitorWDTClear    }, "Clear RSIR status",            "'rsir' has no parameters" },
+  { NULL,       0,  0, CMDTYPE_FUNCTION,  { NULL               }, NULL,                           NULL },
+};
+
+static commandList_t commandList [] =
+{
+  { "help",     0,  0, CMDTYPE_FUNCTION,  { monitorHelp        }, "This help list",               "'help' has no parameters" },
+  { "init",     0,  0, CMDTYPE_FUNCTION,  { monitorDiskInit    }, "Initialize disk subsystem",    "'init' has no parameters" },
+  { "mount",    0,  0, CMDTYPE_FUNCTION,  { monitorDiskMount   }, "Mount disk",                   "'mount' has no parameters" },
+  { "mkfs",     0,  0, CMDTYPE_FUNCTION,  { monitorFileMkfs    }, "Create a FAT filesystem",      "'mkfs' has no parameters" },
+  { "df",       0,  0, CMDTYPE_FUNCTION,  { monitorFileDf      }, "File system status & info",    "'fd' has no parameters" },
+  { "ls",       0,  1, CMDTYPE_FUNCTION,  { monitorFileLs      }, "Display directory",            "'ls [optional path]'" },
+  { "mkdir",    1,  1, CMDTYPE_FUNCTION,  { monitorFileMkdir   }, "Create directory",             "'mkdir <[path]directory'" },
+  { "rmdir",    1,  1, CMDTYPE_FUNCTION,  { monitorFileRmdir   }, "Delete directory",             "'rmdir <[path]directory>'" },
+  { "rm",       1,  1, CMDTYPE_FUNCTION,  { monitorFileRm      }, "Delete file",                  "'rm <[path]filename>'" },
+  { "mv",       2,  2, CMDTYPE_FUNCTION,  { monitorFileMv      }, "Rename a file or directory",   "'mv <[path]old_filename> <[path]new_filename>'" },
+  { "cp",       1,  2, CMDTYPE_FUNCTION,  { monitorFileCp      }, "Copy a file",                  "'mv <[path]old_filename> <[path]new_filename>'" },
+  { "cpcon",    1,  1, CMDTYPE_FUNCTION,  { monitorFileCpCon   }, "Copy console input to file",   "'cp <[path]filename>' (ctrl-d exits and saves)" },
+  { "chmod",    2,  2, CMDTYPE_FUNCTION,  { monitorFileChmod   }, "Change file mode",             "'chmod <+w|-w> <[path]filename>'" },
+  { "sync",     0,  0, CMDTYPE_FUNCTION,  { monitorFileSync    }, "Sync filesystem",              "'sync' has no parameters" },
+  { "thruput",  1,  1, CMDTYPE_FUNCTION,  { monitorFileThruPut }, "Measure MMC/SD throughput",    "'thruput <normal|noints|high|suspendall>'" },
+  { "gps",      0,  0, CMDTYPE_FUNCTION,  { monitorGPS         }, "Display GPS data",             "'gps' has no parameters" },
+  { "sensors",  0,  0, CMDTYPE_FUNCTION,  { monitorSensors     }, "Display sensor data",          "'sensors' has no parameters" },
+  { "md",       0,  2, CMDTYPE_FUNCTION,  { monitorMd          }, "Display memory",               "'md [address [length]]'" },
+
+  { "abort",    1,  0, CMDTYPE_CMDLIST,   { commandListAbort   }, "Read/clear abort registers",   "'abort help' for help list" },
+  { "ee",       1,  0, CMDTYPE_CMDLIST,   { commandListEE      }, "Read/write I2C EEPROM",        "'ee help' for help list" },
+  { "fiq",      1,  0, CMDTYPE_CMDLIST,   { commandListFIQ     }, "Demonstrate FIQ functions",    "'fiq help' for help list" },
+  { "i2c",      1,  0, CMDTYPE_CMDLIST,   { commandListI2C     }, "Perform I2C commands",         "'i2c help' for help list" },
+  { "iap",      1,  0, CMDTYPE_CMDLIST,   { commandListIAP     }, "Perform IAP commands",         "'iap help' for help list" },
+  { "lm75",     1,  0, CMDTYPE_CMDLIST,   { commandListLM75    }, "Read/set LM75 temp sensor",    "'lm75 help' for help list" },
+  { "mem",      1,  0, CMDTYPE_CMDLIST,   { commandListMem     }, "Various memory functions",     "'mem help' for help list" },
+  { "misc",     1,  0, CMDTYPE_CMDLIST,   { commandListMisc    }, "Miscellaneous stuff",          "'misc help' for help list" },
+  { "rtc",      1,  0, CMDTYPE_CMDLIST,   { commandListRTC     }, "Demonstrate RTC functions",    "'rtc help' for help list" },
+  { "swi",      1,  0, CMDTYPE_CMDLIST,   { commandListSWI     }, "Demonstrate SWI functions",    "'swi help' for help list" },
+  { "wdt",      1,  0, CMDTYPE_CMDLIST,   { commandListWDT     }, "Manipulate watchdog timer",    "'wdt help' for help list" },
+  { "version",  0,  0, CMDTYPE_FUNCTION,  { monitorVersion     }, "Display version information",  "'version' has no parameters" },
+  { NULL,       0,  0, CMDTYPE_FUNCTION,  { NULL               }, NULL,                           NULL },
+};
+
+static FATFS fatfs;
+static FILINFO fileInfo;
+commandList_t *activeCommandList = NULL;
+
+//
+//  External variables
+//
+extern unsigned int __abort_dat;
+extern unsigned long __start_of_text__;
+extern unsigned long __end_of_text__;
+extern unsigned long __start_of_startup__;
+extern unsigned long __end_of_startup__;
+extern unsigned long __start_of_prog__;
+extern unsigned long __end_of_prog__;
+extern unsigned long __start_of_rodata__;
+extern unsigned long __end_of_rodata__;
+extern unsigned long __start_of_glue7__;
+extern unsigned long __end_of_glue7__;
+extern unsigned long __data_beg__;
+extern unsigned long __data_end__;
+extern unsigned long __bss_beg__;
+extern unsigned long __bss_end__;
+extern unsigned long __heap_max;
+extern unsigned long __heap_beg;
+extern unsigned long __heap_end;
+extern unsigned long __stack_end__;
+extern unsigned long __stack_beg_und;
+extern unsigned long __stack_end_und;
+extern unsigned long __stack_beg_abt;
+extern unsigned long __stack_end_abt;
+extern unsigned long __stack_beg_fiq;
+extern unsigned long __stack_end_fiq;
+extern unsigned long __stack_beg_irq;
+extern unsigned long __stack_end_irq;
+extern unsigned long __stack_beg_svc;
+extern unsigned long __stack_end_svc;
+extern unsigned long __stack_beg_sys;
+extern unsigned long __stack_end_sys;
+
+
+//
+//  Recursion is our friend...  fileInfo is global to avoid eating stack space
+//
+static FRESULT scan_files_ex (char *path, int *total_size, int *total_files, int *total_dirs)
+{
+  DIR dirs;
+  FRESULT res;
+
+  if ((res = f_opendir (&dirs, path)) == FR_OK) 
+  {
+    int i = strlen (path);
+
+    while (((res = f_readdir (&dirs, &fileInfo)) == FR_OK) && fileInfo.fname [0]) 
+    {
+      if (fileInfo.fattrib & AM_DIR) 
+      {
+        *total_dirs += 1;
+        *(path + i) = '/'; 
+        strcpy (path + i + 1, &fileInfo.fname [0]);
+        res = scan_files_ex (path, total_size, total_files, total_dirs);
+        *(path + i) = '\0';
+
+        if (res != FR_OK) 
+          return res;
+      } 
+      else 
+      {
+        *total_files += 1;
+        *total_size += fileInfo.fsize;
+      }
+    }
+  }
+
+  return res;
+}
+
+static FRESULT scan_files (char *path, int *total_size, int *total_files, int *total_dirs)
+{
+  *total_size = 0;
+  *total_files = 0;
+  *total_dirs = 0;
+
+  return scan_files_ex (path, total_size, total_files, total_dirs);
+}
+
+//
+//  These two really ought to be in the FatFS code
+//
+U32 get_fattime ()
+{
+  U32 tmr;
+  time_t now;
+  struct tm tm;
+
+  now = time (NULL);
+  localtime_r (&now, &tm);
+
+  tmr = 0
+    | ((tm.tm_year - 80) << 25)
+    | ((tm.tm_mon + 1)   << 21)
+    | (tm.tm_mday        << 16)
+    | (tm.tm_hour        << 11)
+    | (tm.tm_min         << 5)
+    | (tm.tm_sec         >> 1);
+
+  return tmr;
+}
+
+//
+//  Functions newlib doesn't know about (but should)
+//
+void _sync  (void);
+int  _mkdir (const char *path, mode_t mode);
+int  _chmod (const char *path, mode_t mode);
+
+void sync  (void);
+int  chmod (const char *path, mode_t mode);
+
+void sync (void)
+{
+  _sync ();
+}
+
+int mkdir (const char *path, mode_t mode)
+{
+  return _mkdir (path, mode);
+}
+
+int chmod (const char *path, mode_t mode)
+{
+  return _chmod (path, mode);
+}
+
+//
+//
+//
+static int getNumber (char *s, unsigned int *result)
+{
+  unsigned int value;
+  unsigned int mustBeHex = FALSE;
+  int sgn = 1;
+  const unsigned char hexToDec [] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255, 255, 10, 11, 12, 13, 14, 15};
+
+  if (!s)
+    return 0;
+
+  if ((strlen (s) > 2) && (!strncmp (s, "0x", 2) || !strncmp (s, "0X", 2)))
+  {
+    mustBeHex = TRUE;
+    s += 2;
+  }
+
+  if (!mustBeHex && *s && (*s == '-'))
+  {
+    sgn = -1;
+    s++;
+  }
+
+  for (value = 0; *s; s++)
+  {
+    if (mustBeHex && isxdigit (*s))
+      value = (value << 4) | hexToDec [toupper (*s) - '0'];
+    else if (isdigit (*s))
+      value = (value * 10) + (*s - '0');
+    else
+    {
+      printf ("Malformed number.  Must be decimal number, or hex value preceeded by '0x'\n");
+      return 0;
+    }
+  }
+
+  if (!mustBeHex)
+    value *= sgn;
+
+  *result = value;
+
+  return 1;
+}
+
+static int monitorDumpMemory (unsigned int displayAddress, unsigned int address, int length)
+{
+  unsigned char *buffer;
+  int i;
+
+  if (!length)
+  {
+    printf ("Error: monitorDumpMemory() passed 0 for length\n");
+    return address;
+  }
+
+  for (buffer = (unsigned char *) address, i = 0; i < length; i += 16)
+  {
+    unsigned int l;
+    unsigned int j;
+
+    if (i)
+      printf ("\n");
+
+    printf ("%08x: ", displayAddress + i);
+
+    if ((length - i) < 16)
+      l = length & 15;
+    else
+      l = 16;
+
+    for (j = 0; j < 16; j++)
+    {
+      if (j < l)
+        printf ("%02x ", buffer [i+j]);
+      else
+        printf ("   ");
+    }
+
+    printf ("  ");
+
+    for (j = 0; j < l; j++)
+    {
+      unsigned char c = buffer [i+j];
+
+      if (c < 32 || c > 127)
+        c = '.';
+
+      printf ("%c", c);
+    }
+  }
+
+  printf ("\n");
+
+  address += length;
+
+  return address;
+}
+
+//
+//
+//
+static int monitorHelp (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+  unsigned int i;
+  int t;
+  int longestCmd;
+  portCHAR spaces [32];
+
+  memset (spaces, ' ', sizeof (spaces));
+
+  for (longestCmd = 0, i = 0; activeCommandList [i].command; i++)
+    if ((t = strlen (activeCommandList [i].command)) > longestCmd)
+      longestCmd = t;
+
+  spaces [longestCmd] = '\0';
+
+  for (i = 0; activeCommandList [i].command; i++)
+  {
+    const commandList_t *cl = &activeCommandList [i];
+
+    printf ("%s%s -- %s\n", cl->command, &spaces [strlen (cl->command)], cl->description);
+  }
+
+  printf ("\nUse '<command> ?' for details on parameters to command\n");
+
+  return 0;
+}
+
+//
+//
+//
+static int monitorDiskInit (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+  printf ("RRC=%d\n", diskInitialize (0));
+
+  return 0;
+}
+
+static int monitorDiskMount (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+  f_printerror (f_mount (0, &fatfs));
+
+  return 0;
+}
+
+static int monitorFileMkfs (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+  f_printerror (f_mkfs (0, 0, 64));
+
+  return 0;
+}
+
+static int monitorFileDf (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+  U32 p2;
+  FATFS *fs;
+  char buffer [100];
+  FRESULT res;
+  int acc_size;
+  int acc_files;
+  int acc_dirs;
+
+  if ((res = f_getfree ("", (U32 *) &p2, &fs)))
+  { 
+    f_printerror (res); 
+    return 0;
+  }
+
+  printf ("FAT type = %u\nBytes/Cluster = %u\nNumber of FATs = %u\n"
+      "Root DIR entries = %u\nSectors/FAT = %u\nNumber of clusters = %u\n"
+      "FAT start (lba) = %u\nDIR start (lba,clustor) = %u\nData start (lba) = %u\n",
+      fs->fs_type, fs->sects_clust * 512, fs->n_fats,
+      fs->n_rootdir, fs->sects_fat, fs->max_clust - 2,
+      fs->fatbase, fs->dirbase, fs->database
+      );
+
+  acc_size = acc_files = acc_dirs = 0;
+
+  buffer [0] = '\0';
+
+  if ((res = scan_files (buffer, &acc_size, &acc_files, &acc_dirs)))
+  { 
+    f_printerror (res); 
+    return 0;
+  }
+
+  printf ("\n%u files, %u bytes.\n%u folders.\n"
+      "%u bytes total disk space.\n%u bytes available\n",
+      acc_files, acc_size, acc_dirs,
+      (fs->max_clust - 2) * fs->sects_clust * 512, p2 * fs->sects_clust * 512
+      );
+
+  return 0;
+}
+
+static int monitorFileLs (int argc, portCHAR **argv)
+{
+  DIR dir;
+  FRESULT res;
+  U32 size;
+  U16 files;
+  U16 dirs;
+  FATFS *fs;
+  char *path;
+
+  path = argc ? argv [0] : "";
+
+  if ((res = f_opendir (&dir, path)))
+  { 
+    f_printerror (res); 
+    return 0;
+  }
+
+  for (size = files = dirs = 0;;)
+  {
+    if (((res = f_readdir (&dir, &fileInfo)) != FR_OK) || !fileInfo.fname [0]) 
+      break;
+
+    if (fileInfo.fattrib & AM_DIR) 
+      dirs++;
+    else 
+    {
+      files++; 
+      size += fileInfo.fsize;
+    }
+
+    printf ("\n%c%c%c%c%c %u/%02u/%02u %02u:%02u %9u  %s",
+        (fileInfo.fattrib & AM_DIR) ? 'D' : '-',
+        (fileInfo.fattrib & AM_RDO) ? 'R' : '-',
+        (fileInfo.fattrib & AM_HID) ? 'H' : '-',
+        (fileInfo.fattrib & AM_SYS) ? 'S' : '-',
+        (fileInfo.fattrib & AM_ARC) ? 'A' : '-',
+        (fileInfo.fdate >> 9) + 1980, (fileInfo.fdate >> 5) & 15, fileInfo.fdate & 31,
+        (fileInfo.ftime >> 11), (fileInfo.ftime >> 5) & 63,
+        fileInfo.fsize, &(fileInfo.fname [0]));
+  }
+
+  printf ("\n%4u File(s),%10u bytes\n%4u Dir(s)", files, size, dirs);
+
+  if (f_getfree (path, (U32 *) &size, &fs) == FR_OK)
+    printf (", %10uK bytes free", size * fs->sects_clust / 2);
+
+  printf ("\n");
+
+  return 0;
+}
+
+static int monitorFileMkdir (int argc __attribute__ ((unused)), portCHAR **argv)
+{
+  f_printerror (f_mkdir (argv [0]));
+
+  return 0;
+}
+
+static int monitorFileRmCommon (char *path, int mode)
+{
+  FRESULT f;
+
+  if ((f = f_stat (path, &fileInfo)) != FR_OK)
+  {
+    f_printerror (f);
+    return 0;
+  }
+
+  if (mode == AM_DIR)
+  {
+    if (!(fileInfo.fattrib & AM_DIR))
+      printf ("Not a directory\n");
+    else
+      f_printerror (f_unlink (path));
+  }
+  else
+  {
+    if (fileInfo.fattrib & AM_DIR)
+      printf ("Not a regular file\n");
+    else
+      f_printerror (f_unlink (path));
+  }
+
+  return 0;
+}
+
+static int monitorFileRmdir (int argc __attribute__ ((unused)), portCHAR **argv)
+{
+  return monitorFileRmCommon (argv [0], AM_DIR);
+}
+
+static int monitorFileRm (int argc __attribute__ ((unused)), portCHAR **argv)
+{
+  return monitorFileRmCommon (argv [0], 0);
+}
+
+static int monitorFileMv (int argc __attribute__ ((unused)), portCHAR **argv)
+{
+  if (rename (argv [0], argv [1]) == -1)
+    printf ("rename failed, errno=%d/%s\n", errno, strerror (errno));
+
+  return 0;
+}
+
+static int monitorFileCp (int argc __attribute__ ((unused)), portCHAR **argv)
+{
+  int fdIn;
+  int fdOut;
+  int l;
+  char buffer [128];
+
+  if ((fdIn = open (argv [0], O_RDONLY)) == -1)
+  {
+    printf ("Cannot open input file \"%s\", errno=%d/%s\n", argv [0], errno, strerror (errno));
+    return 0;
+  }
+
+  if (argc == 1)
+  {
+    fdOut = fileno (stdout);
+    fflush (stdout);
+  }
+  else if ((fdOut = open (argv [1], O_CREAT | O_TRUNC | O_WRONLY)) == -1)
+  {
+    printf ("Cannot open output file \"%s\", errno=%d/%s\n", argv [1], errno, strerror (errno));
+    close (fdIn);
+    return 0;
+  }
+
+  while ((l = read (fdIn, buffer, sizeof (buffer))))
+  {
+    if (write (fdOut, buffer, l) != l)
+    {
+      printf ("write() returned error %d/%s (l=%d)\n", errno, strerror (errno), l);
+      break;
+    }
+  }
+
+  close (fdIn);
+
+  if (fdOut != fileno (stdout))
+    close (fdOut);
+
+  return 0;
+}
+
+static int monitorFileSync (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+  sync ();
+
+  return 0;
+}
+
+int monitorTimevalSubtract (struct timeval *result, struct timeval *x, struct timeval *y);
+int monitorTimevalSubtract (struct timeval *result, struct timeval *x, struct timeval *y)
+{
+  if (x->tv_usec < y->tv_usec)
+  {
+    int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
+    y->tv_usec -= 1000000 * nsec;
+    y->tv_sec += nsec;
+  }
+
+  if (x->tv_usec - y->tv_usec > 1000000)
+  {
+    int nsec = (x->tv_usec - y->tv_usec) / 1000000;
+    y->tv_usec += 1000000 * nsec;
+    y->tv_sec -= nsec;
+  }
+
+  result->tv_sec = x->tv_sec - y->tv_sec;
+  result->tv_usec = x->tv_usec - y->tv_usec;
+
+  return x->tv_sec < y->tv_sec;
+}
+
+typedef enum
+{
+  MODE_NORMAL = 0,
+  MODE_NOINTS,
+  MODE_SUSPENDALL,
+  MODE_HIGH
+}
+mode_e;
+
+static int monitorFileThruPut (int argc __attribute__ ((unused)), portCHAR **argv)
+{
+  unsigned int i;
+  mode_e mode;
+  int fileSizes [] = { 1*1024, 8*1024, 16*1024, 64*1024, 128*1024, 512*1024, 1024*1024, 2048*1024 };
+
+  if (!strcmp (argv [0], "normal"))
+    mode = MODE_NORMAL;
+  else if (!strcmp (argv [0], "noints"))
+    mode = MODE_NOINTS;
+  else if (!strcmp (argv [0], "suspendall"))
+    mode = MODE_SUSPENDALL;
+  else if (!strcmp (argv [0], "high"))
+    mode = MODE_HIGH;
+  else
+  {
+    printf ("arguments must be 'normal', 'noints', 'suspendall', or 'high'\n");
+    return 0;
+  }
+
+  printf ("%lu tests, with ", arrsizeof (fileSizes));
+
+  switch (mode)
+  {
+    case MODE_NORMAL     : printf ("interrupts enabled, no tasks suspended, default priority\n\n"); break;
+    case MODE_NOINTS     : printf ("interrupts disabled (no tasking)\n\n"); break;
+    case MODE_SUSPENDALL : printf ("interrupts enabled, all tasks suspended\n\n"); break;
+    case MODE_HIGH       : printf ("interrupts enabled, this task promoted to highest priority\n\n");
+  }
+
+  for (i = 0; i < arrsizeof (fileSizes); i++)
+  {
+    int j;
+
+    for (j = 0; j < 2; j++)
+    {
+      int fd;
+      int k;
+      char buffer [512];
+      struct timeval tv_start;
+      struct timeval tv_end;
+      struct timeval tv_diff;
+      unsigned long ticks10ms;
+      unsigned portBASE_TYPE taskPriority = 0;
+
+      if ((fd = open ("testfile.bin", !j ? (O_TRUNC | O_CREAT | O_WRONLY) : (O_RDONLY))) == -1)
+      {
+        printf ("Cannot open \"testfile.bin\", errno=%d/%s\n", errno, strerror (errno));
+        return 0;
+      }
+
+      if (!j)
+        memset (buffer, 0xe5, sizeof (buffer));
+
+
+      switch (mode)
+      {
+        case MODE_NORMAL     : break;
+        case MODE_NOINTS     : portENTER_CRITICAL (); break;
+        case MODE_SUSPENDALL : vTaskSuspendAll (); break;
+        case MODE_HIGH       : taskPriority = uxTaskPriorityGet (NULL); vTaskPrioritySet (NULL, (configMAX_PRIORITIES - 1)); break;
+      }
+
+      gettimeofday (&tv_start, NULL);
+
+      if (!j)
+      {
+        for (k = fileSizes [i]; k > 0; k -= sizeof (buffer))
+        {
+          if (write (fd, buffer, sizeof (buffer)) != sizeof (buffer))
+          {
+            printf ("write() failed, errno=%d/%s\n", errno, strerror (errno));
+            close (fd);
+            return 0;
+          }
+        }
+      }
+      else
+      {
+        for (k = fileSizes [i]; k > 0; k -= sizeof (buffer))
+        {
+          if (read (fd, buffer, sizeof (buffer)) != sizeof (buffer))
+          {
+            printf ("read() failed, errno=%d/%s\n", errno, strerror (errno));
+            close (fd);
+            return 0;
+          }
+        }
+      }
+
+      gettimeofday (&tv_end, NULL);
+
+      switch (mode)
+      {
+        case MODE_NORMAL     : break;
+        case MODE_NOINTS     : portEXIT_CRITICAL (); break;
+        case MODE_SUSPENDALL : xTaskResumeAll (); break;
+        case MODE_HIGH       : vTaskPrioritySet (NULL, taskPriority); break;
+      }
+
+      if (close (fd) == -1)
+      {
+        printf ("close() failed, errno=%d/%s\n", errno, strerror (errno));
+        return 0;
+      }
+
+      {
+        struct timeval tempStart = tv_start;
+        struct timeval tempEnd = tv_end;
+
+        monitorTimevalSubtract (&tv_diff, &tv_end, &tv_start);
+        ticks10ms = (tv_diff.tv_sec * 100) + (tv_diff.tv_usec / 10000);
+
+        printf ("%5s: %9u bytes, %7lu milliseconds (%4ld seconds), %7lu bytes/sec\n", 
+            !j ? "Write" : "Read", 
+            fileSizes [i], 
+            ticks10ms * 10,
+            ticks10ms / 100,
+            (fileSizes [i] * 100) / ticks10ms);
+
+        if (ticks10ms > 10000)
+        {
+          printf ("tv_start = %ld, %ld\n", tempStart.tv_sec, tempStart.tv_usec);
+          printf ("tv_end   = %ld, %ld\n", tempEnd.tv_sec, tempEnd.tv_usec);
+          printf ("tv_diff  = %ld, %ld\n", tv_diff.tv_sec, tv_diff.tv_usec);
+        }
+      }
+
+      if (j && unlink ("testfile.bin") == -1)
+      {
+        printf ("unlink() failed, errno=%d/%s\n", errno, strerror (errno));
+        return 0;
+      }
+    }
+  }
+
+  printf ("\nDone\n");
+
+  return 0;
+}
+
+static int monitorFileCpCon (int argc __attribute__ ((unused)), portCHAR **argv)
+{
+  int fdOut;
+  char c;
+
+  if ((fdOut = open (argv [0], O_CREAT | O_TRUNC | O_WRONLY)) == -1)
+  {
+    printf ("Cannot open output file \"%s\", errno=%d/%s\n", argv [0], errno, strerror (errno));
+    return 0;
+  }
+
+  while (read (fileno (stdin), &c, sizeof (c)))
+  {
+    if (c == 0x04)
+      break;
+
+    if (c == '\r')
+      c = '\n';
+
+    if (write (fdOut, &c, sizeof (c)) != sizeof (c))
+    {
+      printf ("write() returned error %d/%s\n", errno, strerror (errno));
+      break;
+    }
+
+    printf ("%c", c);
+    fflush (stdout);
+  }
+
+  if (close (fdOut) == -1)
+    printf ("close() returned error %d/%s\n", errno, strerror (errno));
+
+  return 0;
+}
+
+static int monitorFileChmod (int argc __attribute__ ((unused)), portCHAR **argv)
+{
+  mode_t mode;
+
+  if (!strcmp (argv [0], "-w"))
+    mode = 0;
+  else if (!strcmp (argv [0], "+w"))
+    mode = S_IWUSR;
+  else
+  {
+    printf ("mode must be +w (writable) or -w (not writable)\n");
+    return 0;
+  }
+
+  if (chmod (argv [1], mode) == -1)
+    printf ("chmod() failed, errno=%d/%s\n", errno, strerror (errno));
+
+  return 0;
+}
+
+//
+//
+//
+static int monitorGPS (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+  gpsData_t gpsData;
+
+  if (gpsCopyData (&gpsData))
+  {
+    printf ("Valid ...... : %d\n", gpsData.valid);
+    printf ("Date ....... : %04d/%02d/%02d\n", gpsData.utcYear, gpsData.utcMonth, gpsData.utcDay);
+    printf ("Time ....... : %02d:%02d:%02d\n", gpsData.utcHours, gpsData.utcMinutes, gpsData.utcSeconds);
+    printf ("Speed ...... : %f\n", gpsData.groundSpeed);
+    printf ("Heading .... : %f\n", gpsData.trueCourse);
+    printf ("Altitude ... : %f\n", gpsData.height);
+    printf ("Latitude ... : %f\n", gpsData.latitude);
+    printf ("Longitude .. : %f\n", gpsData.longitude);
+    printf ("Restarts ... : %d\n", gpsData.restarts);
+    printf ("Sizeof () .. : %ld\n", sizeof (gpsData));
+  }
+  else
+    printf ("Unable to get GPS data\n");
+
+  return 0;
+}
+
+//
+//
+//
+static int monitorSensors (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+  sensorData_t sensorData;
+
+  if (sensorsCopyData (&sensorData))
+  {
+    printf ("Sensor count .. : %d\n", sensorData.sensorCount);
+    printf ("ADC changes ... : %d\n", sensorData.adcChanges);
+  }
+  else
+    printf ("Unable to get sensor data\n");
+
+  return 0;
+}
+
+static int monitorMd (int argc, portCHAR **argv)
+{
+  static unsigned int address = 0x00000000;
+  unsigned int length = 256;
+
+  if ((argc >= 1))
+  {
+    if (!getNumber (argv [0], &address))
+      return 0;
+
+    if (argc == 2)
+      if (!getNumber (argv [1], &length))
+        return 0;
+  }
+
+  address = monitorDumpMemory (address, address, length);
+
+  return 0;
+}
+
+//
+//
+//
+static int monitorAbortRegs (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+  abortDat_t *ad = (abortDat_t *) &__abort_dat;
+
+  printf ("contents=%s, sigil=0x%08x, count=%d\n", (ad->sigil == 0xdeadc0de) ? "probable" : "invalid", ad->sigil, ad->count);
+  printf ("abort type=%s\n", (ad->type == 0) ? "undefined instruction" : (ad->type == 1) ? "prefetch abort" : (ad->type == 2) ? "data abort" : "unknown");
+  printf ("pc=0x%08x, opcode=0x%08x\n", ad->pc, ad->opcode);
+  printf ("cpsr=0x%08x, sp=0x%08x, lr=0x%08x\n", ad->cpsr, ad->sp, ad->lr);
+  printf ("r0=0x%08x, r1=0x%08x, r2=0x%08x, r3=0x%08x\n", ad->r0, ad->r1, ad->r2, ad->r3);
+  printf ("r4=0x%08x, r5=0x%08x, r6=0x%08x, r7=0x%08x\n", ad->r4, ad->r5, ad->r6, ad->r7);
+  printf ("r8=0x%08x, r9=0x%08x, r10=0x%08x, r11=0x%08x\n", ad->r8, ad->r9, ad->r10, ad->r11);
+  printf ("r12=0x%08x\n", ad->r12);
+  printf ("\n");
+
+  printf ("sp[0]=0x%08x, sp[1]=0x%08x, sp[2]=0x%08x, sp[3]=0x%08x\n", ad->stack [0], ad->stack [1], ad->stack [2], ad->stack [3]);
+  printf ("sp[4]=0x%08x, sp[5]=0x%08x, sp[6]=0x%08x, sp[7]=0x%08x\n", ad->stack [4], ad->stack [5], ad->stack [6], ad->stack [7]);
+
+  return 0;
+}
+
+static int monitorAbortClear (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+  abortDat_t *ad = (abortDat_t *) &__abort_dat;
+
+  memset (ad, 0, sizeof (* ad));
+
+  return 0;
+}
+
+static int monitorAbortDirty (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+  abortDat_t *ad = (abortDat_t *) &__abort_dat;
+
+  ad->sigil = 0;
+
+  return 0;
+}
+
+static int monitorAbortUndef (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+  asm volatile (" .word 0x06000010" : /* no output */ : /* no inputs */ );
+
+  return 0;
+}
+
+static int monitorAbortPabort (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+  asm volatile (" ldr r0, =0x00080000" : /* no output */ : /* no inputs */ );
+  asm volatile (" mov pc, r0" : /* no output */ : /* no inputs */ );
+
+  return 0;
+}
+
+static int monitorAbortDabort (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+  unsigned char c;
+  volatile unsigned char *ptr = (unsigned char *) 0x40008000;
+
+  c = *ptr;
+
+  return 0;
+}
+
+//
+//
+//
+static int monitorEEAddr (int argc __attribute__ ((unused)), portCHAR **argv)
+{
+  unsigned int address;
+
+  if (!getNumber (argv [0], &address))
+    return 0;
+
+  if (eepromSetAddress (address))
+  {
+    printf ("Error: address out of range\n");
+    eepromSetAddress (0);
+  }
+
+  return 0;
+}
+
+static int monitorEERead (int argc, portCHAR **argv)
+{
+  unsigned int address;
+  unsigned int length = 256;
+  unsigned char buffer [64];
+  unsigned int i;
+
+  if (argc && !getNumber (argv [0], &length))
+    return 0;
+
+  for (address = eepromGetAddress(), i = 0; i < length; i += sizeof (buffer), address = (address + sizeof (buffer)) % EEPROM_SIZE)
+  {
+    unsigned int l;
+
+    if (!(l = i % sizeof (buffer)))
+      l = MIN (length, sizeof (buffer));
+
+    if (eepromRead (buffer, l))
+    {
+      printf ("eepromRead() returned error %d/%s\n", i2cGetErrno (), i2cStrerror (i2cGetErrno ()));
+      return 0;
+    }
+
+    monitorDumpMemory (address, (unsigned int) buffer, l);
+  }
+
+  return 0;
+}
+
+static int monitorEEReadAddr (int argc, portCHAR **argv)
+{
+  unsigned int address;
+  
+  if (!getNumber (argv [0], &address))
+    return 0;
+
+  if (eepromSetAddress (address))
+  {
+    printf ("Error: address out of range\n");
+    return 0;
+  }
+
+  return monitorEERead (--argc, ++argv);
+}
+
+static int monitorEEWriteCommon (int argc, portCHAR **argv, unsigned char *buffer, int bufferLength)
+{
+  int i;
+
+  for (i = 0; i < argc; i++)
+  {
+    unsigned int n;
+
+    if (i >= bufferLength)
+    {
+      printf ("Error: buffer too small for number arguments\n");
+      return -1;
+    }
+
+    if (!getNumber (argv [i], &n))
+      return 0;
+
+    if (n > 255)
+    {
+      printf ("Error: data must be 0x00..0xff (0..255)\n");
+      return -1;
+    }
+
+    buffer [i] = n;
+  }
+
+  return 0;
+}
+
+//
+//  Note the two reserved bytes at the beginning of the buffer.  These are
+//  reserved for the address we're writing to in the EEPROM.  They're populated
+//  by the eepromWrite() routine.  This feel hackish, but unlike the read
+//  routines, we can't send the address, then a repeated start bit to switch to
+//  write.
+//
+static int monitorEEWrite (int argc, portCHAR **argv)
+{
+  unsigned char buffer [18];
+
+  if (monitorEEWriteCommon (argc, argv, &buffer [2], sizeof (buffer) - 2))
+    return 0;
+
+  if (eepromWrite (buffer, argc))
+    printf ("eepromWrite() returned %d/%s\n", i2cGetErrno (), i2cStrerror (i2cGetErrno ()));
+
+  return 0;
+}
+
+static int monitorEEWriteAddr (int argc, portCHAR **argv)
+{
+  unsigned int address;
+
+  if (!getNumber (argv [0], &address))
+    return 0;
+
+  if (eepromSetAddress (address))
+  {
+    printf ("Error: address out of range\n");
+    return 0;
+  }
+
+  return monitorEEWrite (--argc, ++argv);
+}
+
+static int monitorEEFillAddr (int argc __attribute__ ((unused)), portCHAR **argv)
+{
+  unsigned int address;
+  unsigned int length;
+  unsigned int fillChar;
+
+  if (!getNumber (argv [0], &address) || !getNumber (argv [1], &length) || !getNumber (argv [2], &fillChar))
+    return 0;
+
+  if (fillChar > 255)
+    printf ("Error: fill value must be 0x00..0xff (0..255)\n");
+  else if (eepromFillAddress (address, length, fillChar))
+    printf ("eepromFillAddress() returned error %d/%s\n", i2cGetErrno (), i2cStrerror (i2cGetErrno ()));
+
+  return 0;
+}
+
+//
+//
+//
+static int monitorFIQOn (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+  printf ("FIQ interrupts enabled, previous state was %s\n", fiqEnable () ? "enabled" : "disabled");
+
+  return 0;
+}
+
+static int monitorFIQOff (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+  printf ("FIQ interrupts disabled, previous state was %s\n", fiqDisable () ? "enabled" : "disabled");
+
+  return 0;
+}
+
+static int monitorFIQCount (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+  printf ("FIQ counter = %u\n", fiqGetCount ());
+
+  return 0;
+}
+
+static int monitorFIQClear (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+  fiqClearCount ();
+
+  return 0;
+}
+
+//
+//
+//
+int monitorI2CRead (int argc __attribute__ ((unused)), portCHAR **argv)
+{
+  unsigned int address;
+  unsigned int numBytes;
+  unsigned char buffer [16];
+  int r;
+
+  if (!getNumber (argv [0], &address))
+    return 0;
+  if (!getNumber (argv [1], &numBytes))
+    return 0;
+
+  if (address > 255)
+  {
+    printf ("Error: address must be 0x00..0xff (0..255)\n");
+    return 0;
+  }
+
+  if ((numBytes < 1) || (numBytes > sizeof (buffer)))
+  {
+    printf ("Error: number of bytes must be 1..%ld\n", sizeof (buffer));
+    return 0;
+  }
+
+  r = i2cReadBuffer (address, buffer, numBytes);
+
+  printf ("i2cReadBuffer() returned %d/%s (%s)\n\n", i2cGetErrno (), i2cStrerror (i2cGetErrno ()), r ? "error" : "no error");
+
+  monitorDumpMemory (0, (unsigned int) buffer, (int) sizeof (buffer));
+
+  return 0;
+}
+
+int monitorI2CWrite (int argc, portCHAR **argv)
+{
+  unsigned int address;
+  unsigned char buffer [16];
+  int i;
+
+  if (!getNumber (argv [0], &address))
+    return 0;
+
+  if (address > 255)
+  {
+    printf ("Error: address must be 0x00..0xff (0..255)\n");
+    return 0;
+  }
+
+  for (i = 0; i < argc - 1; i++)
+  {
+    unsigned int n;
+
+    if (!getNumber (argv [i + 1], &n))
+      return 0;
+
+    if (n > 255)
+    {
+      printf ("Error: data must be 0x00..0xff (0..255)\n");
+      return 0;
+    }
+
+    buffer [i] = n;
+  }
+
+  i = i2cWriteBuffer (address, buffer, argc - 1);
+
+  printf ("i2cWriteBuffer() returned %d/%s (%s)\n", i2cGetErrno (), i2cStrerror (i2cGetErrno ()), i ? "error" : "no error");
+
+  return 0;
+}
+
+int monitorI2CWriteRead (int argc, portCHAR **argv)
+{
+  unsigned int address;
+  unsigned int bytesToWrite;
+  unsigned int bytesToRead;
+  unsigned char buffer [16];
+  unsigned int i;
+
+  if (!getNumber (argv [0], &address))
+    return 0;
+
+  if (address > 255)
+  {
+    printf ("Error: address must be 0x00..0xff (0..255)\n");
+    return 0;
+  }
+
+  for (bytesToWrite = argc - 2, i = 0; i < bytesToWrite; i++)
+  {
+    unsigned int n;
+
+    if (!getNumber (argv [i + 1], &n))
+      return 0;
+
+    if (n > 255)
+    {
+      printf ("Error: data must be 0x00..0xff (0..255)\n");
+      return 0;
+    }
+
+    buffer [i] = n;
+  }
+
+  if (!getNumber (argv [argc - 1], &bytesToRead))
+    return 0;
+
+  if ((bytesToRead < 1) || (bytesToRead > sizeof (buffer)))
+  {
+    printf ("Error: number of bytes must be 1..%ld\n", sizeof (buffer));
+    return 0;
+  }
+
+  i2cWriteReadBuffer (address, buffer, bytesToWrite, bytesToRead);
+
+  printf ("i2cWriteReadBuffer() returned %d/%s\n\n", i2cGetErrno (), i2cStrerror (i2cGetErrno ()));
+
+  monitorDumpMemory (0, (unsigned int) buffer, (int) sizeof (buffer));
+
+  return 0;
+}
+
+int monitorI2CDump (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+  i2cDump ();
+
+  return 0;
+}
+
+int monitorI2CErrno (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+  printf ("i2cErrno=%d/%s\n", i2cGetErrno (), i2cStrerror (i2cGetErrno ()));
+
+  return 0;
+}
+
+//
+//  Note that although the iapXXX calls can deal with multiple sectors, we only ever
+//  deal with one at a time.  This simplifies the user interface.
+//
+static int monitorIAPFSS (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+  int ss;
+
+  if ((ss = iapFindSafeSector ()) == -1)
+    printf ("Can't find a safe sector!  All of flash in use?\n");
+  else
+    printf ("Sector number %d is safe for IAP operations (won't overwrite any code)\n", ss);
+
+  return 0;
+}
+
+static int monitorIAPSTOA (int argc __attribute__ ((unused)), portCHAR **argv)
+{
+  unsigned int sector;
+  unsigned long address;
+  int sectorSize;
+
+  if (!getNumber (argv [0], &sector))
+    return 0;
+
+  if (iapSectorToAddress (sector, &address, &sectorSize) == -1)
+    printf ("Sector number out of range\n");
+  else
+    printf ("Sector %d occupies address 0x%08lx for 0x%04x bytes\n", sector, address, sectorSize);
+
+  return 0;
+}
+
+static int monitorIAPFill (int argc __attribute__ ((unused)), portCHAR **argv)
+{
+  unsigned int sector;
+  unsigned int byte;
+
+  if (!getNumber (argv [0], &sector))
+    return 0;
+  if (!getNumber (argv [1], &byte))
+    return 0;
+
+  if (!iapIsSafeSector ((int) sector))
+  {
+    printf ("Sector number out of range or not in safe region\n");
+    return 0;
+  }
+
+  if (byte > 255)
+  {
+    printf ("Fill character must be 0x00..0xff (0..255)\n");
+    return 0;
+  }
+
+  if (iapFillSectors (sector, sector, byte) == -1)
+    printf ("iapFillSectors returned error %d/%s\n", iapGetErrno (), iapStrerror (iapGetErrno ()));
+  else
+    printf ("Sector %d filled with 0x%02x\n", sector, byte);
+
+  return 0;
+}
+
+static int monitorIAPErase (int argc __attribute__ ((unused)), portCHAR **argv)
+{
+  unsigned int sector;
+
+  if (!getNumber (argv [0], &sector))
+    return 0;
+
+  if (!iapIsSafeSector ((int) sector))
+  {
+    printf ("Sector number out of range or not in safe region\n");
+    return 0;
+  }
+
+  if (iapEraseSectors (sector, sector) == -1)
+    printf ("iapEraseSectors returned error %d/%s\n", iapGetErrno (), iapStrerror (iapGetErrno ()));
+  else
+    printf ("Sector %d erased\n", sector);
+
+  return 0;
+}
+
+static int monitorIAPBlank (int argc __attribute__ ((unused)), portCHAR **argv)
+{
+  unsigned int sector;
+
+  if (!getNumber (argv [0], &sector))
+    return 0;
+
+  if (!iapIsValidSector ((int) sector))
+  {
+    printf ("Sector number out of range\n");
+    return 0;
+  }
+
+  switch (iapBlankCheckSectors (sector, sector))
+  {
+    case 0 :
+      printf ("Sector %d is blank\n", sector);
+      break;
+
+    case 1 :
+      printf ("Sector %d is not blank\n", sector);
+      break;
+
+    default :
+      printf ("iapBlankCheckSector returned error %d/%s\n", iapGetErrno (), iapStrerror (iapGetErrno ()));
+      break;
+  }
+
+  return 0;
+}
+
+static int monitorIAPID (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+  printf ("IAP ID=0x%08x\n", iapReadPartID ());
+
+  return 0;
+}
+
+static int monitorIAPVer (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+  printf ("IAP ID=0x%08x\n", iapReadBootCodeVersion ());
+
+  return 0;
+}
+
+static int monitorIAPISP (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+  iapISP ();
+
+  return 0;
+}
+
+//
+//
+//
+int monitorLM75Init (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+  if (lm75Init ())
+    printf ("lm75Init() returned error %d/%s\n", i2cGetErrno (), i2cStrerror (i2cGetErrno ()));
+
+  return 0;
+}
+
+int monitorLM75Mode (int argc __attribute__ ((unused)), portCHAR **argv)
+{
+  unsigned int mode;
+
+  if (!getNumber (argv [0], &mode))
+    return 0;
+
+  if (mode > 1)
+    printf ("Error: mode must be 0 or 1\n");
+  else
+  {
+    lm75SetMode (mode);
+
+    if (!mode)
+      printf ("lm75 using I2C repeated start for write then read\n");
+    else
+      printf ("lm75 using I2C stop then start for read\n");
+  }
+
+  return 0;
+}
+
+int monitorLM75Addr (int argc __attribute__ ((unused)), portCHAR **argv)
+{
+  unsigned int address;
+
+  if (!getNumber (argv [0], &address))
+    return 0;
+
+  if (address > 0xff)
+    printf ("Error: address must be 0x00..0xff (0..255)\n");
+  else
+    lm75SetAddress (address);
+
+  return 0;
+}
+
+int monitorLM75ReRead (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+  int value;
+
+  if (lm75ReRead (&value))
+    printf ("lm75Read() returned error %d/%s\n", i2cGetErrno (), i2cStrerror (i2cGetErrno ()));
+  else
+    printf ("value=0x%x\n", value);
+
+  return 0;
+}
+
+int monitorLM75Temp (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+  int temp;
+
+  if (lm75TemperatureRead (&temp))
+    printf ("lm75TemperatureRead() returned error %d/%s\n", i2cGetErrno (), i2cStrerror (i2cGetErrno ()));
+  else
+    printf ("temp=%d.%dC\n", temp >> 1, (temp & 0x01) ? 5 : 0);
+
+  return 0;
+}
+
+int monitorLM75Config (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+  int config;
+
+  if (lm75ConfigRead (&config))
+    printf ("lm75ConfigRead() returned error %d/%s\n", i2cGetErrno (), i2cStrerror (i2cGetErrno ()));
+  else
+    printf ("config=0x%02x\n", config);
+
+  return 0;
+}
+
+int monitorLM75Thyst (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+  int thyst;
+
+  if (!argc)
+  {
+    if (lm75THYSTRead (&thyst))
+      printf ("lm75THYSTRead() returned error %d/%s\n", i2cGetErrno (), i2cStrerror (i2cGetErrno ()));
+    else
+      printf ("THYST=%d.%dC\n", thyst / 2, (thyst & 0x01) ? 5 : 0);
+  }
+  else
+  {
+    if (!getNumber (argv [0], (unsigned int *) &thyst))
+      return 0;
+
+    if ((thyst < -55) || (thyst > 125))
+      printf ("Error: THYST range is -55C to +125C\n");
+    else if (lm75THYSTWrite (thyst << 1))
+      printf ("lm75THYSTWrite() returned error %d/%s\n", i2cGetErrno (), i2cStrerror (i2cGetErrno ()));
+  }
+  return 0;
+}
+
+int monitorLM75Tos (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+  int tos;
+
+  if (!argc)
+  {
+    if (lm75TOSTRead (&tos))
+      printf ("lm75TOSRead() returned error %d/%s\n", i2cGetErrno (), i2cStrerror (i2cGetErrno ()));
+    else
+      printf ("TOS=%d.%dC\n", tos / 2, (tos & 0x01) ? 5 : 0);
+  }
+  else 
+  {
+    if (!getNumber (argv [0], (unsigned int *) &tos))
+      return 0;
+    
+    if ((tos < -55) || (tos > 125))
+      printf ("Error: TOS range is -55C to +125C\n");
+    else if (lm75TOSWrite (tos << 1))
+      printf ("lm75TOSWrite() returned error %d/%s\n", i2cGetErrno (), i2cStrerror (i2cGetErrno ()));
+  }
+
+  return 0;
+}
+
+//
+//  6 tasks, each task needs about 42 bytes to display
+//
+#define monitorTask_BUFFERSIZE (6 * 42)
+
+static int monitorMemTask (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+#if configUSE_TRACE_FACILITY == 1
+  signed portCHAR buffer [monitorTask_BUFFERSIZE];
+  int bytesFree;
+  int bytesUsed;
+  int blocksFree;
+
+  vTaskList (buffer);
+  vPortUsedMem (&bytesFree, &bytesUsed, &blocksFree);
+  printf ("%s\nHeap size=%ld, used=%d, free=%d (%d blocks)\n", buffer, configTOTAL_HEAP_SIZE, bytesUsed, bytesFree, blocksFree);
+#else
+  printf ("Not implemented (requires configUSE_TRACE_FACILITY in FreeRTOSConfig.h)\n");
+#endif
+
+  return 0;
+}
+
+typedef struct memMap_s
+{
+  char *desc;
+  int m;
+  unsigned int start;
+  unsigned int end;
+}
+memMap_t;
+
+typedef union 
+{
+  void *v;
+  unsigned int i;
+}
+sbrkConv_t;
+
+static inline unsigned __get_cpsr (void)
+{
+  unsigned long retval;
+
+  asm volatile (" mrs  %0, cpsr" : "=r" (retval) : /* no inputs */  );
+
+  return retval;
+}
+
+static int monitorMemMap (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+  unsigned int i;
+  sbrkConv_t sbrkConv;
+  static memMap_t memMap [] = 
+  {
+    { ".startup .....", 0, (unsigned int) &__start_of_startup__, (unsigned int) &__end_of_startup__ },
+    { ".text ........", 0, (unsigned int) &__start_of_text__,    (unsigned int) &__end_of_text__ },
+    { ".code ........", 0, (unsigned int) &__start_of_prog__,    (unsigned int) &__end_of_prog__ },
+    { ".rodata ......", 0, (unsigned int) &__start_of_rodata__,  (unsigned int) &__end_of_rodata__ },
+    { ".data ........", 0, (unsigned int) &__data_beg__,         (unsigned int) &__data_end__ },
+    { ".bss .........", 0, (unsigned int) &__bss_beg__,          (unsigned int) &__bss_end__ },
+    { "heap .........", 1, (unsigned int) &__heap_beg,           (unsigned int) &__heap_end },
+    { "heap range ...", 1, (unsigned int) &__heap_beg,           (unsigned int) &__heap_max },
+//  { "SYS stack ....", 1, (unsigned int) &__stack_beg_sys,      (unsigned int) &__stack_end_sys }, // Not relevant to FreeRTOS
+    { "SVC stack ....", 1, (unsigned int) &__stack_beg_svc,      (unsigned int) &__stack_end_svc },
+    { "IRQ stack ....", 1, (unsigned int) &__stack_beg_irq,      (unsigned int) &__stack_end_irq },
+    { "FIQ stack ....", 1, (unsigned int) &__stack_beg_fiq,      (unsigned int) &__stack_end_fiq },
+    { "abort stack ..", 1, (unsigned int) &__stack_beg_abt,      (unsigned int) &__stack_end_abt },
+    { "undef stack ..", 1, (unsigned int) &__stack_beg_und,      (unsigned int) &__stack_end_und },
+  };
+
+  sbrkConv.v = sbrk (0);
+  __heap_end = sbrkConv.i;
+  __stack_end_sys = sbrkConv.i;
+
+  printf ("Section        Start      End        Length\n");
+  printf ("-------------------------------------------\n");
+
+  for (i = 0; i < arrsizeof (memMap); i++)
+  {
+    if (!memMap [i].m)
+      printf ("%s 0x%08x 0x%08x 0x%x\n", memMap [i].desc, memMap [i].start, memMap [i].end, abs (memMap [i].end - memMap [i].start));
+    else
+      printf ("%s 0x%08x 0x%08x 0x%x\n", memMap [i].desc, *(unsigned int *) memMap [i].start, *(unsigned int *) memMap [i].end, abs (*(unsigned int *) memMap [i].end - *(unsigned int *) memMap [i].start));
+  }
+
+#if 0
+  printf ("\nProcessor mode ");
+
+  switch ((i = __get_cpsr ()) & 0x1f)
+  {
+    case 0x10 : printf ("User"); break;
+    case 0x11 : printf ("FIQ"); break;
+    case 0x12 : printf ("IRQ"); break;
+    case 0x13 : printf ("Supervisor"); break;
+    case 0x17 : printf ("Abort"); break;
+    case 0x1b : printf ("Undefined"); break;
+    case 0x1f : printf ("System"); break;
+    default   : printf ("Unknown");
+  }
+
+  printf (", IRQ %s", (i & 0x80) ? "disabled" : "enabled");
+  printf (", FIQ %s", (i & 0x40) ? "disabled" : "enabled");
+  printf (", mode %s\n", (i & 0x20) ? "THUMB" : "ARM");
+#endif
+
+  printf ("\n");
+  malloc_stats ();
+
+  return 0;
+}
+
+typedef struct memorySlots_s
+{
+  unsigned char *p;
+  unsigned int size;
+}
+memorySlots_t;
+
+memorySlots_t memorySlots [8];
+
+static int monitorMemAlloc (int argc __attribute__ ((unused)), portCHAR **argv)
+{
+  unsigned int size;
+  unsigned int slot;
+  unsigned char *p;
+
+  if (!getNumber (argv [0], &slot) || !getNumber (argv [0], &size))
+    return 0;
+
+  if (slot >= arrsizeof (memorySlots))
+  {
+    printf ("slot must be 0..%lu\n", arrsizeof (memorySlots) - 1);
+    return 0;
+  }
+
+  if (memorySlots [slot].p)
+    printf ("Slot %d in use, free it first, or use realloc\n", slot);
+  else if (!(p = malloc (size)))
+    printf ("malloc() failed, error %d/%s\n", errno, strerror (errno));
+  else
+  {
+    memorySlots [slot].p = p;
+    memorySlots [slot].size = size;
+  }
+
+  return 0;
+}
+
+static int monitorMemRealloc (int argc __attribute__ ((unused)), portCHAR **argv)
+{
+  unsigned int size;
+  unsigned int slot;
+  unsigned char *p;
+
+  if (!getNumber (argv [0], &slot) || !getNumber (argv [0], &size))
+    return 0;
+
+  if (slot >= arrsizeof (memorySlots))
+  {
+    printf ("slot must be 0..%lu\n", arrsizeof (memorySlots) - 1);
+    return 0;
+  }
+
+  if (!(p = realloc (memorySlots [slot].p, size)))
+    printf ("realloc() failed, error %d/%s\n", errno, strerror (errno));
+  else
+  {
+    memorySlots [slot].p = p;
+    memorySlots [slot].size = size;
+  }
+
+  return 0;
+}
+
+static int monitorMemFree (int argc __attribute__ ((unused)), portCHAR **argv)
+{
+  unsigned int slot;
+
+  if (!getNumber (argv [0], &slot))
+    return 0;
+
+  if (slot >= arrsizeof (memorySlots))
+  {
+    printf ("slot must be 0..%lu\n", arrsizeof (memorySlots) - 1);
+    return 0;
+  }
+
+  if (!memorySlots [slot].p)
+    printf ("Can't free it, slot %d not in use\n", slot);
+  else
+  {
+    free (memorySlots [slot].p);
+    memorySlots [slot].p = NULL;
+    memorySlots [slot].size = 0;
+  }
+
+  return 0;
+}
+
+static int monitorMemList (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+  unsigned int i;
+
+  printf ("Slot  Address     Size\n");
+  printf ("----------------------\n");
+
+  for (i = 0; i < arrsizeof (memorySlots); i++)
+    printf ("%4d  0x%08x  %d\n", i, (unsigned int) memorySlots [i].p, memorySlots [i].size);
+
+  return 0;
+}
+
+//
+//
+//
+static int monitorMiscSizeof (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+  printf ("sizeof (char)      = %lu\n", sizeof (char));
+  printf ("sizeof (short)     = %lu\n", sizeof (short));
+  printf ("sizeof (int)       = %lu\n", sizeof (int));
+  printf ("sizeof (long)      = %lu\n", sizeof (long));
+  printf ("sizeof (long long) = %lu\n", sizeof (long long));
+  printf ("sizeof (float)     = %lu\n", sizeof (float));
+  printf ("sizeof (double)    = %lu\n", sizeof (double));
+  printf ("sizeof (void *)    = %lu\n", sizeof (void *));
+
+  return 0;
+}
+
+//
+//
+//
+static int monitorRTCGet (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+  time_t now;
+  char buffer [32];
+
+  now = time (NULL);
+  ctime_r (&now, buffer);
+  printf ("%s", buffer);
+
+  return 0;
+}
+
+//
+//  This works because atoi() stops on a non-digit.  We already know the 
+//  string values are digits, because of isGoodString().
+//
+static int tmSetElement (int *element, int minValue, int maxValue, int adjustValue, char *s)
+{
+  int v;
+  
+  if (((v = atoi (s)) < minValue) || (v > maxValue))
+  {
+    printf ("Illegal value encountered in parameter\n");
+    return FALSE;
+  }
+
+  *element = (v + adjustValue);
+
+  return TRUE;
+}
+
+static int isGoodString (char *s, char *fmt)
+{
+  unsigned int i;
+  unsigned int l;
+
+  if ((l = strlen (s)) != strlen (fmt))
+    return FALSE;
+
+  for (i = 0; i < l; i++, s++, fmt++)
+  {
+    if (*fmt == 'N')
+    {
+      if (!isdigit (*s))
+        return FALSE;
+    }
+    else if (*fmt != *s)
+      return FALSE;
+  }
+
+  return TRUE;
+}
+
+static int monitorRTCSet (int argc, portCHAR **argv)
+{
+  if ((argc == 1) && !strcmp (argv [0], "gps"))
+  {
+    gpsData_t gpsData;
+
+    if (gpsCopyData (&gpsData))
+    {
+      if (gpsData.valid)
+      {
+        struct tm tm;
+
+        tm.tm_sec   = gpsData.utcSeconds;
+        tm.tm_min   = gpsData.utcMinutes;
+        tm.tm_hour  = gpsData.utcHours;
+        tm.tm_mday  = gpsData.utcDay;
+        tm.tm_mon   = gpsData.utcMonth - 1;
+        tm.tm_year  = gpsData.utcYear - 1900;
+        tm.tm_wday  = 0;
+        tm.tm_yday  = 0;
+        tm.tm_isdst = 0;
+
+        rtcSetEpochSeconds (mktime (&tm));
+
+        printf ("Date/time set from GPS\n");
+      }
+      else
+        printf ("GPS data not valid\n");
+    }
+    else
+      printf ("Unable to get GPS data\n");
+  }
+  else if (isGoodString (argv [0], "NNNN/NN/NN") && isGoodString (argv [1], "NN:NN:NN"))
+  {
+    struct tm tm;
+
+    if (!tmSetElement (&tm.tm_year, 1900, 2038, -1900, &argv [0][0]))
+      return 0;
+    if (!tmSetElement (&tm.tm_mon, 1, 12, -1, &argv [0][5]))
+      return 0;
+    if (!tmSetElement (&tm.tm_mday, 1, 31, 0, &argv [0][8]))
+      return 0;
+    if (!tmSetElement (&tm.tm_hour, 0, 23, 0, &argv [1][0]))
+      return 0;
+    if (!tmSetElement (&tm.tm_min, 0, 59, 0, &argv [1][3]))
+      return 0;
+    if (!tmSetElement (&tm.tm_sec, 0, 59, 0, &argv [1][6]))
+      return 0;
+
+    tm.tm_wday  = 0;
+    tm.tm_yday  = 0;
+    tm.tm_isdst = 0;
+
+    rtcSetEpochSeconds (mktime (&tm));
+  }
+  else
+    printf ("Parameter(s) either not 'gps' or not 'YYYYY/MM/DD HH:MM:SS'\n");
+
+  return 0;
+}
+
+static int monitorRTCAlarm (int argc, portCHAR **argv)
+{
+  if (argc == 0)
+  {
+    time_t a;
+
+    if ((a = rtcGetAlarmEpochSeconds ()))
+    {
+      char buffer [32];
+      ctime_r (&a, buffer);
+      printf ("%s", buffer);
+    }
+    else
+      printf ("alarm not enabled\n");
+  }
+  else if (argc == 1)
+  {
+    if (!strcmp (argv [0], "off"))
+      rtcSetAlarm (NULL);
+    else
+      printf ("'rtc alarm' requires either 'off' or 'YYYY/MM/DD HH:MM:SS' as arguments\n");
+  }
+  else if (isGoodString (argv [0], "NNNN/NN/NN") && isGoodString (argv [1], "NN:NN:NN"))
+  {
+    struct tm tm;
+
+    if (!tmSetElement (&tm.tm_year, 1900, 2038, -1900, &argv [0][0]))
+      return 0;
+    if (!tmSetElement (&tm.tm_mon, 1, 12, -1, &argv [0][5]))
+      return 0;
+    if (!tmSetElement (&tm.tm_mday, 1, 31, 0, &argv [0][8]))
+      return 0;
+    if (!tmSetElement (&tm.tm_hour, 0, 23, 0, &argv [1][0]))
+      return 0;
+    if (!tmSetElement (&tm.tm_min, 0, 59, 0, &argv [1][3]))
+      return 0;
+    if (!tmSetElement (&tm.tm_sec, 0, 59, 0, &argv [1][6]))
+      return 0;
+
+    if (rtcSetAlarm (&tm))
+      printf ("Cannot set the alarm for the past\n");
+  }
+  else
+    printf ("Parameter(s) either not 'off' or not 'YYYYY/MM/DD HH:MM:SS'\n");
+
+  return 0;
+}
+
+static int monitorRTCPeriodic (int argc, portCHAR **argv)
+{
+  if (!argc)
+    printf ("Current periodic alarm state is %s\n", rtcPeriodicAlarm (-1) ? "on" : "off");
+  else if (!strcmp (argv [0], "off"))
+    rtcPeriodicAlarm (0);
+  else if (!strcmp (argv [0], "on"))
+    rtcPeriodicAlarm (1);
+  else
+    printf ("Error: if argument present, must be 'off' or 'on'\n");
+
+  return 0;
+}
+
+//
+//
+//
+static inline unsigned long monitorSWICommon (unsigned long swi);
+static inline unsigned long monitorSWICommon (unsigned long swi)
+{
+  unsigned long result;
+
+  SWICALL (swi, result);
+
+  return result;
+}
+
+static inline unsigned long monitorSWICommon2 (unsigned long swi, unsigned long state);
+static inline unsigned long monitorSWICommon2 (unsigned long swi, unsigned long state)
+{
+  unsigned long result;
+
+  SWICALL1 (swi, state, result);
+
+  return result;
+}
+
+int monitorSWISetAsm (int argc __attribute__ ((unused)), portCHAR **argv)
+{
+  unsigned int state;
+
+  if (!strcmp (argv [0], "on"))
+    state = 0;
+  else if (!strcmp (argv [0], "off"))
+    state = 1;
+  else 
+  {
+    printf ("State must be 'on' or 'off'\n");
+    return 0;
+  }
+  
+  printf ("Setting LED2 %s via C, previous state was %s\n", state ? "off" : "on", monitorSWICommon2 (SWICALL_A_LED2SET, state) ? "off" : "on");
+
+  return 0;
+}
+
+int monitorSWIOnAsm (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+  printf ("Setting LED2 on via assembly, previous state was %s\n", monitorSWICommon (SWICALL_A_LED2ON) ? "off" : "on");
+
+  return 0;
+}
+
+int monitorSWIOffAsm (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+  printf ("Setting LED2 off via assembly, previous state was %s\n", monitorSWICommon (SWICALL_A_LED2OFF) ? "off" : "on");
+
+  return 0;
+}
+
+int monitorSWIToggleAsm (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+  printf ("Toggling LED2 via assembly, previous state was %s\n", monitorSWICommon (SWICALL_A_LED2TOGGLE) ? "off" : "on");
+
+  return 0;
+}
+
+int monitorSWISetC (int argc __attribute__ ((unused)), portCHAR **argv)
+{
+  unsigned int state;
+
+  if (!strcmp (argv [0], "on"))
+    state = 0;
+  else if (!strcmp (argv [0], "off"))
+    state = 1;
+  else 
+  {
+    printf ("State must be 'on' or 'off'\n");
+    return 0;
+  }
+  
+  printf ("Setting LED2 %s via C, previous state was %s\n", state ? "off" : "on", monitorSWICommon2 (SWICALL_C_LED2SET, state) ? "off" : "on");
+
+  return 0;
+}
+
+int monitorSWIOnC (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+  printf ("Setting LED2 on via C, previous state was %s\n", monitorSWICommon (SWICALL_C_LED2ON) ? "off" : "on");
+
+  return 0;
+}
+
+int monitorSWIOffC (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+  printf ("Setting LED2 off via C, previous state was %s\n", monitorSWICommon (SWICALL_C_LED2OFF) ? "off" : "on");
+
+  return 0;
+}
+
+int monitorSWIToggleC (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+  printf ("Toggling LED2 via C, previous state was %s\n", monitorSWICommon (SWICALL_C_LED2TOGGLE) ? "off" : "on");
+
+  return 0;
+}
+
+//
+//
+//
+int monitorWDTTest (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+  printf ("The watchdog is disabled, by default.  This command enables the watchdog, and if\n"
+          "no command is typed for 10 seconds, the watchdog will cause the system reset.\n"
+          "The 10 seconds is based on a 48Mhz PCLK (12Mhz xtal, PLL x 4, VBPDIV = /1).  The\n"
+          "'wdt status' command will show the cause of a system reset.  RSIR is reset by\n"
+          "this command.\n");
+
+  SCB_RSIR = SCB_RSIR_MASK;
+  WD_MOD = WD_MOD_WDEN | WD_MOD_RESET;
+  WD_TC = 120000000;
+  WD_FEED = WD_FEED_FEED1;
+  WD_FEED = WD_FEED_FEED2;
+
+  return 0;
+}
+
+int monitorWDTStatus (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+  int regRSIR = SCB_RSIR;
+  int regWDMOD = WD_MOD;
+  int regWDTC = WD_TC;
+  int regWDTV = WD_TV;
+
+  printf ("Watchdog enabled .................. : %s\n", (regWDMOD & WD_MOD_WDEN) ? "Yes" : "No");
+  printf ("Watchdog timeout generates reset .. : %s\n", (regWDMOD & WD_MOD_RESET) ? "Yes" : "No");
+  printf ("Watchdog timeout (in PCLK/4's) .... : %d\n", regWDTC);
+  printf ("Watchdog timeout counter .......... : %d\n", regWDTV);
+  printf ("\n");
+  printf ("Reset because of POR .............. : %s\n", (regRSIR & SCB_RSIR_POR) ? "Yes" : "No");
+  printf ("Reset because of /RESET ........... : %s\n", (regRSIR & SCB_RSIR_EXTR) ? "Yes" : "No");
+  printf ("Reset because of watchdog ......... : %s\n", (regRSIR & SCB_RSIR_WDTR) ? "Yes" : "No");
+  printf ("Reset because of BOD .............. : %s\n", (regRSIR & SCB_RSIR_BODR) ? "Yes" : "No");
+
+  return 0;
+}
+
+int monitorWDTClear (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+  SCB_RSIR = SCB_RSIR_MASK;
+  WD_MOD = 0;
+
+  return 0;
+}
+
+//
+//
+//
+static int monitorVersion (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+  printf ("LPC-P2148 Demo, Version " __VERSION ", " __DATE__ " " __TIME__ "\n");
+  printf ("Copyright (c) 2007, J.C. Wren\n");
+
+  return 0;
+}
+
+//
+//
+//
+#if defined CFG_CONSOLE_USB || defined CFG_CONSOLE_UART1
+static void monitorReassignFD (FILE *fp, int fd);
+static void monitorReassignFD (FILE *fp, int fd)
+{
+  fp->_file = fd;
+}
+#endif
+
+static void argsDispatch (commandList_t *cl, int argc, char **argv)
+{
+  activeCommandList = cl;
+
+  while (cl->command)
+  {
+    if (!strcmp (cl->command, argv [0]))
+    {
+      if ((argc == 2) && !strcmp (argv [1], "?"))
+        printf ("%s\n", cl->parameters);
+      else if ((argc - 1) < cl->minArgs)
+        printf ("Too few arguments to command (%d expected)\n", cl->minArgs);
+      else if (cl->cmdType == CMDTYPE_CMDLIST)
+        argsDispatch (cl->commandList, argc - 1, &argv [1]);
+      else if ((argc - 1) > cl->maxArgs)
+        printf ("Too many arguments to command (%d maximum)\n", cl->maxArgs);
+      else
+        (*cl->handler) (argc - 1, &argv [1]);
+
+      return;
+    }
+
+    cl++;
+  }
+
+  if (!cl->command)
+    printf ("Unknown command \"%s\"\n", argv [0]);
+}
+
+portTASK_FUNCTION (vMonitorTask, pvParameters __attribute__ ((unused)))
+{
+  static U8 buffer [256];
+  static portCHAR *argv [34];
+  int argc;
+  int fd = fileno (stdin);
+
+  fclose (stderr);
+  stderr = stdout;
+
+#if defined CFG_CONSOLE_USB
+  fd = open ("/dev/usb", O_RDWR);
+#elif defined CFG_CONSOLE_UART1
+  fd = open ("/dev/uart1", O_RDWR);
+#endif
+
+#if defined CFG_CONSOLE_USB || defined CFG_CONSOLE_UART1
+  monitorReassignFD (stdin, fd);
+  monitorReassignFD (stdout, fd);
+#endif
+
+  monitorVersion (0, NULL);
+
+#ifndef CFG_USB_MSC
+  //
+  //  If CFG_USB_MSC defined, this gets done by mscblockInit()
+  //
+  {
+    FRESULT f;
+
+    if ((f = diskInitialize (0)) != FR_OK)
+      f_printerror (f);
+  }
+#endif
+
+  for (;;)
+  {
+    int l;
+
+    if ((l = argsGetLine (fd, buffer, sizeof (buffer))))
+    {
+      if ((l == 1) && ((buffer [0] == 0xfe) || (buffer [0] == 0xff)))
+      {
+        int type = buffer [0];
+        time_t now = time (NULL);
+        ctime_r (&now, (char *) buffer);
+        printf ("%s -- %s", (type == 0xfe) ? "ALARM" : "PERIODIC", buffer);
+      }
+      else if (argsParse ((char *) buffer, argv, sizeof (argv), &argc))
+        printf ("Too many arguments (max %ld)\n", arrsizeof (argv));
+      else if (argv [0])
+        argsDispatch (commandList, argc, &argv [0]);
+    }
+
+    WD_FEED = WD_FEED_FEED1;
+    WD_FEED = WD_FEED_FEED2;
+  }
+}
diff --git a/monitor/monitor.h b/monitor/monitor.h
new file mode 100644 (file)
index 0000000..0bcf3a5
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef _MONITOR_H_
+#define _MONITOR_H_
+
+portTASK_FUNCTION_PROTO (vMonitorTask, pvParameters __attribute__ ((unused)));
+
+#endif
diff --git a/newlib/Makefile b/newlib/Makefile
new file mode 100644 (file)
index 0000000..5a58c7d
--- /dev/null
@@ -0,0 +1,25 @@
+SRC_FILES=syscalls.c
+
+#
+# Define all object files.
+#
+ARM_OBJ = $(SRC_FILES:.c=.o)
+
+.PHONY: all
+all: $(ARM_OBJ)
+
+$(ARM_OBJ) : %.o : %.c Makefile .depend
+       $(CC) -c $(CFLAGS) $< -o $@
+       $(AR) r $(COMMON)/common.a $@
+
+#
+#  The .depend files contains the list of header files that the
+#  various source files depend on.  By doing this, we'll only
+#  rebuild the .o's that are affected by header files changing.
+#
+.depend:
+                       $(CC) $(CFLAGS) -M $(SRC_FILES) > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff --git a/newlib/syscalls.c b/newlib/syscalls.c
new file mode 100644 (file)
index 0000000..a7d743d
--- /dev/null
@@ -0,0 +1,732 @@
+//
+//  Support files for GNU libc.  Files in the system namespace go here.
+//  Files in the C namespace (ie those that do not start with an underscore) go in .c
+//  
+#include <_ansi.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/times.h>
+#include <errno.h>
+#include <reent.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include "FreeRTOS.h"
+#include "task.h"
+#include "../uart/uart.h"
+#include "../usbser/usbser.h"
+#include "../rtc/rtc.h"
+#include "../fatfs/ff.h"
+
+//
+//  Forward prototypes
+//
+int     _mkdir        _PARAMS ((const char *, mode_t));
+int     _chmod        _PARAMS ((const char *, mode_t));
+int     _read         _PARAMS ((int, char *, int));
+int     _lseek        _PARAMS ((int, int, int));
+int     _write        _PARAMS ((int, const char *, int));
+int     _open         _PARAMS ((const char *, int, ...));
+int     _close        _PARAMS ((int));
+int     _kill         _PARAMS ((int, int));
+void    _exit         _PARAMS ((int));
+int     _getpid       _PARAMS ((int));
+caddr_t _sbrk         _PARAMS ((int));
+int     _fstat        _PARAMS ((int, struct stat *));
+int     _stat         _PARAMS ((const char *, struct stat *));
+int     _link         _PARAMS ((void));
+int     _unlink       _PARAMS ((const char *));
+void    _raise        _PARAMS ((void));
+int     _gettimeofday _PARAMS ((struct timeval *, struct timezone *));
+clock_t _times        _PARAMS ((struct tms *));
+int     isatty        _PARAMS ((int));
+int     _rename       _PARAMS ((const char *, const char *));
+int     _system       _PARAMS ((const char *));
+void    _sync         _PARAMS ((void));
+void    syscallsInit  _PARAMS ((void));
+
+int     rename        _PARAMS ((const char *, const char *));
+
+static int  set_errno             _PARAMS ((int));
+static time_t fatfs_time_to_timet _PARAMS ((FILINFO *));
+static int  remap_handle          _PARAMS ((int));
+static int  findslot              _PARAMS ((int));
+
+//
+//  Register name faking - works in collusion with the linker
+//
+register char *stack_ptr asm ("sp");
+
+//
+//  Following is copied from libc/stdio/local.h to check std streams 
+//
+extern void _EXFUN (__sinit,( struct _reent *));
+
+#define CHECK_INIT(ptr)            \
+do                                 \
+{                                  \
+  if ((ptr) && !(ptr)->__sdidinit) \
+  __sinit (ptr);                   \
+}                                  \
+while (0)
+
+//
+//  Adjust our internal handles to stay away from std* handles
+//
+#define FILE_HANDLE_OFFSET (0x20)
+
+#define MONITOR_STDIN  0
+#define MONITOR_STDOUT 1
+#define MONITOR_STDERR 2
+#define MONITOR_UART0  3
+#define MONITOR_UART1  4
+#define MONITOR_USB    5
+#define MONITOR_FATFS  6
+
+// 
+//
+//
+typedef struct
+{
+  int handle;
+  int pos;
+  int flags;
+  FIL *fatfsFCB;
+}
+openFiles_t;
+
+//
+//
+//
+#define MAX_OPEN_FILES 10
+static openFiles_t openfiles [MAX_OPEN_FILES];
+
+static int findslot (int fh)
+{
+  static int slot;
+  static int lastfh = -1;
+
+  if ((fh != -1) && (fh == lastfh))
+    return slot;
+
+  for (slot = 0; slot < MAX_OPEN_FILES; slot++)
+    if (openfiles [slot].handle == fh)
+      break;
+
+  lastfh = fh;
+
+  return slot;
+}
+
+//
+//  Function to convert std(in|out|err) handles to internal versions.  
+//
+static int remap_handle (int fh)
+{
+  CHECK_INIT(_REENT);
+
+  if (fh == STDIN_FILENO)
+    return MONITOR_STDIN;
+  if (fh == STDOUT_FILENO)
+    return MONITOR_STDOUT;
+  if (fh == STDERR_FILENO)
+    return MONITOR_STDERR;
+
+  return fh - FILE_HANDLE_OFFSET;
+}
+
+static int remap_fatfs_errors (FRESULT f)
+{
+  switch (f)
+  {
+    case FR_NO_FILE         : errno = ENOENT;   break;
+    case FR_NO_PATH         : errno = ENOENT;   break;
+    case FR_INVALID_NAME    : errno = EINVAL;   break;
+    case FR_INVALID_DRIVE   : errno = ENODEV;   break;
+    case FR_DENIED          : errno = EACCES;   break;
+    case FR_EXIST           : errno = EEXIST;   break;
+    case FR_NOT_READY       : errno = EIO;      break;
+    case FR_WRITE_PROTECTED : errno = EACCES;   break;
+    case FR_RW_ERROR        : errno = EIO;      break;
+    case FR_NOT_ENABLED     : errno = EIO;      break;
+    case FR_NO_FILESYSTEM   : errno = EIO;      break;
+    case FR_INVALID_OBJECT  : errno = EBADF;    break;
+    default                 : errno = EIO;      break;
+  }
+
+  return -1;
+}
+
+static time_t fatfs_time_to_timet (FILINFO *f)
+{
+  struct tm tm;
+
+  tm.tm_sec  =  (f->ftime & 0x001f) << 1;
+  tm.tm_min  =  (f->ftime & 0x07e0) >> 5;
+  tm.tm_hour =  (f->ftime & 0xf800) >> 11;
+  tm.tm_mday =  (f->fdate & 0x001f);
+  tm.tm_mon  = ((f->fdate & 0x01e0) >> 5) - 1;
+  tm.tm_year = ((f->fdate & 0xfe00) >> 9) + 80;
+  tm.tm_isdst = 0;
+
+  return mktime (&tm);
+}
+
+static int set_errno (int errval)
+{
+  errno = errval;
+
+  return -1;
+}
+
+void syscallsInit (void)
+{
+  int slot;
+  static int initialized = 0;
+
+  if (initialized)
+    return;
+
+  initialized = 1;
+
+  __builtin_memset (openfiles, 0, sizeof (openfiles));
+
+  for (slot = 0; slot < MAX_OPEN_FILES; slot++)
+    openfiles [slot].handle = -1;
+
+  openfiles [0].handle = MONITOR_STDIN;
+  openfiles [1].handle = MONITOR_STDOUT;
+  openfiles [2].handle = MONITOR_STDERR;
+}
+
+int _mkdir (const char *path, mode_t mode __attribute__ ((unused)))
+{
+  FRESULT f;
+
+  if ((f = f_mkdir (path)) != FR_OK)
+    return remap_fatfs_errors (f);
+
+  return 0;
+}
+
+int _chmod (const char *path, mode_t mode)
+{
+  FRESULT f;
+
+  if ((f = f_chmod (path, (mode & S_IWUSR) ? 0 : AM_RDO, AM_RDO)) != FR_OK)
+    return remap_fatfs_errors (f);
+
+  return 0;
+}
+
+int _read (int fd, char *ptr, int len)
+{
+  int i;
+  int fh;
+  int slot;
+  portTickType xBlockTime;
+  int bytesUnRead = -1;
+
+  if ((slot = findslot (fh = remap_handle (fd))) == MAX_OPEN_FILES)
+    return set_errno (EBADF);
+
+  if (openfiles [slot].flags & O_WRONLY)
+    return set_errno (EBADF);
+
+  xBlockTime = (openfiles [slot].flags & O_NONBLOCK) ? 0 : portMAX_DELAY;
+
+  switch (fh)
+  {
+    case MONITOR_STDIN :
+      {
+        for (i = 0; i < len; i++)
+          if (!uartGetChar (0, (signed portCHAR *) ptr++, xBlockTime))
+            break;
+
+        bytesUnRead = len - i;
+      }
+      break;
+
+    case MONITOR_STDOUT :
+    case MONITOR_STDERR :
+      break;
+
+    case MONITOR_UART0 :
+      {
+        for (i = 0; i < len; i++)
+          if (!uartGetChar (0, (signed portCHAR *) ptr++, xBlockTime))
+            break;
+
+        bytesUnRead = len - i;
+      }
+      break;
+
+    case MONITOR_UART1 :
+      {
+        for (i = 0; i < len; i++)
+          if (!uartGetChar (1, (signed portCHAR *) ptr++, xBlockTime))
+            break;
+
+        bytesUnRead = len - i;
+      }
+      break;
+
+    case MONITOR_USB :
+      {
+        for (i = 0; i < len; i++)
+          if (!usbserGetChar ((signed portCHAR *) ptr++, xBlockTime))
+            break;
+
+        bytesUnRead = len - i;
+      }
+      break;
+
+    default :
+      {
+        if (openfiles [slot].fatfsFCB)
+        {
+          FRESULT f;
+          U16 fatfsBytesRead;
+
+          if ((f = f_read (openfiles [slot].fatfsFCB, ptr, len, &fatfsBytesRead)) != FR_OK)
+            return remap_fatfs_errors (f);
+
+          bytesUnRead = len - fatfsBytesRead;
+        }
+      }      
+      break;
+  }
+
+  if (bytesUnRead < 0)
+    return -1;
+
+  openfiles [slot].pos += len - bytesUnRead;
+
+  return len - bytesUnRead;
+}
+
+int _lseek (int fd, int ptr, int dir)
+{
+  int fh;
+  int slot;
+  FRESULT f = FR_INVALID_OBJECT;
+
+  if (((slot = findslot (fh = remap_handle (fd))) == MAX_OPEN_FILES) || !openfiles [slot].fatfsFCB)
+    return set_errno (EBADF);
+
+  if (dir == SEEK_SET)
+    f = f_lseek (openfiles [slot].fatfsFCB, ptr); 
+  else if (dir == SEEK_CUR)
+    f = f_lseek (openfiles [slot].fatfsFCB, openfiles [slot].fatfsFCB->fptr + ptr); 
+  else if (dir == SEEK_END)
+    f = f_lseek (openfiles [slot].fatfsFCB, openfiles [slot].fatfsFCB->fsize + ptr); 
+
+  if (f != FR_OK)
+    return remap_fatfs_errors (f);
+
+  return openfiles [slot].pos = openfiles [slot].fatfsFCB->fptr;
+}
+
+int _write (int fd, const char *ptr, int len)
+{
+  int i;
+  int fh;
+  int slot;
+  portTickType xBlockTime;
+  int bytesUnWritten = -1;
+
+  if ((slot = findslot (fh = remap_handle (fd))) == MAX_OPEN_FILES)
+    return set_errno (EBADF);
+
+  if (openfiles [slot].flags & O_RDONLY)
+    return set_errno (EBADF);
+
+  xBlockTime = (openfiles [slot].flags & O_NONBLOCK) ? 0 : portMAX_DELAY;
+  
+  switch (fh)
+  {
+    case MONITOR_STDIN :
+      break;
+
+    case MONITOR_STDOUT :
+    case MONITOR_STDERR :
+      {
+        for (i = 0; i < len; i++)
+        {
+          if (*ptr == '\n')
+            if (!uartPutChar (0, '\r', xBlockTime))
+              break;
+          if (!uartPutChar (0, *ptr++, xBlockTime))
+            break;
+        }
+
+        bytesUnWritten = len - i;
+      }
+      break;
+
+    case MONITOR_UART0 :
+      {
+        for (i = 0; i < len; i++)
+          if (!uartPutChar (0, *ptr++, xBlockTime))
+            break;
+
+        bytesUnWritten = len - i;
+      }
+      break;
+
+    case MONITOR_UART1 :
+      {
+        for (i = 0; i < len; i++)
+        {
+#ifdef CFG_CONSOLE_UART1
+          if (*ptr == '\n')
+            if (!uartPutChar (1, '\r', xBlockTime))
+              break;
+#endif
+          if (!uartPutChar (1, *ptr++, xBlockTime))
+            break;
+        }
+
+        bytesUnWritten = len - i;
+      }
+      break;
+
+    case MONITOR_USB :
+      {
+        for (i = 0; i < len; i++)
+        {
+#ifdef CFG_CONSOLE_USB
+          if (*ptr == '\n')
+            if (!usbserPutChar ('\r', xBlockTime))
+              break;
+#endif
+          if (!usbserPutChar (*ptr++, xBlockTime))
+            break;
+        }
+
+        bytesUnWritten = len - i;
+      }
+      break;
+
+    default :
+      {
+        if (openfiles [slot].fatfsFCB)
+        {
+          FRESULT f;
+          U16 fatfsBytesWritten;
+
+          if ((f = f_write (openfiles [slot].fatfsFCB, ptr, len, &fatfsBytesWritten)) != FR_OK)
+            return remap_fatfs_errors (f);
+
+          bytesUnWritten = len - fatfsBytesWritten;
+        }
+        else
+          return set_errno (EBADF);
+      }
+      break;
+  }
+
+  if (bytesUnWritten == -1 || bytesUnWritten == len)
+    return -1;
+
+  openfiles [slot].pos += len - bytesUnWritten;
+
+  return len - bytesUnWritten;
+}
+
+int _open (const char *path, int flags, ...)
+{
+  int fh = 0;
+  int slot;
+
+  if ((slot = findslot (-1)) == MAX_OPEN_FILES)
+    return set_errno (ENFILE);
+
+  if (flags & O_APPEND)
+    flags &= ~O_TRUNC;
+
+  if (!__builtin_strcmp (path, "/dev/uart0"))
+    fh = MONITOR_UART0;
+  else if (!__builtin_strcmp (path, "/dev/uart1"))
+    fh = MONITOR_UART1;
+  else if (!__builtin_strcmp (path, "/dev/usb"))
+    fh = MONITOR_USB;
+  else
+  {
+    U8 fatfsFlags = FA_OPEN_EXISTING;
+    FRESULT f;
+
+    //
+    // FA_OPEN_EXISTING Opens the file. The function fails if the file is not existing. (Default)
+    // FA_OPEN_ALWAYS   Opens the file, if it is existing. If not, the function creates the new file.
+    // FA_CREATE_NEW    Creates a new file. The function fails if the file is already existing.
+    // FA_CREATE_ALWAYS Creates a new file. If the file is existing, it is truncated and overwritten.
+    //
+    // O_CREAT If the file does not exist it will be created.
+    // O_EXCL  When used with O_CREAT, if the file already exists it is an error and the open() will fail.
+    // O_TRUNC If the file already exists and is a regular file and the open mode allows writing (i.e., is O_RDWR or O_WRONLY) it will be truncated to length 0. 
+    //
+    if (((flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC)) && (flags & (O_RDWR | O_WRONLY)))
+      fatfsFlags = FA_CREATE_ALWAYS;
+    else if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
+      fatfsFlags = FA_OPEN_EXISTING;
+    else if ((flags & O_CREAT) == O_CREAT)
+      fatfsFlags = FA_OPEN_ALWAYS;
+    else if ((flags == O_RDONLY) || (flags == O_WRONLY) || (flags == O_RDWR))
+      fatfsFlags = FA_OPEN_EXISTING;
+    else
+      return set_errno (EINVAL);
+
+    if ((flags & O_ACCMODE) == O_RDONLY)
+      fatfsFlags |= FA_READ;
+    else if ((flags & O_ACCMODE) == O_WRONLY)
+      fatfsFlags |= FA_WRITE;
+    else if ((flags & O_ACCMODE) == O_RDWR)
+      fatfsFlags |= (FA_READ | FA_WRITE);
+    else
+      return set_errno (EINVAL);
+
+    fh = -1;
+    errno = EIO;
+
+    if (!openfiles [slot].fatfsFCB)
+      if ((openfiles [slot].fatfsFCB = __builtin_calloc (1, sizeof (FIL))))
+        if ((fh = ((f = f_open (openfiles [slot].fatfsFCB, path, fatfsFlags)) == FR_OK) ? (slot + MONITOR_FATFS) : -1) == -1)
+          return remap_fatfs_errors (f);
+  }
+
+  if (fh >= 0)
+  {
+    openfiles [slot].handle = fh;
+    openfiles [slot].pos = 0;
+    openfiles [slot].flags = flags;
+  }
+
+  return fh >= 0 ? (fh + FILE_HANDLE_OFFSET) : -1;
+}
+
+int _close (int fd)
+{
+  int slot;
+
+  if ((slot = findslot (remap_handle (fd))) == MAX_OPEN_FILES)
+    return set_errno (EBADF);
+
+  openfiles [slot].handle = -1;
+
+  if (openfiles [slot].fatfsFCB)
+  {
+    FRESULT f;
+
+    f = f_close (openfiles [slot].fatfsFCB);
+    free (openfiles [slot].fatfsFCB);
+    openfiles [slot].fatfsFCB = NULL;
+
+    if (f != FR_OK)
+      return remap_fatfs_errors (f);
+  }
+
+  return 0;
+}
+
+int _kill (int pid __attribute__ ((unused)), int sig __attribute__ ((unused)))
+{
+  return set_errno (ENOTSUP);
+}
+
+void _exit (int status)
+{
+  /* There is only one SWI for both _exit and _kill. For _exit, call
+     the SWI with the second argument set to -1, an invalid value for
+     signum, so that the SWI handler can distinguish the two calls.
+      Note: The RDI implementation of _kill throws away both its
+      arguments.  */
+  _kill (status, -1);
+
+  while (1);
+}
+
+int _getpid (int n)
+{
+  return 1;
+  n = n;
+}
+
+caddr_t _sbrk (int incr)
+{
+  extern char end asm ("end");  /* Defined by the linker.  */
+  extern unsigned long __heap_max;
+  static char *heap_end;
+  char *prev_heap_end;
+  char *eom;
+
+  if (!heap_end)
+    heap_end = & end;
+
+  prev_heap_end = heap_end;
+
+  //
+  //  If FreeRTOS is not running, the stack pointer will be in the SVC region,
+  //  and therefore greater than the start of the heap (end of .bss).  In this
+  //  case, we see if the heap allocation will run past the current stack
+  //  pointer, and if so, return ENOMEM (this does not guarantee subsequent
+  //  stack operations won't overflow into the heap!).  
+  //
+  //  If FreeRTOS is running, then we define the end of the heap to be the
+  //  start of end of the supervisor stack (since FreeRTOS is running, the
+  //  system stack, and very little of the supervisor stack space is used).
+  //
+  eom = (stack_ptr > & end) ? stack_ptr : (char *) __heap_max;
+
+  if (heap_end + incr > eom)
+  {
+    errno = ENOMEM;
+    return (caddr_t) -1;
+  }
+
+  heap_end += incr;
+
+  return (caddr_t) prev_heap_end;
+}
+
+//
+//  Tihs is a problem.  FatFS has no way to go from a file handle back to a file,
+//  since file name information isn't stored with the handle.  Tried to think of
+//  a good way to handle this, couldn't come up with anything.  For now, it
+//  returns ENOSYS (not implemented).
+//
+int _fstat (int fd __attribute__ ((unused)), struct stat *st __attribute__ ((unused)))
+{
+  return set_errno (ENOSYS);
+}
+
+int _stat (const char *fname, struct stat *st)
+{
+  FRESULT f;
+  FILINFO fi;
+
+  if ((f = f_stat (fname, &fi)) != FR_OK)
+    return remap_fatfs_errors (f);
+
+  __builtin_memset (st, 0, sizeof (* st));
+
+  st->st_mode |= (fi.fattrib & AM_DIR) ? S_IFDIR : S_IFREG;
+  st->st_mode |= (fi.fattrib & AM_RDO) ? ((S_IRWXU & ~S_IWUSR) | (S_IRWXG & ~S_IWGRP) | (S_IRWXO & ~S_IWOTH)) : (S_IRWXU | S_IRWXG | S_IRWXO);
+  st->st_size = fi.fsize;
+  st->st_ctime = fatfs_time_to_timet (&fi);
+  st->st_mtime = st->st_ctime;
+  st->st_atime = st->st_ctime;
+  st->st_blksize = 512;
+
+  return 0;
+}
+
+//
+//  FatFS and FAT file systems don't support links
+//
+int _link (void)
+{
+  return set_errno (ENOSYS);
+}
+
+int _unlink (const char *path)
+{
+  FRESULT f;
+
+  if ((f = f_unlink (path)) != FR_OK)
+    return remap_fatfs_errors (f);
+
+  return 0;
+}
+
+void _raise (void)
+{
+  return;
+}
+
+int _gettimeofday (struct timeval *tp, struct timezone *tzp)
+{
+  unsigned int milliseconds;
+
+  if (tp)
+  {
+    tp->tv_sec = rtcGetEpochSeconds (&milliseconds);
+    tp->tv_usec = milliseconds * 1000;
+  }
+
+  //
+  //  Return fixed data for the timezone
+  //
+  if (tzp)
+  {
+    tzp->tz_minuteswest = 0;
+    tzp->tz_dsttime = 0;
+  }
+
+  return 0;
+}
+
+//
+//  Return a clock that ticks at 100Hz
+//
+clock_t _times (struct tms *tp)
+{
+  clock_t timeval = (clock_t) xTaskGetTickCount ();
+
+  if (tp)
+  {
+    tp->tms_utime  = timeval;
+    tp->tms_stime  = 0;
+    tp->tms_cutime = 0;
+    tp->tms_cstime = 0;
+  }
+
+  return timeval;
+};
+
+int isatty (int fd)
+{
+  return (fd <= 2) ? 1 : 0;  /* one of stdin, stdout, stderr */
+}
+
+int _system (const char *s)
+{
+  if (s == NULL)
+    return 0;
+
+  return set_errno (ENOSYS);
+}
+
+int _rename (const char *oldpath, const char *newpath)
+{
+  FRESULT f;
+
+  if ((f = f_rename (oldpath, newpath)))
+    return remap_fatfs_errors (f);
+
+  return 0;
+}
+
+//
+//  Default crossdev -t options for ARM newlib doesn't define HAVE_RENAME, so
+//  it's trying to use the link/unlink process.  FatFS doesn't support link(),
+//  so override the newlib rename() to make it work correctly.
+//
+int rename (const char *oldpath, const char *newpath)
+{
+  return _rename (oldpath, newpath);
+}
+
+void _sync (void)
+{
+  int slot;
+
+  for (slot = 0; slot < MAX_OPEN_FILES; slot++)
+    if (openfiles [slot].fatfsFCB)
+      f_sync (openfiles [slot].fatfsFCB);
+}
diff --git a/rtc/Makefile b/rtc/Makefile
new file mode 100644 (file)
index 0000000..bfd113d
--- /dev/null
@@ -0,0 +1,25 @@
+SRC_FILES=rtc.c rtcISR.c
+
+#
+# Define all object files.
+#
+ARM_OBJ = $(SRC_FILES:.c=.o)
+
+.PHONY: all
+all: $(ARM_OBJ)
+
+$(ARM_OBJ) : %.o : %.c Makefile .depend
+       $(CC) -c $(CFLAGS) $< -o $@
+       $(AR) r $(COMMON)/common.a $@
+
+#
+#  The .depend files contains the list of header files that the
+#  various source files depend on.  By doing this, we'll only
+#  rebuild the .o's that are affected by header files changing.
+#
+.depend:
+                       $(CC) $(CFLAGS) -M $(SRC_FILES) > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff --git a/rtc/rtc.c b/rtc/rtc.c
new file mode 100644 (file)
index 0000000..6ae6337
--- /dev/null
+++ b/rtc/rtc.c
@@ -0,0 +1,268 @@
+#include "FreeRTOS.h"
+#include "task.h"
+#include "queue.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sys/times.h>
+
+#include "rtcISR.h"
+#include "rtc.h"
+
+//
+//  Place RTC on 32kHz xtal and disconnect power.
+//
+static inline void rtcSleep (void)
+{
+  RTC_CCR = (RTC_CCR_CLKEN | RTC_CCR_CLKSRC);
+  SCB_PCONP &= ~SCB_PCONP_PCRTC;
+}
+
+//
+//  Prepare clock for interactive use.
+//
+static inline void rtcWake (void)
+{
+  RTC_CCR = (RTC_CCR_CLKEN | RTC_CCR_CLKSRC);
+  SCB_PCONP |= SCB_PCONP_PCRTC;
+}
+
+//
+//  Read clock registers and return tm structure.
+//
+static void rtcRead (struct tm *theTime, unsigned int *milliseconds)
+{
+  unsigned int ticks32Khz;
+  rtcCTIME0_t ctime0;
+  rtcCTIME1_t ctime1;
+  rtcCTIME2_t ctime2;
+
+  rtcWake ();
+  portENTER_CRITICAL ();
+
+  do
+  {
+    ctime0.i = RTC_CTIME0;
+    ctime1.i = RTC_CTIME1;
+    ctime2.i = RTC_CTIME2;
+
+    do
+      ticks32Khz = (RTC_CTC & 0xfffe);
+    while (ticks32Khz != (RTC_CTC & 0xfffe));
+  }
+  while (ctime0.i != RTC_CTIME0);
+
+  portEXIT_CRITICAL ();
+  rtcSleep ();
+
+  if (milliseconds)
+    *milliseconds = (((ticks32Khz / 2) * 1000u) / 32768u);
+
+  theTime->tm_sec   = ctime0.seconds;
+  theTime->tm_min   = ctime0.minutes;
+  theTime->tm_hour  = ctime0.hours;
+  theTime->tm_mday  = ctime1.dom;
+  theTime->tm_mon   = ctime1.month - 1;
+  theTime->tm_year  = ctime1.year - 1900;
+  theTime->tm_wday  = ctime0.dow;
+  theTime->tm_yday  = ctime2.doy - 1;
+  theTime->tm_isdst = 0;
+}
+
+//
+//  Set clock to new values.
+//
+static void rtcWrite (struct tm *newTime)
+{
+  rtcWake ();
+  portENTER_CRITICAL ();
+
+  RTC_CCR &= ~RTC_CCR_CLKEN;
+  RTC_CCR |=  RTC_CCR_CTCRST;
+
+  RTC_SEC   = newTime->tm_sec;
+  RTC_MIN   = newTime->tm_min;
+  RTC_HOUR  = newTime->tm_hour;
+  RTC_DOM   = newTime->tm_mday;
+  RTC_MONTH = newTime->tm_mon + 1;
+  RTC_YEAR  = newTime->tm_year + 1900;
+  RTC_DOW   = newTime->tm_wday;
+  RTC_DOY   = newTime->tm_yday + 1;
+
+  RTC_CCR &= ~RTC_CCR_CTCRST;
+  RTC_CCR |=  RTC_CCR_CLKEN;
+
+  portEXIT_CRITICAL ();
+  rtcSleep ();
+}
+
+//
+//
+//
+time_t rtcGetEpochSeconds (unsigned int *milliseconds)
+{
+  struct tm tm;
+
+  rtcRead (&tm, milliseconds);
+  return mktime (&tm);
+}
+
+void rtcSetEpochSeconds (time_t now)
+{
+  struct tm tm;
+
+  localtime_r (&now, &tm);
+  rtcWrite (&tm);
+}
+
+//
+//  Start clock so that the sytsem may use it.
+//
+static void rtcInitClockCalendar (void)
+{
+  int nonsense = 0;
+  rtcCTIME0_t ctime0;
+  rtcCTIME1_t ctime1;
+  rtcCTIME2_t ctime2;
+
+  rtcWake ();
+  
+  ctime0.i = RTC_CTIME0; 
+  ctime1.i = RTC_CTIME1; 
+  ctime2.i = RTC_CTIME2;
+
+  //
+  //  Leisurely tear the packed time apart into individual time.
+  //
+  if ((ctime0.seconds < 0) || (ctime0.seconds > 59))  nonsense = 1;
+  if ((ctime0.minutes < 0) || (ctime0.minutes > 59))  nonsense = 1;
+  if ((ctime0.hours < 0)   || (ctime0.hours > 23))    nonsense = 1;
+  if ((ctime1.dom < 1)     || (ctime1.dom > 31))      nonsense = 1;
+  if ((ctime1.month < 1)   || (ctime1.month > 12))    nonsense = 1;
+  if ((ctime1.year < 1980) || (ctime1.year > 2050))   nonsense = 1;
+  if ((ctime0.dow < 0)     || (ctime0.dow > 6))       nonsense = 1;
+  if ((ctime2.doy < 0)     || (ctime2.doy > 366))     nonsense = 1;
+
+  rtcSleep ();
+
+  //
+  //  Set the clock to Jan 1, 2006 00:00:00
+  //
+  if (nonsense) 
+    rtcSetEpochSeconds ((time_t) 1136073600);
+}
+
+//
+//
+//
+void rtcInit (void)
+{
+  rtcISRInit ();
+
+  SCB_PCONP |= SCB_PCONP_PCRTC;
+
+  RTC_CCR = 0;
+
+  RTC_CCR |= RTC_CCR_CLKSRC;
+
+  RTC_AMR = RTC_AMR_AMRMASK;
+  RTC_CIIR = 0;
+
+  RTC_ILR = RTC_ILR_MASK;
+
+  RTC_CCR |= RTC_CCR_CLKEN;
+
+  VIC_IntSelect &= ~VIC_IntSelect_RTC;
+#ifdef RTC_NONVECTOREDIRQ
+  VIC_DefVectAddr = (portLONG) rtcISR;
+#else
+  VIC_VectAddr6 = (portLONG) rtcISR;
+  VIC_VectCntl6 = VIC_VectCntl_ENABLE | VIC_Channel_RTC;
+#endif
+  VIC_IntEnable = VIC_IntEnable_RTC;
+
+  rtcInitClockCalendar ();
+}
+
+int rtcSetAlarm (struct tm *tm)
+{
+  if (tm && (mktime (tm) < time (NULL)))
+    return -1;
+
+  rtcWake ();
+
+  RTC_AMR = RTC_AMR_AMRMASK;
+
+  if (tm)
+  {
+    RTC_ALYEAR = tm->tm_year + 1900;
+    RTC_ALMON = tm->tm_mon + 1;
+    RTC_ALDOM = tm->tm_mday;
+    RTC_ALHOUR = tm->tm_hour;
+    RTC_ALMIN = tm->tm_min;
+    RTC_ALSEC = tm->tm_sec;
+    RTC_ALDOW = 0;
+    RTC_ALDOY = 0;
+
+    RTC_AMR = RTC_AMR_AMRDOW | RTC_AMR_AMRDOY;
+  }
+
+  rtcSleep ();
+
+  return 0;
+}
+
+struct tm *rtcGetAlarmTm (struct tm *tm)
+{
+  if (tm)
+  {
+    memset (tm, 0, sizeof (* tm));
+
+    rtcWake ();
+
+    if (RTC_AMR != RTC_AMR_AMRMASK)
+    {
+      tm->tm_year = RTC_ALYEAR - 1900;
+      tm->tm_mon = RTC_ALMON - 1;
+      tm->tm_mday = RTC_ALDOM;
+      tm->tm_hour = RTC_ALHOUR;
+      tm->tm_min = RTC_ALMIN;
+      tm->tm_sec = RTC_ALSEC;
+    }
+    else
+    {
+      time_t now = 0;
+      memcpy (tm, localtime (&now), sizeof (* tm));
+    }
+
+    rtcSleep ();
+  }
+
+  return tm;
+}
+
+time_t rtcGetAlarmEpochSeconds (void)
+{
+  struct tm tm;
+
+  return mktime (rtcGetAlarmTm (&tm));
+}
+
+int rtcPeriodicAlarm (int mode)
+{
+  int state;
+    
+  rtcWake ();
+
+  state = RTC_CIIR & RTC_CIIR_IMMIN;
+
+  if (!mode)
+    RTC_CIIR &= ~RTC_CIIR_IMMIN;
+  else if (mode > 0)
+    RTC_CIIR |= RTC_CIIR_IMMIN;
+
+  rtcSleep ();
+
+  return state ? 1 : 0;
+}
diff --git a/rtc/rtc.h b/rtc/rtc.h
new file mode 100644 (file)
index 0000000..1564a3c
--- /dev/null
+++ b/rtc/rtc.h
@@ -0,0 +1,23 @@
+#ifndef _RTC_H_
+#define _RTC_H_
+
+#include <time.h>
+
+//
+//  Define this for using non-vectored IRQs.  Undef it if a regular vectored
+//  IRQ is preferred.
+//
+#define RTC_NONVECTOREDIRQ
+
+//
+//
+//
+void rtcInit (void);
+time_t rtcGetEpochSeconds (unsigned int *milliseconds);
+void rtcSetEpochSeconds (time_t now);
+int rtcSetAlarm (struct tm *tm);
+struct tm *rtcGetAlarmTm (struct tm *tm);
+time_t rtcGetAlarmEpochSeconds (void);
+int rtcPeriodicAlarm (int mode);
+
+#endif
diff --git a/rtc/rtcISR.c b/rtc/rtcISR.c
new file mode 100644 (file)
index 0000000..a4a52e4
--- /dev/null
@@ -0,0 +1,75 @@
+#include <stdlib.h>
+
+//
+// Scheduler includes
+//
+#include "FreeRTOS.h"
+#include "task.h"
+#include "queue.h"
+
+#include "../uart/uart.h"
+#include "../usbser/usbser.h"
+#include "rtcISR.h"
+#include "rtc.h"
+
+//
+//
+//
+static xQueueHandle consoleQueue = NULL;
+
+//
+//
+//
+void rtcISRInit (void)
+{
+#if defined CFG_CONSOLE_USB
+  usbserGetRxQueue (&consoleQueue);
+#elif defined CFG_CONSOLE_UART0
+  uart0GetRxQueue (&consoleQueue);
+#elif defined CFG_CONSOLE_UART1
+  uart1GetRxQueue (&consoleQueue);
+#else
+#error "Eeek!  No console devices defined!"
+#endif
+}
+
+//
+//
+//
+void rtcISR (void) __attribute__ ((naked));
+void rtcISR (void)
+{
+       portENTER_SWITCHING_ISR ();
+
+  portBASE_TYPE taskWoken = pdFALSE;
+
+  RTC_CCR = (RTC_CCR_CLKEN | RTC_CCR_CLKSRC);
+  SCB_PCONP |= SCB_PCONP_PCRTC;
+
+  if (RTC_ILR & RTC_ILR_RTCCIF)
+  {
+    U8 c = 0xff;
+
+    if (consoleQueue && xQueueSendFromISR (consoleQueue, &c, (portBASE_TYPE) pdFALSE)) 
+      taskWoken = pdTRUE;
+
+         RTC_ILR = RTC_ILR_RTCCIF;
+  }
+
+  if (RTC_ILR & RTC_ILR_RTCALF)
+  {
+    U8 c = 0xfe;
+
+    if (consoleQueue && xQueueSendFromISR (consoleQueue, &c, (portBASE_TYPE) pdFALSE)) 
+      taskWoken = pdTRUE;
+
+         RTC_ILR = RTC_ILR_RTCALF;
+  }
+
+  VIC_VectAddr = (unsigned portLONG) 0;
+
+  RTC_CCR = (RTC_CCR_CLKEN | RTC_CCR_CLKSRC);
+  SCB_PCONP &= ~SCB_PCONP_PCRTC;
+
+       portEXIT_SWITCHING_ISR (taskWoken);
+}
diff --git a/rtc/rtcISR.h b/rtc/rtcISR.h
new file mode 100644 (file)
index 0000000..26eb6a1
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _RTCISR_H_
+#define _RTCISR_H_
+
+void rtcISRInit (void);
+void rtcISR (void);
+
+#endif
+
diff --git a/sensors/Makefile b/sensors/Makefile
new file mode 100644 (file)
index 0000000..ba31b01
--- /dev/null
@@ -0,0 +1,25 @@
+SRC_FILES=sensors.c
+
+#
+# Define all object files.
+#
+ARM_OBJ = $(SRC_FILES:.c=.o)
+
+.PHONY: all
+all: $(ARM_OBJ)
+
+$(ARM_OBJ) : %.o : %.c Makefile .depend
+       $(CC) -c $(CFLAGS) $< -o $@
+       $(AR) r $(COMMON)/common.a $@
+
+#
+#  The .depend files contains the list of header files that the
+#  various source files depend on.  By doing this, we'll only
+#  rebuild the .o's that are affected by header files changing.
+#
+.depend:
+                       $(CC) $(CFLAGS) -M $(SRC_FILES) > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff --git a/sensors/sensors.c b/sensors/sensors.c
new file mode 100644 (file)
index 0000000..86fb39c
--- /dev/null
@@ -0,0 +1,94 @@
+//
+//
+//
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "FreeRTOS.h"
+#include "task.h"
+#include "semphr.h"
+
+#include "../main.h"
+#include "../adc/adc.h"
+#include "../dac/dac.h"
+#include "../leds/leds.h"
+#include "sensors.h"
+
+//
+//
+//
+static sensorData_t sensorData;
+static xSemaphoreHandle semaphore;
+
+//
+//  Return 1 if got a copy, 0 if not.
+//
+int sensorsCopyData (sensorData_t *dst)
+{
+  if (xSemaphoreTake (semaphore, 100 / portTICK_RATE_MS) == pdTRUE)
+  {
+    memcpy (dst, &sensorData, sizeof (sensorData));
+    xSemaphoreGive (semaphore);
+    return 1;
+  }
+
+  memset (dst, 0, sizeof (sensorData_t));
+  return 0;
+}
+
+//
+//
+//
+portTASK_FUNCTION (vSensorsTask, pvParameters __attribute__ ((unused)))
+{
+  portTickType xTickCount;
+  int adcValue;
+  int adcLastValue = -1;
+  int adcChanged = -1;
+  int dacValue = 0;
+  int dacDirection = -16;
+
+  memset (&sensorData, 0, sizeof (sensorData));
+
+  vSemaphoreCreateBinary (semaphore);
+
+  xTickCount = xTaskGetTickCount ();
+
+  for (;;)
+  {
+    vTaskDelayUntil (&xTickCount, 100 / portTICK_RATE_MS);
+
+    //
+    //  Adjust the DAC value so we output a slow sine wave
+    //
+    if ((dacValue <= 0) || (dacValue >= (1024 - dacDirection)))
+      dacDirection = 0 - dacDirection;
+
+    dacSet (dacValue);
+    dacValue += dacDirection;
+
+    //
+    //  Read the current ADC value, keep only top 2 bits.  If it changes,
+    //  tell the LED task to change the blink rate.
+    //
+    if ((adcValue = (adcRead0_3 () >> 8)) != adcLastValue)
+    {
+      xQueueSend (xLEDQueue, &adcValue, (portTickType) 0);
+      adcLastValue = adcValue;
+      adcChanged++;
+    }
+
+    //
+    //  Update the sensors data
+    //
+    if (xSemaphoreTake (semaphore, portMAX_DELAY) == pdTRUE)
+    {
+      sensorData.sensorCount++;
+      sensorData.adcChanges = adcChanged;
+
+      xSemaphoreGive (semaphore);
+    }
+  }
+}
diff --git a/sensors/sensors.h b/sensors/sensors.h
new file mode 100644 (file)
index 0000000..380e62e
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef _SENSORS_H_
+#define _SENSORS_H_
+
+#include "semphr.h"
+
+//
+//
+//
+typedef struct sensorData_s
+{
+  int  sensorCount;
+  int  adcChanges;
+}
+sensorData_t;
+
+//
+//
+//
+int sensorsCopyData (sensorData_t *dst);
+portTASK_FUNCTION_PROTO (vSensorsTask, pvParameters __attribute__ ((unused)));
+
+#endif
diff --git a/swi/Makefile b/swi/Makefile
new file mode 100644 (file)
index 0000000..7f716f8
--- /dev/null
@@ -0,0 +1,31 @@
+SRC_FILES=swi.c
+ASMSRC_FILES=swidispatch.s
+
+#
+# Define all object files.
+#
+ARM_OBJ = $(SRC_FILES:.c=.o)
+ARM_ASMOBJ = $(ASMSRC_FILES:.s=.o)
+
+.PHONY: all
+all: $(ARM_OBJ) $(ARM_ASMOBJ)
+
+$(ARM_OBJ) : %.o : %.c Makefile .depend
+       $(CC) -c $(CFLAGS) $< -o $@
+       $(AR) r $(COMMON)/common.a $@
+
+$(ARM_ASMOBJ) : %.o : %.s Makefile .depend
+       $(CC) -c $(CFLAGS) $< -o $@
+       $(AR) r $(COMMON)/common.a $@
+
+#
+#  The .depend files contains the list of header files that the
+#  various source files depend on.  By doing this, we'll only
+#  rebuild the .o's that are affected by header files changing.
+#
+.depend:
+                       $(CC) $(CFLAGS) -M $(SRC_FILES) > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff --git a/swi/swi.c b/swi/swi.c
new file mode 100644 (file)
index 0000000..b6aa66c
--- /dev/null
+++ b/swi/swi.c
@@ -0,0 +1,73 @@
+#include "FreeRTOS.h"
+
+#include <stdio.h>
+
+#include "swi.h"
+
+//
+//
+//
+#define LED2 GPIO_IO_P11
+
+//
+//
+//
+void swiInit (void)
+{
+}
+
+int swiDispatchC (unsigned long r0, unsigned long r1 __attribute__ ((unused)), unsigned long r2 __attribute__ ((unused)), unsigned long swi)
+{
+  int state = 0;
+
+  switch (swi)
+  {
+    case SWICALL_YIELDPROCESSOR :
+    case SWICALL_A_LED2SET :
+    case SWICALL_A_LED2ON :
+    case SWICALL_A_LED2OFF :
+    case SWICALL_A_LED2TOGGLE :
+      printf ("Eeek!  This should have been handled in the asm code\n");
+      break;
+
+    case SWICALL_C_LED2SET :
+      {
+        state = GPIO0_IOPIN & LED2;
+
+        if (r0)
+          GPIO0_IOSET = LED2;                  
+        else
+          GPIO0_IOCLR = LED2;
+      }
+      break;
+
+    case SWICALL_C_LED2ON :
+      {
+        state = GPIO0_IOPIN & LED2;
+        GPIO0_IOCLR = LED2;                    
+      }
+      break;
+
+    case SWICALL_C_LED2OFF :
+      {
+        state = GPIO0_IOPIN & LED2;
+        GPIO0_IOSET = LED2;                    
+      }
+      break;
+
+    case SWICALL_C_LED2TOGGLE :
+      {
+        if ((state = GPIO0_IOPIN & LED2))
+          GPIO0_IOCLR = LED2;
+        else
+          GPIO0_IOSET = LED2;                  
+      }
+      break;
+
+    default :
+      printf ("Eeek! Unhandled SWI value\n");
+      break;
+  }
+
+  return state;
+}
diff --git a/swi/swi.h b/swi/swi.h
new file mode 100644 (file)
index 0000000..78d22ac
--- /dev/null
+++ b/swi/swi.h
@@ -0,0 +1,60 @@
+#ifndef _SWI_H_
+#define _SWI_H_
+
+//
+//
+//
+typedef enum
+{
+  SWICALL_YIELDPROCESSOR = 0,   // FreeRTOS xYieldTask (asm)
+  SWICALL_A_LED2SET,            // Set LED2 on or off, return previous state (asm)
+  SWICALL_A_LED2ON,             // LED2 on, return previous state (asm)
+  SWICALL_A_LED2OFF,            // LED2 off, return previous state (asm)
+  SWICALL_A_LED2TOGGLE,         // LED2 toggle, return previous state (asm)
+  SWICALL_C_LED2SET,            // Set LED2 on or off, return previous state (C)
+  SWICALL_C_LED2ON,             // LED2 on, return previous state (C)
+  SWICALL_C_LED2OFF,            // LED2 off, return previous state (C)
+  SWICALL_C_LED2TOGGLE,         // LED2 toggle, return previous state (C)
+}
+swiCalls_e;
+
+//
+//
+//
+#define SWICALL(swiID, swiOut) \
+       asm  volatile (\
+       "swi %a1   \n\t" \
+       "mov %0,r0 \n\t" \
+       : "=r" (swiOut) : "I" (swiID) : "r0", "lr")
+
+#define SWICALL1(swiID, swiIn, swiOut) \
+       asm  volatile (\
+       "mov r0,%1 \t\n" \
+       "swi %a2   \n\t" \
+       "mov %0,r0 \n\t" \
+       : "=r" (swiOut) : "r" (swiIn), "I" (swiID) : "r0", "lr")
+
+#define SWICALL2(swiID, swiIn1, swiIn2, swiOut) \
+       asm volatile ( \
+       "mov r0,%1 \t\n" \
+       "mov r1,%2 \t\n" \
+       "swi %a3   \n\t" \
+       "mov %0,r0 \n\t" \
+       : "=r" (swiOut) : "r" (swiIn1), "r" (swiIn2), "I" (swiID) : "r0", "lr")
+
+#define SWICALL3(swiID, swiIn1, swiIn2, swiIn3, swiOut) \
+       asm volatile ( \
+       "mov r0,%1 \t\n" \
+       "mov r1,%2 \t\n" \
+       "mov r2,%3 \t\n" \
+       "swi %a4   \n\t" \
+       "mov %0,r0 \n\t" \
+       : "=r" (swiOut) : "r" (swiIn1), "r" (swiIn2), "r" (swiIn3), "I" (swiID) : "r0", "lr")
+
+//
+//
+//
+void swiInit (void);
+int swiDispatchC (unsigned long r0, unsigned long r1, unsigned long r2, unsigned long swi);
+
+#endif
diff --git a/swi/swidispatch.s b/swi/swidispatch.s
new file mode 100644 (file)
index 0000000..3b03c18
--- /dev/null
@@ -0,0 +1,131 @@
+@
+@  This code expects to find a function named 'swiDispatchC' (which should be
+@  in swi.c) to dispatch any functions that aren't written in assembly.
+@  (What nut-case picked '@' as the comment character for .s files?)
+@
+        .text
+        .extern swiDispatchC
+        .global swiDispatch
+        .func   swiDispatch
+
+@
+@  Equates for GPIO0 registers
+@
+        .set    GPIO0_IOPIN, 0xe0028000
+        .set    GPIO0_IOSET, 0xe0028004
+        .set    GPIO0_IODIR, 0xe0028008
+        .set    GPIO0_IOCLR, 0xe002800c
+        .set    GPIO_IO_P11, 0x00000800
+
+@
+@  No check for Thumb mode.  The LPC2148 demo code doesn't do Thumb
+@
+swiDispatch:
+        stmfd   sp!, {r4, lr}           @ Save r4, lr
+        ldr     r4, [lr, #-4]           @ Fetch the SWI instruction that invoked us
+        bic     r4, r4, #0xff000000     @ Clear top 8 bits leaving swi "comment field"=number
+        cmp     r4, #SWI_LAST           @ <= SWI_LAST, handled in assembly, otherwise, in C handler
+        ldrls   pc, [pc, r4, lsl #2]    @ If <= SWI_LAST, we're handling it in assembly
+        b       swiDispatchToC          @ Not handled in here, switch to the C handler
+        
+@ 
+@  Dispatch table for functions in assembly.  The swiEntriesStart label isn't
+@  referenced directly by the code.  Rather, it must directly follow the 
+@  swiDispatch code, because it is relatively referenced.
+@
+swiEntriesStart:
+        .word   swiPYP                  @ 0 - FreeRTOS Yield Process
+        .word   LED2Set                 @ 1 - Set LED2 state, return previous state
+        .word   LED2On                  @ 2 - Turn LED2 on, return previous state
+        .word   LED2Off                 @ 3 - Turn LED2 off, return previous state
+        .word   LED2Toggle              @ 4 - Toggle LED2, return previous state
+swiEntriesEnd:
+        .set    SWI_LAST, ((swiEntriesEnd-swiEntriesStart)/4)-1
+
+@
+@  FreeRTOS uses SWI to yield process, but it's greedy and wants SWI all to its 
+@  self.  So... Special handling it is!
+@
+swiPYP:
+        ldmfd   sp!, {r4, lr}           @ Recover r4, lr
+        b       vPortYieldProcessor     @ Yield... yield like the wind!
+
+@
+@  Values are returned in r0.  LED2 is hardwired in this code (bad programmer!)  Also
+@  remember that LED2 (and LED1) have their anodes tied to +3.3V, so we have to drive
+@  the port pin LOW to turn them on.  When the caller wants to turn an LED off, it 
+@  passes in a non-zero value (keeping the same software logic as the hardware logic)
+@
+LED2Set:
+        stmfd   sp!, {r1}               @ Save r1
+        cmp     r0, #0                  @ Turn LED2 off?
+        ldreq   r4, =GPIO0_IOCLR        @ Get GPIO0_IOCLR address (0 == on)
+        ldrne   r4, =GPIO0_IOSET        @ Get GPIO0_IOSET address (!0 == off)
+        ldr     r0, =GPIO0_IOPIN        @ Load GPIO0_IOPIN address
+        ldr     r0, [r0]                @ Get GPIO0_IOPIN contents
+        ldr     r1, =GPIO_IO_P11        @ Constant for port pin LED2 attached to
+        and     r0, r0, r1              @ R0 has bit that reflects LED2 current state
+        str     r1, [r4]                @ Set LED2 on
+        ldmfd   sp!, {r1}               @ Recover r1
+        b       swiExit                 @ Exit SWI handler
+
+LED2On:
+        stmfd   sp!, {r1}               @ Save r1
+        ldr     r0, =GPIO0_IOPIN        @ Load GPIO0_IOPIN address
+        ldr     r0, [r0]                @ Get GPIO0_IOPIN contents
+        ldr     r1, =GPIO_IO_P11        @ Constant for port pin LED2 attached to
+        and     r0, r0, r1              @ R0 has bit that reflects LED2 current state
+        ldr     r4, =GPIO0_IOCLR        @ Get GPIO0_IOCLR address
+        str     r1, [r4]                @ Set LED2 on
+        ldmfd   sp!, {r1}               @ Recover r1
+        b       swiExit                 @ Exit SWI handler
+
+LED2Off:
+        stmfd   sp!, {r1}               @ Save r1
+        ldr     r0, =GPIO0_IOPIN        @ Load GPIO0_IOPIN address
+        ldr     r0, [r0]                @ Get GPIO0_IOPIN contents
+        ldr     r1, =GPIO_IO_P11        @ Constant for port pin LED2 attached to
+        and     r0, r0, r1              @ R0 has bit that reflects LED2 current state
+        ldr     r4, =GPIO0_IOSET        @ Get GPIO0_IOSET address
+        str     r1, [r4]                @ Set LED2 off
+        ldmfd   sp!, {r1}               @ Recover r1
+        b       swiExit                 @ Exit SWI handler
+
+LED2Toggle:
+        stmfd   sp!, {r1}               @ Save r1
+        ldr     r0, =GPIO0_IOPIN        @ Load GPIO0_IOPIN address
+        ldr     r0, [r0]                @ Get GPIO0_IOPIN contents
+        ldr     r1, =GPIO_IO_P11        @ Constant for port pin LED2 attached to
+        ands    r0, r0, r1              @ R0 has bit that reflects LED2 current state
+        ldrne   r4, =GPIO0_IOCLR        @ Get GPIO0_IOCLR address (!0 == off, so turn on)
+        ldreq   r4, =GPIO0_IOSET        @ Get GPIO0_IOSET address (0 == on, so turn off)
+        str     r1, [r4]                @ Set LED2 off
+        ldmfd   sp!, {r1}               @ Recover r1
+        b       swiExit                 @ Exit SWI handler
+
+@
+@  Not an internal function, try the C dispatch handler.  r0, r1, r2 will be
+@  passed through as set.  r3 will contain the SWI number.  Return value will
+@  be in r0.
+@
+swiDispatchToC:
+        stmfd   sp!,{r1-r12, lr}        @ Save r1..r12, lr on stack
+        mrs     r12, spsr               @ Saved Process Status Register (SPSR) to r12
+        stmfd   sp!, {r12}              @ Save r12
+        ldr     r12, =swiDispatchC      @ Get the address of the C handler function
+        mov     r3, r4                  @ Pass SWI number as parameter in r3
+        mov     lr, pc                  @ Save current PC to lr
+        bx      r12                     @ Branch to r12 (C handler function), return to next instruction
+        ldmfd   sp!, {r12}              @ Recover old SPSR to r12
+        msr     spsr_cxsf, r12          @ Set SPSR from r12
+        ldmfd   sp!, {r1-r12, pc}^      @ Recover r1..r12, return value in r0
+        b       swiExit                 @ And exit
+
+@
+@  Exit SWI handler.  Recover r4, return to caller
+@
+swiExit:
+        ldmfd   sp!, {r4, pc}^          @ Recover r4, return to caller
+
+        .endfunc
+        .end
diff --git a/sysdefs.h b/sysdefs.h
new file mode 100644 (file)
index 0000000..4d0e749
--- /dev/null
+++ b/sysdefs.h
@@ -0,0 +1,52 @@
+#ifndef _SYSDEFS_H_
+#define _SYSDEFS_H_
+
+#ifndef TRUE
+#define TRUE (1)
+#endif
+#ifndef FALSE
+#define FALSE (0)
+#endif
+
+typedef unsigned char U8;
+typedef signed char N8;
+typedef unsigned short U16;
+typedef signed short N16;
+typedef unsigned int U32;
+typedef signed int N32;
+typedef int BOOL;
+
+typedef volatile U8 REG8;
+typedef volatile U16 REG16;
+typedef volatile U32 REG32;
+
+#define pREG8  (REG8 *)
+#define pREG16 (REG16 *)
+#define pREG32 (REG32 *)
+
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif
+
+#define MIN(x,y) ((x)<(y)?(x):(y))
+#define MAX(x,y)((x)>(y)?(x):(y))
+#define arrsizeof(x) ((sizeof (x))/(sizeof (x [0])))
+
+//
+//  Yuck.  Don't like this here, but what the heck...
+//
+#if !defined CFG_CONSOLE_USB && !defined CFG_CONSOLE_UART0 && !defined CFG_CONSOLE_UART1
+#error "Must define CFG_CONSOLE_USB, CFG_CONSOLE_UART0 or CFG_CONSOLE_UART1
+#endif
+
+#if defined CFG_CONSOLE_USB && (defined CFG_CONSOLE_UART0 || defined CFG_CONSOLE_UART1)
+#error "Only one of CFG_CONSOLE_USB, CFG_CONSOLE_UART0 or CFG_CONSOLE_UART1 may be defined"
+#endif
+#if defined CFG_CONSOLE_UART0 && (defined CFG_CONSOLE_USB || defined CFG_CONSOLE_UART1)
+#error "Only one of CFG_CONSOLE_USB, CFG_CONSOLE_UART0 or CFG_CONSOLE_UART1 may be defined"
+#endif
+#if defined CFG_CONSOLE_UART1 && (defined CFG_CONSOLE_USB || defined CFG_CONSOLE_UART0)
+#error "Only one of CFG_CONSOLE_USB, CFG_CONSOLE_UART0 or CFG_CONSOLE_UART1 may be defined"
+#endif
+
+#endif
diff --git a/uart/Makefile b/uart/Makefile
new file mode 100644 (file)
index 0000000..a7bd147
--- /dev/null
@@ -0,0 +1,25 @@
+SRC_FILES=uart.c uartISR.c
+
+#
+# Define all object files.
+#
+ARM_OBJ = $(SRC_FILES:.c=.o)
+
+.PHONY: all
+all: $(ARM_OBJ)
+
+$(ARM_OBJ) : %.o : %.c Makefile .depend
+       $(CC) -c $(CFLAGS) $< -o $@
+       $(AR) r $(COMMON)/common.a $@
+
+#
+#  The .depend files contains the list of header files that the
+#  various source files depend on.  By doing this, we'll only
+#  rebuild the .o's that are affected by header files changing.
+#
+.depend:
+                       $(CC) $(CFLAGS) -M $(SRC_FILES) > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff --git a/uart/uart.c b/uart/uart.c
new file mode 100644 (file)
index 0000000..acc2ef7
--- /dev/null
@@ -0,0 +1,350 @@
+/* 
+   INTERRUPT DRIVEN SERIAL PORT DRIVER FOR UART0 and UART1. 
+
+   This file contains all the serial port components that can be compiled to
+   either ARM or THUMB mode.  Components that must be compiled to ARM mode are
+   contained in serialISR.c.
+ */
+
+//
+//  Standard includes
+//
+#include <stdlib.h>
+
+//
+//  Scheduler includes
+//
+#include "FreeRTOS.h"
+#include "queue.h"
+#include "task.h"
+
+//
+//  Demo application includes
+//
+#include "uart.h"
+#include "uartISR.h"
+
+//
+//  Constants to setup and access the UART
+//
+#define serWANTED_CLOCK_SCALING          ((unsigned portLONG) 16)
+
+//
+//  Constants to setup and access the VIC
+//
+#define serINVALID_QUEUE                                 ((xQueueHandle) 0)
+#define serHANDLE                                              ((xComPortHandle) 1)
+#define serNO_BLOCK                                          ((portTickType) 0)
+
+//
+//  Queues used to hold received characters, and characters waiting to be transmitted
+//
+static xQueueHandle xRX0Queue; 
+static xQueueHandle xTX0Queue; 
+static xQueueHandle xRX1Queue; 
+static xQueueHandle xTX1Queue; 
+
+//
+//  Communication flag between the interrupt service routine and serial API
+//
+static volatile portLONG *plTHREEmpty;
+static volatile portLONG *plTHREEmpty1;
+
+//
+//
+//
+xComPortHandle uartInit (portCHAR pxPort, unsigned portLONG ulWantedBaud, unsigned portBASE_TYPE uxQueueLength)
+{
+  unsigned portLONG ulDivisor;
+  unsigned portLONG ulWantedClock;
+  xComPortHandle xReturn = serHANDLE;
+
+  switch (pxPort)
+  {
+    case 0 :    
+      {
+        uartISRCreateQueues (0, uxQueueLength, &xRX0Queue, &xTX0Queue, &plTHREEmpty);
+
+        if ((xRX0Queue != serINVALID_QUEUE) && 
+            (xTX0Queue != serINVALID_QUEUE) && 
+            (ulWantedBaud != (unsigned portLONG) 0) 
+           )
+        {
+          portENTER_CRITICAL ();
+
+          {
+            SCB_PCONP |= SCB_PCONP_PCUART0;
+
+            //
+            //  Setup the baud rate:  Calculate the divisor value
+            //
+            ulWantedClock = ulWantedBaud * serWANTED_CLOCK_SCALING;
+            ulDivisor = configCPU_CLOCK_HZ / ulWantedClock;
+
+            //
+            //  Set the DLAB bit so we can access the divisor
+            //
+            UART0_LCR |= UART_LCR_DLAB;
+
+            //
+            //  Setup the divisor
+            //
+            UART0_DLL = (unsigned portCHAR) (ulDivisor & (unsigned portLONG) 0xff);
+            ulDivisor >>= 8;
+            UART0_DLM = (unsigned portCHAR) (ulDivisor & (unsigned portLONG) 0xff);
+
+            //
+            //  Turn on the FIFO's and clear the buffers
+            //
+            UART0_FCR = UART_FCR_EN | UART_FCR_CLR;
+
+            //
+            //  Setup transmission format
+            //
+            UART0_LCR = UART_LCR_NOPAR | UART_LCR_1STOP | UART_LCR_8BITS;
+
+            //
+            //  Setup the VIC for the UART
+            //
+            VIC_IntSelect &= ~VIC_IntSelect_UART0;
+            VIC_VectAddr2 = (portLONG) uartISR0;
+            VIC_VectCntl2 = VIC_VectCntl_ENABLE | VIC_Channel_UART0;
+            VIC_IntEnable = VIC_IntEnable_UART0;
+
+            //
+            //  Enable UART0 interrupts
+            //
+            UART0_IER |= UART_IER_EI;
+          }
+
+          portEXIT_CRITICAL ();
+        }
+        else
+          xReturn = (xComPortHandle) 0;
+      }
+      break;
+
+    case 1:
+      {
+        uartISRCreateQueues (1, uxQueueLength, &xRX1Queue, &xTX1Queue, &plTHREEmpty1);
+
+        if ((xRX1Queue != serINVALID_QUEUE) && 
+            (xTX1Queue != serINVALID_QUEUE) && 
+            (ulWantedBaud != (unsigned portLONG) 0) 
+           )
+        {
+          portENTER_CRITICAL ();
+
+          {
+            SCB_PCONP |= SCB_PCONP_PCUART1;
+
+            //
+            //  Setup the baud rate:  Calculate the divisor value
+            //
+            ulWantedClock = ulWantedBaud * serWANTED_CLOCK_SCALING;
+            ulDivisor = configCPU_CLOCK_HZ / ulWantedClock;
+
+            //
+            //  Set the DLAB bit so we can access the divisor
+            //
+            UART1_LCR |= UART_LCR_DLAB;
+
+            //
+            //  Setup the divisor
+            //
+            UART1_DLL = (unsigned portCHAR) (ulDivisor & (unsigned portLONG) 0xff);
+            ulDivisor >>= 8;
+            UART1_DLM = (unsigned portCHAR) (ulDivisor & (unsigned portLONG) 0xff);
+
+            //
+            //  Turn on the FIFO's and clear the buffers
+            //
+            UART1_FCR = UART_FCR_EN | UART_FCR_CLR;
+
+            //
+            //  Setup transmission format
+            //
+            UART1_LCR = UART_LCR_NOPAR | UART_LCR_1STOP | UART_LCR_8BITS;
+
+            //
+            //  Setup the VIC for the UART
+            //
+            VIC_IntSelect &= ~VIC_IntSelect_UART1;
+            VIC_VectAddr3 = (portLONG) uartISR1;
+            VIC_VectCntl3 = VIC_VectCntl_ENABLE | VIC_Channel_UART1;
+            VIC_IntEnable = VIC_IntEnable_UART1;
+
+            //
+            //  Enable UART0 interrupts//
+            //
+            UART1_IER |= UART_IER_EI;
+          }
+
+          portEXIT_CRITICAL ();
+        }
+        else
+          xReturn = (xComPortHandle) 0;
+      }
+      break;
+  }
+
+  return xReturn;
+}
+
+signed portBASE_TYPE uartGetChar (portCHAR pxPort, signed portCHAR *pcRxedChar, portTickType xBlockTime)
+{
+  switch (pxPort)
+  {
+    //
+    //  Get the next character from the buffer.  Return false if no characters are available, or arrive before xBlockTime expires
+    //
+    case 0:    
+      {
+        if (xQueueReceive (xRX0Queue, pcRxedChar, xBlockTime))
+          return pdTRUE;
+        else
+          return pdFALSE;
+      }
+      break;
+
+      //
+      //  Get the next character from the buffer.  Return false if no characters are available, or arrive before xBlockTime expires
+      //
+    case 1:
+      {
+        if (xQueueReceive (xRX1Queue, pcRxedChar, xBlockTime))
+          return pdTRUE;
+        else
+          return pdFALSE;
+      }
+      break;
+  }
+
+  return pdFALSE;
+}
+
+//
+//
+//
+void uartPutString (portCHAR pxPort, const signed portCHAR * const pcString, portTickType xBlockTime)
+{
+  signed portCHAR *pxNext;
+
+  pxNext = (signed portCHAR *) pcString;
+
+  while (*pxNext)
+  {
+    uartPutChar (pxPort, *pxNext, xBlockTime);
+    pxNext++;
+  }
+}
+
+//
+//
+//
+signed portBASE_TYPE uartPutChar (portCHAR pxPort, signed portCHAR cOutChar, portTickType xBlockTime)
+{
+  signed portBASE_TYPE xReturn = 0;
+
+  switch (pxPort)
+  {
+    case 0 :    
+      {
+        portENTER_CRITICAL ();
+
+        {
+          //
+          //  Is there space to write directly to the UART?
+          //
+          if (*plTHREEmpty == (portLONG) pdTRUE)
+          {
+            *plTHREEmpty = pdFALSE;
+            UART0_THR = cOutChar;
+            xReturn = pdPASS;
+          }
+          else 
+          {
+            //
+            //  We cannot write directly to the UART, so queue the character.  Block for a maximum of 
+            //  xBlockTime if there is no space in the queue.
+            //
+            xReturn = xQueueSend (xTX0Queue, &cOutChar, xBlockTime);
+
+            //
+            //  Depending on queue sizing and task prioritisation:  While we were blocked waiting to post 
+            //  interrupts were not disabled.  It is possible that the serial ISR has emptied the Tx queue, 
+            //  in which case we need to start the Tx off again.
+            //
+            if ((*plTHREEmpty == (portLONG) pdTRUE) && (xReturn == pdPASS))
+            {
+              xQueueReceive (xTX0Queue, &cOutChar, serNO_BLOCK);
+              *plTHREEmpty = pdFALSE;
+              UART0_THR = cOutChar;
+            }
+          }
+        }
+
+        portEXIT_CRITICAL ();
+      }
+      break;
+
+    case 1 :
+      {
+        portENTER_CRITICAL ();
+
+        {
+          //
+          //  Is there space to write directly to the UART?
+          //
+          if (*plTHREEmpty1 == (portLONG) pdTRUE)
+          {
+            *plTHREEmpty1 = pdFALSE;
+            UART1_THR = cOutChar;
+            xReturn = pdPASS;
+          }
+          else 
+          {
+            //
+            //  We cannot write directly to the UART, so queue the character.  Block for a maximum of 
+            //  xBlockTime if there is no space in the queue.
+            //
+            xReturn = xQueueSend (xTX1Queue, &cOutChar, xBlockTime);
+
+            //
+            //  Depending on queue sizing and task prioritisation:  While we were blocked waiting to post 
+            //  interrupts were not disabled.  It is possible that the serial ISR has emptied the Tx queue, 
+            //  in which case we need to start the Tx off again.
+            //
+            if ((*plTHREEmpty1 == (portLONG) pdTRUE) && (xReturn == pdPASS))
+            {
+              xQueueReceive (xTX1Queue, &cOutChar, serNO_BLOCK);
+              *plTHREEmpty1 = pdFALSE;
+              UART1_THR = cOutChar;
+            }
+          }
+        }
+
+        portEXIT_CRITICAL ();  
+      }
+      break;
+
+    default:
+      return xReturn;
+      break;
+  }
+
+  return xReturn;
+}
+
+//
+//
+//
+void uart0GetRxQueue (xQueueHandle *qh)
+{
+  *qh = xRX0Queue;
+}
+
+void uart1GetRxQueue (xQueueHandle *qh)
+{
+  *qh = xRX1Queue;
+}
diff --git a/uart/uart.h b/uart/uart.h
new file mode 100644 (file)
index 0000000..07f10b3
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef _UART_H_
+#define _UART_H_
+
+#include "FreeRTOS.h"
+#include "queue.h"
+
+typedef void *xComPortHandle;
+
+xComPortHandle uartInit (portCHAR pxPort, unsigned portLONG ulWantedBaud, unsigned portBASE_TYPE uxQueueLength);
+void uartPutString (portCHAR pxPort, const signed portCHAR * const pcString, portTickType xBlockTime);
+signed portBASE_TYPE uartGetChar (portCHAR pxPort, signed portCHAR *pcRxedChar, portTickType xBlockTime);
+signed portBASE_TYPE uartPutChar (portCHAR pxPort, signed portCHAR cOutChar, portTickType xBlockTime);
+void uartClose (portCHAR xPort);
+void uart0GetRxQueue (xQueueHandle *qh);
+void uart1GetRxQueue (xQueueHandle *qh);
+
+#endif
diff --git a/uart/uartISR.c b/uart/uartISR.c
new file mode 100644 (file)
index 0000000..a37b6c4
--- /dev/null
@@ -0,0 +1,193 @@
+//
+//  Standard includes
+//
+#include <stdlib.h>
+
+//
+//  Scheduler includes
+//
+#include "FreeRTOS.h"
+#include "queue.h"
+#include "task.h"
+
+//
+//  Demo application includes
+//
+#include "uart.h"
+#include "uartISR.h"
+
+//
+//  Constants to determine the ISR source
+//
+#define serSOURCE_THRE                                   ((unsigned portCHAR) 0x02)
+#define serSOURCE_RX_TIMEOUT                   ((unsigned portCHAR) 0x0c)
+#define serSOURCE_ERROR                                          ((unsigned portCHAR) 0x06)
+#define serSOURCE_RX                                       ((unsigned portCHAR) 0x04)
+#define serINTERRUPT_SOURCE_MASK       ((unsigned portCHAR) 0x0f)
+
+//
+//  Queues used to hold received characters, and characters waiting to be transmitted
+//
+static xQueueHandle xRX0Queue; 
+static xQueueHandle xTX0Queue; 
+static volatile portLONG lTHREEmpty0;
+static xQueueHandle xRX1Queue; 
+static xQueueHandle xTX1Queue; 
+static volatile portLONG lTHREEmpty1;
+
+//
+//
+//
+void uartISRCreateQueues (portCHAR pxPort, unsigned portBASE_TYPE uxQueueLength, xQueueHandle *pxRX0Queue, xQueueHandle *pxTX0Queue, portLONG volatile **pplTHREEmptyFlag)
+{
+  switch (pxPort)
+  {
+    case 0:    
+      {
+        //
+        //  Create the queues used to hold Rx and Tx characters
+        //
+        *pxRX0Queue = xRX0Queue = xQueueCreate (uxQueueLength, (unsigned portBASE_TYPE) sizeof (signed portCHAR));
+        *pxTX0Queue = xTX0Queue = xQueueCreate (uxQueueLength + 1, (unsigned portBASE_TYPE) sizeof (signed portCHAR));
+
+        //
+        //  Initialise the THRE empty flag - and pass back a reference
+        //
+        lTHREEmpty0 = (portLONG) pdTRUE;
+        *pplTHREEmptyFlag = &lTHREEmpty0;
+      }
+      break;
+
+    case 1:
+      {
+        //
+        //  Create the queues used to hold Rx and Tx characters
+        //
+        *pxRX0Queue = xRX1Queue = xQueueCreate (uxQueueLength, (unsigned portCHAR) sizeof (signed portCHAR));
+        *pxTX0Queue = xTX1Queue = xQueueCreate (uxQueueLength + 1, (unsigned portCHAR) sizeof (signed portCHAR));
+
+        //
+        //  Initialise the THRE empty flag - and pass back a reference
+        //
+        lTHREEmpty1 = (portLONG) pdTRUE;
+        *pplTHREEmptyFlag = &lTHREEmpty1;      
+      }
+      break;
+  }
+}
+
+//
+//
+//
+void uartISR0 (void) __attribute__ ((naked));
+void uartISR0 (void)
+{
+  portENTER_SWITCHING_ISR ();
+
+  signed portCHAR cChar;
+  portBASE_TYPE xTaskWokenByTx = pdFALSE;
+  portBASE_TYPE xTaskWokenByRx = pdFALSE;
+
+  switch (UART0_IIR & serINTERRUPT_SOURCE_MASK)
+  {
+    //
+    //  Not handling this, but clear the interrupt
+    //
+    case serSOURCE_ERROR :     
+      {
+        cChar = UART0_LSR;
+      }
+      break;
+
+    //
+    //  The THRE is empty.  If there is another character in the Tx queue, send it now,
+    //  otherwise, no more characters, so indicate THRE is available
+    //
+    case serSOURCE_THRE        :       
+      {
+        if (xQueueReceiveFromISR (xTX0Queue, &cChar, &xTaskWokenByTx) == pdTRUE)
+          UART0_THR = cChar;
+        else
+          lTHREEmpty0 = pdTRUE;
+      }
+      break;
+
+    //
+    //  A character was received.  Place it in the queue of received characters
+    //
+    case serSOURCE_RX_TIMEOUT :
+    case serSOURCE_RX  :       
+      {
+        cChar = UART0_RBR;
+
+        if (xQueueSendFromISR (xRX0Queue, &cChar, (portBASE_TYPE) pdFALSE)) 
+          xTaskWokenByRx = pdTRUE;
+      }
+      break;
+
+    default    :
+      break;
+  }
+
+  VIC_VectAddr = (unsigned portLONG) 0;
+
+  portEXIT_SWITCHING_ISR ((xTaskWokenByTx || xTaskWokenByRx));
+}
+
+//
+//
+//
+void uartISR1 (void) __attribute__ ((naked));
+void uartISR1 (void)
+{
+  portENTER_SWITCHING_ISR ();
+
+  signed portCHAR cChar;
+  portBASE_TYPE xTaskWokenByTx = pdFALSE;
+  portBASE_TYPE xTaskWokenByRx = pdFALSE;
+
+  switch (UART1_IIR & serINTERRUPT_SOURCE_MASK)
+  {
+    //
+    //  Not handling this, but clear the interrupt
+    //
+    case serSOURCE_ERROR :
+      {
+        cChar = UART1_LSR;
+      }
+      break;
+
+    //
+    //  The THRE is empty.  If there is another character in the Tx queue, send it now,
+    //  otherwise, no more characters, so indicate THRE is available
+    //
+    case serSOURCE_THRE        :
+      {
+        if (xQueueReceiveFromISR (xTX1Queue, &cChar, &xTaskWokenByTx) == pdTRUE)
+          UART1_THR = cChar;
+        else
+          lTHREEmpty1 = pdTRUE;
+      }
+      break;
+
+    //
+    //  A character was received.  Place it in the queue of received characters
+    //
+    case serSOURCE_RX_TIMEOUT :
+    case serSOURCE_RX  :
+      {
+        cChar = UART1_RBR;
+
+        if (xQueueSendFromISR (xRX1Queue, &cChar, (portBASE_TYPE) pdFALSE)) 
+          xTaskWokenByRx = pdTRUE;
+      }
+      break;
+
+    default    :
+      break;
+  }
+
+  VIC_VectAddr = (unsigned portLONG) 0;
+
+  portEXIT_SWITCHING_ISR ((xTaskWokenByTx || xTaskWokenByRx));
+}
diff --git a/uart/uartISR.h b/uart/uartISR.h
new file mode 100644 (file)
index 0000000..8926373
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef _UARTISR_H_
+#define _UARTISR_H_
+
+#include "FreeRTOS.h"
+#include "queue.h"
+
+//
+//
+//
+void uartISRCreateQueues (portCHAR pxPort, unsigned portBASE_TYPE uxQueueLength, xQueueHandle *pxRX0Queue, xQueueHandle *pxTX0Queue, portLONG volatile **pplTHREEmptyFlag);
+void uartISR0 (void);
+void uartISR1 (void);
+signed portBASE_TYPE uart0PostSpecialFromISR (U8 special);
+signed portBASE_TYPE uart1PostSpecialFromISR (U8 special);
+
+#endif
diff --git a/usb/Makefile b/usb/Makefile
new file mode 100644 (file)
index 0000000..c6eaef1
--- /dev/null
@@ -0,0 +1,25 @@
+SRC_FILES=usbISR.c usbcontrol.c usbinit.c usbstdreq.c
+
+#
+# Define all object files.
+#
+ARM_OBJ = $(SRC_FILES:.c=.o)
+
+.PHONY: all
+all: $(ARM_OBJ)
+
+$(ARM_OBJ) : %.o : %.c Makefile .depend
+       $(CC) -c $(CFLAGS) $< -o $@
+       $(AR) r $(COMMON)/common.a $@
+
+#
+#  The .depend files contains the list of header files that the
+#  various source files depend on.  By doing this, we'll only
+#  rebuild the .o's that are affected by header files changing.
+#
+.depend:
+                       $(CC) $(CFLAGS) -M $(SRC_FILES) > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff --git a/usb/usbISR.c b/usb/usbISR.c
new file mode 100644 (file)
index 0000000..1f28b03
--- /dev/null
@@ -0,0 +1,411 @@
+#include "FreeRTOS.h"
+#include "task.h"
+// #include "usb.h"
+#include "usbISR.h"
+#include "usbapi.h"
+
+//
+//
+//
+static TFnDevIntHandler *_pfnDevIntHandler = NULL;  /** Installed device interrupt handler */
+static TFnEPIntHandler  *_apfnEPIntHandlers [16];   /** Installed endpoint interrupt handlers */
+static TFnFrameHandler  *_pfnFrameHandler = NULL;   /** Installed frame interrupt handlers */
+
+#define EP2IDX(bEP) ((((bEP)&0xF)<<1)|(((bEP)&0x80)>>7))  /** convert from endpoint address to endpoint index */
+#define IDX2EP(idx) ((((idx)<<7)&0x80)|(((idx)>>1)&0xF))  /** convert from endpoint index to endpoint address */
+
+static void usbISR (void) __attribute__ ((naked));
+
+//
+//  Local function to wait for a device interrupt (and clear it)
+//
+static void usbWaitForDeviceInterrupt (U32 dwIntr)
+{
+  while ((USB_DevIntSt & dwIntr) != dwIntr)
+    ;
+
+  USB_DevIntClr = dwIntr;
+}
+
+//
+//  Local function to send a command to the USB protocol engine
+//
+static void usbHardwareCommand (U8 bCmd)
+{
+  USB_DevIntClr = USB_DevIntClr_CDFULL | USB_DevIntClr_CCEMTY;
+  USB_CmdCode = 0x00000500 | (bCmd << 16);
+  usbWaitForDeviceInterrupt (USB_DevIntSt_CCEMTY);
+}
+
+//
+//  Local function to send a command + data to the USB protocol engine
+//
+static void usbHardwareCommandWrite (U8 bCmd, U16 bData)
+{
+  usbHardwareCommand (bCmd);
+  USB_CmdCode = 0x00000100 | (bData << 16);
+  usbWaitForDeviceInterrupt (USB_DevIntSt_CCEMTY);
+}
+
+//
+//  Local function to send a command to the USB protocol engine and read data
+//
+static U8 usbHardwareCommandRead (U8 bCmd)
+{
+  usbHardwareCommand (bCmd);
+  USB_CmdCode = 0x00000200 | (bCmd << 16);
+  usbWaitForDeviceInterrupt (USB_DevIntSt_CDFULL);
+  return USB_CmdData;
+}
+
+//
+//  'Realizes' an endpoint, meaning that buffer space is reserved for
+//  it. An endpoint needs to be realised before it can be used.
+//    
+//  From experiments, it appears that a USB reset causes USBReEP to
+//  re-initialise to 3 (= just the control endpoints).
+//  However, a USB bus reset does not disturb the USBMaxPSize settings.
+//    
+static void usbHardwareEndpointRealize (int idx, U16 wMaxPSize)
+{
+  USB_ReEP |= (1 << idx);
+  USB_EpInd = idx;
+  USB_MaxPSize = wMaxPSize;
+  usbWaitForDeviceInterrupt (USB_DevIntSt_EPRLZED);
+}
+
+//
+//  Enables or disables an endpoint
+//
+static void usbHardwareEndpointEnable (int idx, BOOL fEnable)
+{
+  usbHardwareCommandWrite (CMD_EP_SET_STATUS | idx, fEnable ? 0 : EP_DA);
+}
+
+//
+// Configures an endpoint and enables it
+//
+void usbHardwareEndpointConfig (U8 bEP, U16 wMaxPacketSize)
+{
+  int idx;
+  
+  idx = EP2IDX (bEP);
+  usbHardwareEndpointRealize (idx, wMaxPacketSize);
+  usbHardwareEndpointEnable (idx, TRUE);
+}
+
+//
+//  Registers an endpoint event callback
+//
+void usbHardwareRegisterEPIntHandler (U8 bEP, TFnEPIntHandler *pfnHandler)
+{
+  int idx;
+  
+  idx = EP2IDX (bEP);
+
+  _apfnEPIntHandlers [idx / 2] = pfnHandler;
+  USB_EpIntEn |= (1 << idx);
+  USB_DevIntEn |= USB_DevIntEn_EPSLOW;
+}
+
+//
+//  Registers an device status callback
+//
+void usbHardwareRegisterDevIntHandler (TFnDevIntHandler *pfnHandler)
+{
+  _pfnDevIntHandler = pfnHandler;
+  USB_DevIntEn |= USB_DevIntEn_DEVSTAT;
+}
+
+//
+//  Registers the frame callback
+//
+void usbHardwareRegisterFrameHandler (TFnFrameHandler *pfnHandler)
+{
+  _pfnFrameHandler = pfnHandler;
+  USB_DevIntEn |= USB_DevIntEn_FRAME;
+}
+
+//
+//  Sets the USB address.
+//
+void usbHardwareSetAddress (U8 bAddr)
+{
+  usbHardwareCommandWrite (CMD_DEV_SET_ADDRESS, DEV_EN | bAddr);
+}
+
+//
+//  Connects or disconnects from the USB bus
+//
+void usbHardwareConnect (BOOL fConnect)
+{
+  usbHardwareCommandWrite (CMD_DEV_STATUS, fConnect ? CON : 0);
+}
+
+//
+//  Enables interrupt on NAK condition
+//    
+//  For IN endpoints a NAK is generated when the host wants to read data
+//  from the device, but none is available in the endpoint buffer.
+//  For OUT endpoints a NAK is generated when the host wants to write data
+//  to the device, but the endpoint buffer is still full.
+//  
+//  The endpoint interrupt handlers can distinguish regular (ACK) interrupts
+//  from NAK interrupt by checking the bits in their bEPStatus argument.
+//  
+void usbHardwareNakIntEnable (U8 bIntBits)
+{
+  usbHardwareCommandWrite (CMD_DEV_SET_MODE, bIntBits);
+}
+
+//
+//  Gets the stalled property of an endpoint
+//
+BOOL usbHardwareEndpointIsStalled (U8 bEP)
+{
+  int idx = EP2IDX (bEP);
+
+  return (usbHardwareCommandRead (CMD_EP_SELECT | idx) & EP_STATUS_STALLED);
+}
+
+//
+//  Sets the stalled property of an endpoint
+//
+void usbHardwareEndpointStall (U8 bEP, BOOL fStall)
+{
+  int idx = EP2IDX (bEP);
+
+  usbHardwareCommandWrite (CMD_EP_SET_STATUS | idx, fStall ? EP_ST : 0);
+}
+
+//
+//  Writes data to an endpoint buffer
+//
+int usbHardwareEndpointWrite (U8 bEP, U8 *pbBuf, int iLen)
+{
+  int idx;
+  
+  idx = EP2IDX (bEP);
+  
+  USB_Ctrl = USB_Ctrl_WREN | ((bEP & 0xF) << 2);
+  USB_TxPLen = iLen;
+
+  while (USB_Ctrl & USB_Ctrl_WREN) 
+  {
+    USB_TxData = (pbBuf [3] << 24) | (pbBuf [2] << 16) | (pbBuf [1] << 8) | pbBuf [0];
+    pbBuf += 4;
+  }
+
+  usbHardwareCommand (CMD_EP_SELECT | idx);
+  usbHardwareCommand (CMD_EP_VALIDATE_BUFFER);
+  
+  return iLen;
+}
+
+//
+//  Reads data from an endpoint buffer
+//
+int usbHardwareEndpointRead (U8 bEP, U8 *pbBuf, int iMaxLen)
+{
+  int i, idx;
+  U32 dwData, dwLen;
+  
+  idx = EP2IDX (bEP);
+  
+  USB_Ctrl = USB_Ctrl_RDEN | ((bEP & 0xF) << 2);
+  
+  do 
+  {
+    dwLen = USB_RxPLen;
+  } 
+  while ((dwLen & USB_RxPLen_PKTRDY) == 0);
+  
+  if ((dwLen & USB_RxPLen_DV) == 0)
+    return -1;
+  
+  dwLen &= USB_RxPLen_PKTLENGTH_MASK;
+  
+  while (USB_Ctrl & USB_Ctrl_RDEN) 
+  {
+    dwData = USB_RxData;
+
+    if (pbBuf != NULL) 
+    {
+      for (i = 0; i < 4; i++) 
+      {
+        if (iMaxLen-- != 0) 
+          *pbBuf++ = dwData & 0xFF;
+
+        dwData >>= 8;
+      }
+    }
+  }
+
+  usbHardwareCommand (CMD_EP_SELECT | idx);
+  usbHardwareCommand (CMD_EP_CLEAR_BUFFER);
+  
+  return dwLen;
+}
+
+
+//
+//  Sets the 'configured' state.
+//
+void usbHardwareConfigDevice (BOOL fConfigured)
+{
+  usbHardwareCommandWrite (CMD_DEV_CONFIG, fConfigured ? CONF_DEVICE : 0);
+}
+
+//
+//
+//
+void usbSetupInterruptHandler (void)
+{
+  //
+  //  Set up USB interrupt, use highest priority ISR slot
+  //
+  VIC_IntSelect &= ~VIC_IntSelect_USB;
+  VIC_VectAddr1 = (portLONG) usbISR;
+  VIC_VectCntl1 = VIC_VectCntl_ENABLE | VIC_Channel_USB;
+  VIC_IntEnable = VIC_IntEnable_USB;
+}
+
+//
+//  USB interrupt handler
+//
+void usbISR (void)
+{
+  portENTER_SWITCHING_ISR ();
+
+  U32 dwStatus;
+  U32 dwIntBit;
+  U8  bEPStat, bDevStat, bStat;
+  int i;
+  portBASE_TYPE xTaskWoken = pdFALSE;
+
+  dwStatus = USB_DevIntSt;
+  
+  if (dwStatus & USB_DevIntSt_DEVSTAT) 
+  {
+    USB_DevIntClr = USB_DevIntClr_DEVSTAT;
+    bDevStat = usbHardwareCommandRead (CMD_DEV_STATUS);
+
+    if (bDevStat & (CON_CH | SUS_CH | RST)) 
+    {
+      bStat = ((bDevStat & CON) ? DEV_STATUS_CONNECT : 0) |
+              ((bDevStat & SUS) ? DEV_STATUS_SUSPEND : 0) |
+              ((bDevStat & RST) ? DEV_STATUS_RESET   : 0);
+      
+      if (_pfnDevIntHandler != NULL)
+        _pfnDevIntHandler (bStat);
+    }
+  }
+  
+  if (dwStatus & USB_DevIntSt_EPSLOW) 
+  {
+    USB_DevIntClr = USB_DevIntClr_EPSLOW;
+
+    for (i = 0; i < 32; i++) 
+    {
+      dwIntBit = (1 << i);
+
+      if (USB_EpIntSt & dwIntBit) 
+      {
+        USB_EpIntClr = dwIntBit;
+        usbWaitForDeviceInterrupt (USB_DevIntSt_CDFULL);
+        bEPStat = USB_CmdData;
+
+        bStat = ((bEPStat & EPSTAT_FE)  ? EP_STATUS_DATA    : 0) |
+                ((bEPStat & EPSTAT_ST)  ? EP_STATUS_STALLED : 0) |
+                ((bEPStat & EPSTAT_STP) ? EP_STATUS_SETUP   : 0) |
+                ((bEPStat & EPSTAT_EPN) ? EP_STATUS_NACKED  : 0) |
+                ((bEPStat & EPSTAT_PO)  ? EP_STATUS_ERROR   : 0);
+
+        if (bEPStat & (1 <<5)) 
+        {
+        }
+
+        if (bEPStat & (1 <<6)) 
+        {
+        }
+
+        if (_apfnEPIntHandlers [i / 2] != NULL)
+          xTaskWoken |= _apfnEPIntHandlers [i / 2] (IDX2EP (i), bStat);
+      }
+    }
+  }
+  
+  if (dwStatus & USB_DevIntSt_FRAME) 
+  {
+    USB_DevIntClr = USB_DevIntClr_FRAME;
+
+    if (_pfnFrameHandler != NULL)
+      _pfnFrameHandler (0);
+  }
+
+       VIC_VectAddr = (unsigned portLONG) 0;
+
+  portEXIT_SWITCHING_ISR (xTaskWoken);
+}
+
+//
+//  Initializes the USB hardware
+//     
+//  This function assumes that the hardware is connected as shown in
+//  section 10.1 of the LPC2148 data sheet:
+//  * P0.31 controls a switch to connect a 1.5k pull-up to D+ if low.
+//  * P0.23 is connected to USB VCC.
+//
+BOOL usbHardwareInit (void)
+{
+  //
+  //  Configure P0.23 for Vbus sense, P0.31 as USB connect indicator
+  //
+  PCB_PINSEL1 = (PCB_PINSEL1 & ~PCB_PINSEL1_P023_GPIO) | PCB_PINSEL1_P023_VBUS;
+  GPIO0_IODIR &= ~GPIO_IO_P23;
+  PCB_PINSEL1 = (PCB_PINSEL1 & ~PCB_PINSEL1_P031_GPIO) | PCB_PINSEL1_P031_CONNECT;
+
+  //
+  //  Enable PUSB
+  //
+  SCB_PCONP |= SCB_PCONP_PUSB;
+
+  //
+  //  Initialize PLL
+  //
+  USB_PLLCON = USB_PLLCON_PLLE;
+  USB_PLLCFG = USB_PLLCFG_DIV2 | USB_PLLCFG_MUL4;
+  USB_PLLFEED = USB_PLLFEED_FEED1;
+  USB_PLLFEED = USB_PLLFEED_FEED2;
+
+  //
+  //  Wait for PLL to lock up
+  //
+  while (!(USB_PLLSTAT & USB_PLLSTAT_PLOCK))
+    ;
+
+  USB_PLLCON = USB_PLLCON_PLLC | USB_PLLCON_PLLE;
+  USB_PLLFEED = USB_PLLFEED_FEED1;
+  USB_PLLFEED = USB_PLLFEED_FEED2;
+
+  //
+  //  Disable/clear all interrupts for now
+  //
+  USB_DevIntEn = USB_DevIntEn_NONE;
+  USB_EpIntEn = USB_EpIntEn_NONE;
+  USB_DevIntClr = USB_DevIntClr_ALL;
+  USB_EpIntClr = USB_EpIntClr_ALL;
+
+  //
+  //  Setup control endpoints
+  //
+  usbHardwareEndpointConfig (0x00, MAX_PACKET_SIZE0);
+  usbHardwareEndpointConfig (0x80, MAX_PACKET_SIZE0);
+
+  //
+  //  By default, only ACKs generate interrupts
+  //
+  usbHardwareNakIntEnable (0);
+
+  return TRUE;
+}
diff --git a/usb/usbISR.h b/usb/usbISR.h
new file mode 100644 (file)
index 0000000..2b1f46c
--- /dev/null
@@ -0,0 +1,98 @@
+//
+//  These really need to be normalized to the names in lp210x.h and included there.
+//  A #define like "DEV_ADDR" is just too ambiguous when it's unqualified with 
+//  what sub-system it belongs to.
+//
+
+#ifndef _USBISR_H_
+#define _USBISR_H_
+
+//
+//  Protocol engine command codes, device commands 
+//
+#define CMD_DEV_SET_ADDRESS       0xD0
+#define CMD_DEV_CONFIG            0xD8
+#define CMD_DEV_SET_MODE          0xF3
+#define CMD_DEV_READ_CUR_FRAME_NR 0xF5
+#define CMD_DEV_READ_TEST_REG     0xFD
+#define CMD_DEV_STATUS            0xFE    /* read/write */
+#define CMD_DEV_GET_ERROR_CODE    0xFF
+#define CMD_DEV_READ_ERROR_STATUS 0xFB
+
+//
+//  Protocol engine command codes, endpoint commands 
+//
+#define CMD_EP_SELECT             0x00
+#define CMD_EP_SELECT_CLEAR       0x40
+#define CMD_EP_SET_STATUS         0x40
+#define CMD_EP_CLEAR_BUFFER       0xF2
+#define CMD_EP_VALIDATE_BUFFER    0xFA
+
+//
+//  Set address command 
+//
+#define DEV_ADDR          (1<<0)
+#define DEV_EN            (1<<7)
+
+//
+//  Configure device command 
+//
+#define CONF_DEVICE       (1<<0)
+
+//
+//  Set mode command 
+//
+#define AP_CLK            (1<<0)
+#define INAK_CI           (1<<1)
+#define INAK_CO           (1<<2)
+#define INAK_II           (1<<3)
+#define INAK_IO           (1<<4)
+#define INAK_BI           (1<<5)
+#define INAK_BO           (1<<6)
+
+//
+//  Set get device status command 
+//  
+#define CON               (1<<0)
+#define CON_CH            (1<<1)
+#define SUS               (1<<2)
+#define SUS_CH            (1<<3)
+#define RST               (1<<4)
+
+//
+//  Get error code command
+//  ...
+//
+
+//
+//  Select Endpoint command read bits 
+//
+#define EPSTAT_FE         (1<<0)
+#define EPSTAT_ST         (1<<1)
+#define EPSTAT_STP        (1<<2)
+#define EPSTAT_PO         (1<<3)
+#define EPSTAT_EPN        (1<<4)
+#define EPSTAT_B1FULL     (1<<5)
+#define EPSTAT_B2FULL     (1<<6)
+
+//
+//  CMD_EP_SET_STATUS command 
+//
+#define EP_ST             (1<<0)
+#define EP_DA             (1<<5)
+#define EP_RF_MO          (1<<6)
+#define EP_CND_ST         (1<<7)
+
+//
+//  Read error status command 
+//
+#define PID_ERR           (1<<0)
+#define UEPKT             (1<<1)
+#define DCRC              (1<<2)
+#define TIMEOUT           (1<<3)
+#define EOP               (1<<4)
+#define B_OVRN            (1<<5)
+#define BTSTF             (1<<6)
+#define TGL_ERR           (1<<7)
+
+#endif
diff --git a/usb/usbapi.h b/usb/usbapi.h
new file mode 100644 (file)
index 0000000..9ee50f4
--- /dev/null
@@ -0,0 +1,92 @@
+#include "usbstruct.h"    // for TSetupPacket
+
+/*************************************************************************
+  USB configuration
+**************************************************************************/
+
+#define MAX_PACKET_SIZE0  64    /**< maximum packet size for EP 0 */
+
+/*************************************************************************
+  USB hardware interface
+**************************************************************************/
+
+// endpoint status sent through callback
+#define EP_STATUS_DATA    (1<<0)    /**< EP has data */
+#define EP_STATUS_STALLED (1<<1)    /**< EP is stalled */
+#define EP_STATUS_SETUP   (1<<2)    /**< EP received setup packet */
+#define EP_STATUS_ERROR   (1<<3)    /**< EP data was overwritten by setup packet */
+#define EP_STATUS_NACKED  (1<<4)    /**< EP sent NAK */
+
+// device status sent through callback
+#define DEV_STATUS_CONNECT    (1<<0)  /**< device just got connected */
+#define DEV_STATUS_SUSPEND    (1<<2)  /**< device entered suspend state */
+#define DEV_STATUS_RESET    (1<<4)  /**< device just got reset */
+
+// interrupt bits for NACK events in usbHardwareNakIntEnable
+// (these bits conveniently coincide with the LPC214x USB controller bit)
+#define INACK_CI    (1<<1)      /**< interrupt on NACK for control in */
+#define INACK_CO    (1<<2)      /**< interrupt on NACK for control out */
+#define INACK_II    (1<<3)      /**< interrupt on NACK for interrupt in */
+#define INACK_IO    (1<<4)      /**< interrupt on NACK for interrupt out */
+#define INACK_BI    (1<<5)      /**< interrupt on NACK for bulk in */
+#define INACK_BO    (1<<6)      /**< interrupt on NACK for bulk out */
+
+BOOL usbHardwareInit (void);
+void usbSetupInterruptHandler (void);
+void usbHardwareNakIntEnable (U8 bIntBits);
+void usbHardwareConnect (BOOL fConnect);
+void usbHardwareSetAddress (U8 bAddr);
+void usbHardwareConfigDevice (BOOL fConfigured);
+
+//
+//  Endpoint operations
+//
+void usbHardwareEndpointConfig    (U8 bEP, U16 wMaxPacketSize);
+int  usbHardwareEndpointRead      (U8 bEP, U8 *pbBuf, int iMaxLen);
+int  usbHardwareEndpointWrite     (U8 bEP, U8 *pbBuf, int iLen);
+void usbHardwareEndpointStall     (U8 bEP, BOOL fStall);
+BOOL usbHardwareEndpointIsStalled (U8 bEP);
+
+//
+//  Endpoint interrupt handler callback
+//
+typedef int (TFnEPIntHandler) (U8 bEP, U8 bEPStatus);
+void usbHardwareRegisterEPIntHandler  (U8 bEP, TFnEPIntHandler *pfnHandler);
+
+//
+//  Device status handler callback
+//
+typedef void (TFnDevIntHandler)  (U8 bDevStatus);
+void usbHardwareRegisterDevIntHandler (TFnDevIntHandler *pfnHandler);
+
+//
+//  Frame event handler callback
+//
+typedef void (TFnFrameHandler)(U16 wFrame);
+void usbHardwareRegisterFrameHandler(TFnFrameHandler *pfnHandler);
+
+
+/*************************************************************************
+  USB application interface
+**************************************************************************/
+
+// initialise the complete stack, including HW
+BOOL usbRegisterHandlers (void);
+
+/** Request handler callback (standard, vendor, class) */
+typedef BOOL (TFnHandleRequest)(TSetupPacket *pSetup, int *piLen, U8 **ppbData);
+void usbRegisterRequestHandler (int iType, TFnHandleRequest *pfnHandler, U8 *pbDataStore);
+void usbRegisterCustomReqHandler (TFnHandleRequest *pfnHandler);
+
+/** Descriptor handler callback */
+typedef BOOL (TFnGetDescriptor)(U16 wTypeIndex, U16 wLangID, int *piLen, U8 **ppbData);
+
+/** Default standard request handler */
+BOOL usbHandleStandardRequest (TSetupPacket *pSetup, int *piLen, U8 **ppbData);
+
+/** Default EP0 handler */
+int usbHandleControlTransfer (U8 bEP, U8 bEPStat);
+
+/** Descriptor handling */
+void usbRegisterDescriptors (const U8 *pabDescriptors);
+BOOL usbGetDescriptor (U16 wTypeIndex, U16 wLangID, int *piLen, U8 **ppbData);
diff --git a/usb/usbcontrol.c b/usb/usbcontrol.c
new file mode 100644 (file)
index 0000000..a29f7d3
--- /dev/null
@@ -0,0 +1,173 @@
+/** @file
+  Control transfer handler.
+  
+  This module handles control transfers and is normally installed on the
+  endpoint 0 callback.
+  
+  Control transfers can be of the following type:
+  0 Standard;
+  1 Class;
+  2 Vendor;
+  3 Reserved.
+
+  A callback can be installed for each of these control transfers using
+  USBRegisterRequestHandler.
+  When an OUT request arrives, data is collected in the data store provided
+  with the usbRegisterRequestHandler call. When the transfer is done, the
+  callback is called.
+  When an IN request arrives, the callback is called immediately to either
+  put the control transfer data in the data store, or to get a pointer to
+  control transfer data. The data is then packetised and sent to the host.
+*/
+
+#include "FreeRTOS.h"
+
+#include "usbstruct.h"
+#include "usbapi.h"
+
+//
+//
+//
+#define MAX_CONTROL_SIZE  128 /**< maximum total size of control transfer data */
+#define MAX_REQ_HANDLERS  4   /**< standard, class, vendor, reserved */
+
+static TSetupPacket Setup;    /**< setup packet */
+
+static U8  *pbData;   /**< pointer to data buffer */
+static int iResidue;  /**< remaining bytes in buffer */
+static int iLen;      /**< total length of control transfer */
+
+static TFnHandleRequest *apfnReqHandlers [4] = { NULL, NULL, NULL, NULL };  // Array of installed request handler callbacks
+static U8 *apbDataStore [4] = { NULL, NULL, NULL, NULL };                   // Array of installed request data pointers */
+
+//
+//  Local function to handle a request by calling one of the installed
+//  request handlers.
+    
+//  In case of data going from host to device, the data is at *ppbData.
+//  In case of data going from device to host, the handler can either
+//  choose to write its data at *ppbData or update the data pointer.
+//
+static BOOL _HandleRequest (TSetupPacket *pSetup, int *piLen, U8 **ppbData)
+{
+  TFnHandleRequest *pfnHandler;
+  int iType;
+  
+  iType = REQTYPE_GET_TYPE (pSetup->bmRequestType);
+  pfnHandler = apfnReqHandlers [iType];
+
+  if (pfnHandler == NULL)
+    return FALSE;
+
+  return pfnHandler (pSetup, piLen, ppbData);
+}
+
+//
+//  Local function to stall the control endpoint
+//
+static void usbStallControlPipe (U8 bEPStat __attribute__ ((unused)))
+{
+  usbHardwareEndpointStall (0x80, TRUE);
+}
+
+//
+//  Sends next chunk of data (possibly 0 bytes) to host
+//
+static void usbDataIn (void)
+{
+  int iChunk;
+
+  iChunk = MIN (MAX_PACKET_SIZE0, iResidue);
+  usbHardwareEndpointWrite (0x80, pbData, iChunk);
+  pbData += iChunk;
+  iResidue -= iChunk;
+}
+
+//
+//  Handles IN/OUT transfers on EP0
+//
+int usbHandleControlTransfer (U8 bEP, U8 bEPStat)
+{
+  int iChunk;
+  int iType;
+
+  //
+  //  OUT transfer
+  //
+  if (bEP == 0x00) 
+  {
+    if (bEPStat & EP_STATUS_SETUP) 
+    {
+      //
+      //  Setup packet, reset request message state machine
+      //
+      usbHardwareEndpointRead (0x00, (U8 *) &Setup, sizeof (Setup));
+
+      //
+      //  Defaults for data pointer and residue
+      //
+      iType = REQTYPE_GET_TYPE (Setup.bmRequestType);
+      pbData = apbDataStore [iType];
+      iResidue = Setup.wLength;
+      iLen = Setup.wLength;
+
+      if ((Setup.wLength == 0) || (REQTYPE_GET_DIR(Setup.bmRequestType) == REQTYPE_DIR_TO_HOST)) 
+      {
+        if (!_HandleRequest (&Setup, &iLen, &pbData)) 
+        {
+          usbStallControlPipe (bEPStat);
+          return pdFALSE;
+        }
+
+        iResidue = MIN (iLen, Setup.wLength);
+        usbDataIn ();
+      }
+    }
+    else 
+    {    
+      if (iResidue > 0) 
+      {
+        iChunk = usbHardwareEndpointRead (0x00, pbData, iResidue);
+
+        if (iChunk < 0) 
+        {
+          usbStallControlPipe (bEPStat);
+          return pdFALSE;
+        }
+
+        pbData += iChunk;
+        iResidue -= iChunk;
+
+        if (iResidue == 0) 
+        {
+          iType = REQTYPE_GET_TYPE (Setup.bmRequestType);
+          pbData = apbDataStore [iType];
+
+          if (!_HandleRequest (&Setup, &iLen, &pbData)) 
+          {
+            usbStallControlPipe (bEPStat);
+            return pdFALSE;
+          }
+
+          usbDataIn ();
+        }
+      }
+      else 
+        iChunk = usbHardwareEndpointRead (0x00, NULL, 0);
+    }
+  }
+  else if (bEP == 0x80) 
+    usbDataIn ();
+
+  return pdFALSE;
+}
+
+
+//
+//  Registers a callback for handling requests
+//
+void usbRegisterRequestHandler (int iType, TFnHandleRequest *pfnHandler, U8 *pbDataStore)
+{
+  apfnReqHandlers [iType] = pfnHandler;
+  apbDataStore [iType] = pbDataStore;
+}
diff --git a/usb/usbinit.c b/usb/usbinit.c
new file mode 100644 (file)
index 0000000..02e2181
--- /dev/null
@@ -0,0 +1,30 @@
+#include "FreeRTOS.h"
+#include "usbapi.h"
+
+
+//
+//  Data storage area for standard requests
+//
+static U8 abStdReqData [8];
+
+
+//
+//  USB reset handler
+//
+static void usbHandleReset(U8 bDevStatus __attribute__ ((unused)))
+{
+}
+
+//
+//
+//
+BOOL usbRegisterHandlers (void)
+{
+  usbHardwareInit ();
+  usbHardwareRegisterDevIntHandler (usbHandleReset);
+  usbHardwareRegisterEPIntHandler (0x00, usbHandleControlTransfer);
+  usbHardwareRegisterEPIntHandler (0x80, usbHandleControlTransfer);
+  usbRegisterRequestHandler (REQTYPE_TYPE_STANDARD, usbHandleStandardRequest, abStdReqData);
+
+  return TRUE;
+}
diff --git a/usb/usbstdreq.c b/usb/usbstdreq.c
new file mode 100644 (file)
index 0000000..96edc2f
--- /dev/null
@@ -0,0 +1,349 @@
+/** @file
+  Standard request handler.
+  
+  This modules handles the 'chapter 9' processing, specifically the
+  standard device requests in table 9-3 from the universal serial bus
+  specification revision 2.0
+  
+  Specific types of devices may specify additional requests (for example
+  HID devices add a GET_DESCRIPTOR request for interfaces), but they
+  will not be part of this module.
+
+  @todo some requests have to return a request error if device not configured:
+  @todo GET_INTERFACE, GET_STATUS, SET_INTERFACE, SYNCH_FRAME
+  @todo this applies to the following if endpoint != 0:
+  @todo SET_FEATURE, GET_FEATURE 
+*/
+
+#include "usbstruct.h"
+#include "usbapi.h"
+
+#define MAX_DESC_HANDLERS 4   /**< device, interface, endpoint, other */
+
+
+//
+//  General descriptor field offsets 
+//
+#define DESC_bLength          0 /**< length offset */
+#define DESC_bDescriptorType  1 /**< descriptor type offset */  
+
+//
+//  Config descriptor field offsets 
+//
+#define CONF_DESC_wTotalLength        2 /**< total length offset */
+#define CONF_DESC_bConfigurationValue 5 /**< configuration value offset */  
+#define CONF_DESC_bmAttributes        7 /**< configuration characteristics */
+
+//
+//  Interface descriptor field offsets 
+//
+#define INTF_DESC_bAlternateSetting   3 /**< alternate setting offset */
+
+//
+//  Endpoint descriptor field offsets 
+//
+#define ENDP_DESC_bEndpointAddress    2 /**< endpoint address offset */
+#define ENDP_DESC_wMaxPacketSize      4 /**< maximum packet size offset */
+
+
+static U8 bConfiguration = 0;                       /** Currently selected configuration */
+static TFnHandleRequest *pfnHandleCustomReq = NULL; /** Installed custom request handler */
+static const U8 *pabDescrip = NULL;                 /** Pointer to registered descriptors */
+
+
+//
+//  Registers a pointer to a descriptor block containing all descriptors for the device.
+//
+void usbRegisterDescriptors (const U8 *pabDescriptors)
+{
+  pabDescrip = pabDescriptors;
+}
+
+//
+//  Parses the list of installed USB descriptors and attempts to find the specified USB descriptor.
+//
+BOOL usbGetDescriptor (U16 wTypeIndex, U16 wLangID __attribute__ ((unused)), int *piLen, U8 **ppbData)
+{
+  U8  bType, bIndex;
+  U8  *pab;
+  int iCurIndex;
+
+  bType = GET_DESC_TYPE (wTypeIndex);
+  bIndex = GET_DESC_INDEX (wTypeIndex);
+
+  pab = (U8 *)pabDescrip;
+  iCurIndex = 0;
+
+  while (pab [DESC_bLength] != 0) 
+  {
+    if (pab [DESC_bDescriptorType] == bType) 
+    {
+      if (iCurIndex == bIndex) 
+      {
+        *ppbData = pab;
+
+        if (bType == DESC_CONFIGURATION) 
+          *piLen =  (pab [CONF_DESC_wTotalLength]) | (pab [CONF_DESC_wTotalLength + 1] << 8);
+        else 
+          *piLen = pab [DESC_bLength];
+
+        return TRUE;
+      }
+
+      iCurIndex++;
+    }
+
+    pab += pab [DESC_bLength];
+  }
+
+  return FALSE;
+}
+
+//
+//  Configures the device according to the specified configuration index and
+//  alternate setting by parsing the installed USB descriptor list.
+//  A configuration index of 0 unconfigures the device.
+//
+static BOOL usbSetConfiguration (U8 bConfigIndex, U8 bAltSetting)
+{
+  U8  *pab;
+  U8  bCurConfig, bCurAltSetting;
+  U8  bEP;
+  U16 wMaxPktSize;
+
+  if (bConfigIndex == 0) 
+    usbHardwareConfigDevice(FALSE);
+  else 
+  {
+    pab = (U8 *) pabDescrip;
+    bCurConfig = 0xFF;
+    bCurAltSetting = 0xFF;
+
+    while (pab [DESC_bLength] != 0) 
+    {
+      switch (pab [DESC_bDescriptorType]) 
+      {
+        case DESC_CONFIGURATION :
+          {
+            bCurConfig = pab [CONF_DESC_bConfigurationValue];
+          }
+          break;
+
+        case DESC_INTERFACE :
+          {
+            bCurAltSetting = pab [INTF_DESC_bAlternateSetting];
+          }
+          break;
+
+        case DESC_ENDPOINT :
+          {
+            if ((bCurConfig == bConfigIndex) && (bCurAltSetting == bAltSetting)) 
+            {
+              bEP = pab [ENDP_DESC_bEndpointAddress];
+              wMaxPktSize = (pab [ENDP_DESC_wMaxPacketSize]) | (pab [ENDP_DESC_wMaxPacketSize + 1] << 8);
+              usbHardwareEndpointConfig (bEP, wMaxPktSize);
+            }
+          }
+          break;
+
+        default :
+          break;
+      }
+
+      pab += pab [DESC_bLength];
+    }
+
+    usbHardwareConfigDevice (TRUE);
+  }
+
+  return TRUE;
+}
+
+//
+//  Local function to handle a standard device request
+//
+static BOOL usbHandleStdDeviceReq (TSetupPacket *pSetup, int *piLen, U8 **ppbData)
+{
+  U8  *pbData = *ppbData;
+
+  switch (pSetup->bRequest) 
+  {
+    case REQ_GET_STATUS :
+      {
+        pbData [0] = 0;
+        pbData [1] = 0;
+        *piLen = 2;
+      }
+      break;
+
+    case REQ_SET_ADDRESS :
+      {
+        usbHardwareSetAddress (pSetup->wValue);
+      }
+      break;
+
+    case REQ_GET_DESCRIPTOR :
+      return usbGetDescriptor (pSetup->wValue, pSetup->wIndex, piLen, ppbData);
+
+    case REQ_GET_CONFIGURATION :
+      {
+        pbData [0] = bConfiguration;
+        *piLen = 1;
+      }
+      break;
+
+    case REQ_SET_CONFIGURATION :
+      {
+        if (!usbSetConfiguration(pSetup->wValue & 0xFF, 0))
+          return FALSE;
+
+        bConfiguration = pSetup->wValue & 0xFF; 
+      }
+      break;
+
+    case REQ_CLEAR_FEATURE :
+    case REQ_SET_FEATURE :
+      {
+        if (pSetup->wValue == FEA_REMOTE_WAKEUP) {
+        }
+        if (pSetup->wValue == FEA_TEST_MODE) {
+        }
+      }
+      return FALSE;
+
+    case REQ_SET_DESCRIPTOR :
+      return FALSE;
+
+    default :
+      return FALSE;
+  }
+
+  return TRUE;
+}
+
+//
+//  Local function to handle a standard interface request
+//
+static BOOL usbHandleStdInterfaceReq (TSetupPacket  *pSetup, int *piLen, U8 **ppbData)
+{
+  U8  *pbData = *ppbData;
+
+  switch (pSetup->bRequest) 
+  {
+    case REQ_GET_STATUS :
+      {
+        pbData [0] = 0;
+        pbData [1] = 0;
+        *piLen = 2;
+      }
+      break;
+
+    case REQ_CLEAR_FEATURE :
+    case REQ_SET_FEATURE :
+      return FALSE;
+
+    case REQ_GET_INTERFACE :
+      {
+        pbData [0] = 0;
+        *piLen = 1;
+      }
+      break;
+
+    case REQ_SET_INTERFACE :
+      {
+        if (pSetup->wValue != 0)
+          return FALSE;
+
+        *piLen = 0;
+      }
+      break;
+
+    default :
+      return FALSE;
+  }
+
+  return TRUE;
+}
+
+//
+//  Local function to handle a standard endpoint request
+// 
+static BOOL usbHandleStdEndPointReq (TSetupPacket *pSetup, int *piLen, U8 **ppbData)
+{
+  U8  *pbData = *ppbData;
+
+  switch (pSetup->bRequest) 
+  {
+    case REQ_GET_STATUS :
+      {
+        pbData [0] = usbHardwareEndpointIsStalled (pSetup->wIndex) ? 1 : 0;
+        pbData [1] = 0;
+        *piLen = 2;
+      }
+      break;
+
+    case REQ_CLEAR_FEATURE :
+      {
+        if (pSetup->wValue == FEA_ENDPOINT_HALT) 
+        {
+          usbHardwareEndpointStall(pSetup->wIndex, FALSE);
+          break;
+        }
+      }
+      return FALSE;
+
+    case REQ_SET_FEATURE :
+      {
+        if (pSetup->wValue == FEA_ENDPOINT_HALT) 
+        {
+          usbHardwareEndpointStall(pSetup->wIndex, TRUE);
+          break;
+        }
+      }
+      return FALSE;
+
+    case REQ_SYNCH_FRAME :
+      return FALSE;
+
+    default :
+      return FALSE;
+  }
+
+  return TRUE;
+}
+
+
+//
+//  Default handler for standard ('chapter 9') requests
+//  If a custom request handler was installed, this handler is called first.
+//
+BOOL usbHandleStandardRequest (TSetupPacket  *pSetup, int *piLen, U8 **ppbData)
+{
+  if ((pfnHandleCustomReq != NULL) && pfnHandleCustomReq (pSetup, piLen, ppbData))
+    return TRUE;
+
+  switch (REQTYPE_GET_RECIP(pSetup->bmRequestType)) 
+  {
+    case REQTYPE_RECIP_DEVICE :    return usbHandleStdDeviceReq (pSetup, piLen, ppbData);
+    case REQTYPE_RECIP_INTERFACE : return usbHandleStdInterfaceReq (pSetup, piLen, ppbData);
+    case REQTYPE_RECIP_ENDPOINT :  return usbHandleStdEndPointReq (pSetup, piLen, ppbData);
+    default :                      return FALSE;
+  }
+}
+
+//
+//  Registers a callback for custom device requests
+// 
+//  In usbHandleStandardRequest, the custom request handler gets a first
+//  chance at handling the request before it is handed over to the 'chapter 9'
+//  request handler.
+// 
+//  This can be used for example in HID devices, where a REQ_GET_DESCRIPTOR
+//  request is sent to an interface, which is not covered by the 'chapter 9'
+//  specification.
+//    
+void usbRegisterCustomReqHandler (TFnHandleRequest *pfnHandler)
+{
+  pfnHandleCustomReq = pfnHandler;
+}
+
diff --git a/usb/usbstruct.h b/usb/usbstruct.h
new file mode 100644 (file)
index 0000000..ee02a75
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+  LPCUSB, an USB device driver for LPC microcontrollers 
+  Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+  2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+  3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 
+  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+/**
+  Definitions of structures of standard USB packets
+*/
+
+#ifndef _USBSTRUCT_H_
+#define _USBSTRUCT_H_
+
+#include "sysdefs.h"
+
+//
+//  Setup packet definitions
+//
+typedef struct 
+{
+  U8  bmRequestType;  /**< characteristics of the specific request */
+  U8  bRequest;       /**< specific request */
+  U16 wValue;         /**< request specific parameter */
+  U16 wIndex;         /**< request specific parameter */
+  U16 wLength;        /**< length of data transfered in data phase */
+} 
+TSetupPacket;
+
+
+#define REQTYPE_GET_DIR(x)      (((x)>>7)&0x01)
+#define REQTYPE_GET_TYPE(x)     (((x)>>5)&0x03)
+#define REQTYPE_GET_RECIP(x)    ((x)&0x1F)
+
+#define REQTYPE_DIR_TO_DEVICE   0
+#define REQTYPE_DIR_TO_HOST     1
+
+#define REQTYPE_TYPE_STANDARD   0
+#define REQTYPE_TYPE_CLASS      1
+#define REQTYPE_TYPE_VENDOR     2
+#define REQTYPE_TYPE_RESERVED   3
+
+#define REQTYPE_RECIP_DEVICE    0
+#define REQTYPE_RECIP_INTERFACE 1
+#define REQTYPE_RECIP_ENDPOINT  2
+#define REQTYPE_RECIP_OTHER     3
+
+//
+//  Standard requests 
+//
+#define REQ_GET_STATUS        0x00
+#define REQ_CLEAR_FEATURE     0x01
+#define REQ_SET_FEATURE       0x03
+#define REQ_SET_ADDRESS       0x05
+#define REQ_GET_DESCRIPTOR    0x06
+#define REQ_SET_DESCRIPTOR    0x07
+#define REQ_GET_CONFIGURATION 0x08
+#define REQ_SET_CONFIGURATION 0x09
+#define REQ_GET_INTERFACE     0x0A
+#define REQ_SET_INTERFACE     0x0B
+#define REQ_SYNCH_FRAME       0x0C
+
+//
+//  Class requests HID 
+//
+#define HID_GET_REPORT      0x01
+#define HID_GET_IDLE        0x02
+#define HID_GET_PROTOCOL    0x03
+#define HID_SET_REPORT      0x09
+#define HID_SET_IDLE        0x0A
+#define HID_SET_PROTOCOL    0x0B
+
+//
+//  Feature selectors 
+//
+#define FEA_ENDPOINT_HALT   0x00
+#define FEA_REMOTE_WAKEUP   0x01
+#define FEA_TEST_MODE       0x02
+
+//
+//  USB descriptor header
+//
+typedef struct 
+{
+  U8  bLength;          /**< descriptor length */
+  U8  bDescriptorType;  /**< descriptor type */
+} 
+TUSBDescHeader;
+
+#define DESC_DEVICE           1
+#define DESC_CONFIGURATION    2
+#define DESC_STRING           3
+#define DESC_INTERFACE        4
+#define DESC_ENDPOINT         5
+#define DESC_DEVICE_QUALIFIER 6
+#define DESC_OTHER_SPEED      7
+#define DESC_INTERFACE_POWER  8
+
+#define DESC_HID_HID        0x21
+#define DESC_HID_REPORT     0x22
+#define DESC_HID_PHYSICAL   0x23
+
+#define GET_DESC_TYPE(x)    (((x)>>8)&0xFF)
+#define GET_DESC_INDEX(x)   ((x)&0xFF)
+
+#endif
diff --git a/usbmass/Makefile b/usbmass/Makefile
new file mode 100644 (file)
index 0000000..0692453
--- /dev/null
@@ -0,0 +1,25 @@
+SRC_FILES=mscblock.c mscbot.c mscscsi.c usbmass.c mscspi.c
+
+#
+# Define all object files.
+#
+ARM_OBJ = $(SRC_FILES:.c=.o)
+
+.PHONY: all
+all: $(ARM_OBJ)
+
+$(ARM_OBJ) : %.o : %.c Makefile .depend
+       $(CC) -c $(CFLAGS) $< -o $@
+       $(AR) r $(COMMON)/common.a $@
+
+#
+#  The .depend files contains the list of header files that the
+#  various source files depend on.  By doing this, we'll only
+#  rebuild the .o's that are affected by header files changing.
+#
+.depend:
+                       $(CC) $(CFLAGS) -M $(SRC_FILES) > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff --git a/usbmass/mscblock.c b/usbmass/mscblock.c
new file mode 100644 (file)
index 0000000..0f6d5a1
--- /dev/null
@@ -0,0 +1,367 @@
+/*****************************************************************************\
+*              efs - General purpose Embedded Filesystem library              *
+*          --------------------- -----------------------------------          *
+*                                                                             *
+* Filename : sd.c                                                             *
+* Revision : Initial developement                                             *
+* Description : This file contains the functions needed to use efs for        *
+*               accessing files on an SD-card.                                *
+*                                                                             *
+* This library is free software; you can redistribute it and/or               *
+* modify it under the terms of the GNU Lesser General Public                  *
+* License as published by the Free Software Foundation; either                *
+* version 2.1 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           *
+* Lesser General Public License for more details.                             *
+*                                                                             *
+*                                                    (c)2005 Michael De Nil   *
+*                                                    (c)2005 Lennart Yseboodt *
+\*****************************************************************************/
+
+/*
+  2006, Bertrik Sikken, modified for LPCUSB
+*/
+
+#include "FreeRTOS.h"
+
+#include <stdio.h>
+
+#include "../fatfs/diskio.h"
+#include "../fatfs/ff.h"
+#include "../fatfs/mmc.h"
+#include "../fatfs/spi.h"
+#include "mscdebug.h"
+#include "mscblock.h"
+#include "mscspi.h"
+
+//
+//
+//
+#define CMD_GOIDLESTATE      0
+#define CMD_SENDOPCOND       1
+#define CMD_READCSD          9
+#define CMD_READCID         10
+#define CMD_SENDSTATUS      13
+#define CMD_READSINGLEBLOCK 17
+#define CMD_WRITE           24
+#define CMD_WRITE_MULTIPLE  25
+
+//
+//
+//
+static void mscblockCommand (U8 cmd, U32 param)
+{
+  U8  abCmd [8];
+
+  abCmd [0] = 0xff;
+  abCmd [1] = 0x40 | cmd;
+  abCmd [2] = (U8)(param >> 24);
+  abCmd [3] = (U8)(param >> 16);
+  abCmd [4] = (U8)(param >> 8);
+  abCmd [5] = (U8)(param);
+  abCmd [6] = 0x95;     /* Checksum (should be only valid for first command (0) */
+  abCmd [7] = 0xff;     /* eat empty command - response */
+
+  mscspiSendBlock (abCmd, 8);
+}
+
+//
+//
+//
+static U8 mscblockResp8b (void)
+{
+  U8 i;
+  U8 resp;
+
+  /* Respone will come after 1 - 8 pings */
+  for (i = 0; i < 8; i++)
+    if ((resp = mscspiTransferByte (0xff)) != 0xff)
+      return resp;
+
+  return resp;
+}
+
+//
+//
+//
+static void mscblockResp8bError (U8 value)
+{
+  switch (value) 
+  {
+    case 0x40 : DBG ("Argument out of bounds.\n");                break;
+    case 0x20 : DBG ("Address out of bounds.\n");                 break;
+    case 0x10 : DBG ("Error during erase sequence.\n");           break;
+    case 0x08 : DBG ("CRC failed.\n");                            break;
+    case 0x04 : DBG ("Illegal command.\n");                       break;
+    case 0x02 : DBG ("Erase reset (see SanDisk docs p5-13).\n");  break;
+    case 0x01 : DBG ("Card is initialising.\n");                  break;
+    default   : DBG ("Unknown error 0x%x (see SanDisk docs p5-13).\n", value); break;
+  }
+}
+
+//
+//  Calculates size of card from CSD 
+//    (extension by Martin Thomas, inspired by code from Holger Klabunde)
+//
+int mscblockGetSize (U32 *pdwDriveSize)
+{
+  U8 cardresp, i, by;
+  U8 iob [16];
+  U16 c_size, c_size_mult, read_bl_len;
+
+  mscblockCommand (CMD_READCSD, 0);
+
+  do {
+    cardresp = mscblockResp8b ();
+  } 
+  while (cardresp != 0xfe);
+
+  DBG ("CSD:");
+
+  for (i = 0; i < 16; i++) 
+  {
+    iob [i] = mscspiTransferByte (0xff);
+    DBG (" %02x", iob [i]);
+  }
+
+  DBG("\n");
+
+  mscspiTransferByte (0xff);
+  mscspiTransferByte (0xff);
+
+  c_size = iob [6] & 0x03;
+  c_size <<= 10;
+  c_size += (U16) iob [7] << 2;
+  c_size += iob [8] >> 6;
+
+  by = iob [5] & 0x0f;
+  read_bl_len = 1 << by;
+
+  by = iob [9] & 0x03;
+  by <<= 1;
+  by += iob [10] >> 7;
+
+  c_size_mult = 1 << (2 + by);
+
+  *pdwDriveSize = (U32) (c_size + 1) * (U32) c_size_mult * (U32) read_bl_len;
+
+  return 0;
+}
+
+//
+//
+//
+static U16 mscblockResp16b (void)
+{
+  U16 resp;
+
+  resp = (mscblockResp8b() << 8) & 0xff00;
+  resp |= mscspiTransferByte(0xff);
+
+  return resp;
+}
+
+//
+//
+//
+static int mscblockState (void)
+{
+  U16 value;
+
+  mscblockCommand (CMD_SENDSTATUS, 0);
+  value = mscblockResp16b ();
+
+  switch (value) 
+  {
+    case 0x0000 : return 1;
+    case 0x0001 : DBG ("Card is Locked.\n");                                                 break;
+    case 0x0002 : DBG ("WP Erase Skip, Lock/Unlock Cmd Failed.\n");                          break;
+    case 0x0004 : DBG ("General / Unknown error -- card broken?.\n");                        break;
+    case 0x0008 : DBG ("Internal card controller error.\n");                                 break;
+    case 0x0010 : DBG ("Card internal ECC was applied, but failed to correct the data.\n");  break;
+    case 0x0020 : DBG ("Write protect violation.\n");                                        break;
+    case 0x0040 : DBG ("An invalid selection, sectors for erase.\n");                        break;
+    case 0x0080 : DBG ("Out of Range, CSD_Overwrite.\n");                                    break;
+    default     : if (value > 0x00ff)
+                    mscblockResp8bError ((U8) (value >> 8));
+                  else
+                    DBG ("Unknown error: 0x%x (see SanDisk docs p5-14).\n", value);
+                  break;
+  }
+
+  return -1;
+}
+
+//
+//
+//
+int mscblockInit (void)
+{
+  FRESULT f;
+
+  //
+  //  We'll see the error because it means we *must* be using a serial
+  //  console, since we can't use USB for MSC and VCOM at the same time.
+  //
+  mscspiInit (); 
+
+#if 1
+  if ((f = diskInitialize (0)) != FR_OK)
+    f_printerror (f);
+#endif
+
+#if 0
+  U8 resp;
+  int i;
+
+  // 
+  //  Try to send reset command up to 100 times 
+  //
+  i = 100;
+
+  do 
+  {
+    mscblockCommand (CMD_GOIDLESTATE, 0);
+    resp = mscblockResp8b ();
+  } 
+  while (resp != 1 && i--);
+
+  if (resp != 1) 
+  {
+    if (resp == 0xff) 
+    {
+      DBG ("resp=0xff\n");
+      return -1;
+    }
+    else 
+    {
+      mscblockResp8bError (resp);
+      DBG ("resp!=0xff\n");
+      return -2;
+    }
+  }
+
+  //
+  //  Wait till card is ready initialising (returns 0 on CMD_1)
+  //  Try up to 32000 times. */
+  //
+  i = 32000;
+
+  do 
+  {
+    mscblockCommand (CMD_SENDOPCOND, 0);
+
+    if ((resp = mscblockResp8b ()) != 0)
+      mscblockResp8bError (resp);
+  } 
+  while (resp == 1 && i--);
+
+  if (resp != 0) 
+  {
+    mscblockResp8bError (resp);
+    return -3;
+  }
+
+  //
+  //  Increase speed after init 
+  //
+  // mscspiSetSpeed (SPI_PRESCALE_MIN);
+#endif
+
+  if (mscblockState () < 0) 
+  {
+    DBG ("Card didn't return the ready state, breaking up...\n");
+    return -2;
+  }
+
+  DBG ("Init done...\n");
+
+  return 0;
+}
+
+//
+// WAIT ?? -- FIXME
+// CMD_WRITE
+// WAIT
+// CARD RESP
+// WAIT
+// DATA BLOCK OUT
+//      START BLOCK
+//      DATA
+//      CHKS (2B)
+// BUSY...
+//
+int mscblockWrite (U32 dwAddress, U8 * pbBuf)
+{
+  U32 place;
+  U16 t = 0;
+
+  place = 512 * dwAddress;
+  mscblockCommand (CMD_WRITE, place);
+
+  mscblockResp8b ();       /* Card response */
+
+  mscspiTransferByte (0xfe);      /* Start block */
+  mscspiSendBlock (pbBuf, 512);
+  mscspiTransferByte (0xff);      /* Checksum part 1 */
+  mscspiTransferByte (0xff);      /* Checksum part 2 */
+
+  mscspiTransferByte (0xff);
+
+  while (spiTransferByte (0xff) != 0xff)
+    t++;
+
+  return 0;
+}
+
+//
+// WAIT ?? -- FIXME
+// CMD_CMD_
+// WAIT
+// CARD RESP
+// WAIT
+// DATA BLOCK IN
+//    START BLOCK
+//    DATA
+//    CHKS (2B)
+//
+int mscblockRead (U32 dwAddress, U8 * pbBuf)
+{
+  U8 cardresp;
+  U8 firstblock;
+  U16 fb_timeout = 0xffff;
+  U32 place;
+
+  place = 512 * dwAddress;
+  mscblockCommand (CMD_READSINGLEBLOCK, place);
+
+  cardresp = mscblockResp8b ();
+
+  //
+  //  Wait for startblock
+  //
+  do 
+  {
+    firstblock = mscblockResp8b();
+  } 
+  while (firstblock == 0xff && fb_timeout--);
+
+  if (cardresp != 0x00 || firstblock != 0xfe) 
+  {
+    mscblockResp8bError (firstblock);
+    return -1;
+  }
+
+  mscspiReceiveBlock (pbBuf, 512);
+
+  //
+  //  Checksum (2 byte) - ignore for now 
+  //
+  mscspiTransferByte (0xff);
+  mscspiTransferByte (0xff);
+
+  return 0;
+}
diff --git a/usbmass/mscblock.h b/usbmass/mscblock.h
new file mode 100644 (file)
index 0000000..fda5109
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+       LPCUSB, an USB device driver for LPC microcontrollers   
+       Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
+
+       Redistribution and use in source and binary forms, with or without
+       modification, are permitted provided that the following conditions are met:
+
+       1. Redistributions of source code must retain the above copyright
+          notice, this list of conditions and the following disclaimer.
+       2. Redistributions in binary form must reproduce the above copyright
+          notice, this list of conditions and the following disclaimer in the
+          documentation and/or other materials provided with the distribution.
+       3. The name of the author may not be used to endorse or promote products
+          derived from this software without specific prior written permission.
+
+       THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+       IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+       OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+       IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 
+       INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+       NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+       DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+       THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+       (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+       THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _MSCBLOCK_H_
+#define _MSCBLOCK_H_
+
+#include "sysdefs.h"
+
+int mscblockInit (void);
+int mscblockWrite (U32 dwAddress, U8* pbBuf);
+int mscblockRead (U32 dwAddress, U8* pbBuf);
+int mscblockGetSize (U32 *pdwDriveSize);
+int mscblockGetStatus (void);
+
+#endif
diff --git a/usbmass/mscbot.c b/usbmass/mscbot.c
new file mode 100644 (file)
index 0000000..e813eef
--- /dev/null
@@ -0,0 +1,443 @@
+/*
+  LPCUSB, an USB device driver for LPC microcontrollers 
+  Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+  2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+  3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 
+  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/** @file
+
+  Bulk-only-transfer layer for mass storage.
+  
+  This layers sits between the generic USB layers and the SCSI layer
+  and performs data transfer according to the BOT protocol.
+*/
+
+#include "FreeRTOS.h"
+
+#include <string.h>
+
+#include "../usb/usbapi.h"
+
+#include "mscdebug.h"
+#include "mscbot.h"
+#include "mscscsi.h"
+
+//
+// Command block wrapper structure
+//
+typedef struct 
+{
+  U32   dwCBWSignature;
+  U32   dwCBWTag;
+  U32   dwCBWDataTransferLength;
+  U8    bmCBWFlags;
+  U8    bCBWLun;
+  U8    bCBWCBLength;
+  U8    CBWCB[16];
+} 
+TCBW;
+
+//
+//  Command status wrapper structure 
+//
+typedef struct 
+{
+  U32   dwCSWSignature;
+  U32   dwCSWTag;
+  U32   dwCSWDataResidue;
+  U8    bmCSWStatus;
+} 
+TCSW;
+
+//
+//  States of BOT state machine 
+//
+typedef enum 
+{
+  eCBW,
+  eDataOut,
+  eDataIn,
+  eCSW,
+  eStalled
+} 
+EBotState;
+
+//
+//
+//
+#define CBW_SIGNATURE 0x43425355    /**< magic word in CBW */
+#define CSW_SIGNATURE 0x53425355    /**< magic word in CSW */
+
+#define STATUS_PASSED   0x00    /**< successful transfer */
+#define STATUS_FAILED   0x01    /**< failed transfer */
+#define STATUS_PHASE_ERR  0x02    /**< conflict between host and device */
+
+static U32 dwTransferSize;   /**< total size of data transfer */
+static U32 dwOffset;     /**< offset in current data transfer */
+static TCBW CBW;
+static TCSW CSW;
+static EBotState  eState;
+static U8 *pbData;
+
+//
+//  Prepares a CSW, to be sent on next bulk-IN interrupt
+//    
+//  @param [in] bStatus CSW status
+//
+static void mscbotSendCSW (U8 bStatus)
+{
+  int iResidue;
+  
+  iResidue = CBW.dwCBWDataTransferLength - dwTransferSize;
+  
+  // construct CSW
+  CSW.dwCSWSignature = CSW_SIGNATURE;
+  CSW.dwCSWTag = CBW.dwCBWTag;
+  CSW.dwCSWDataResidue = MAX (iResidue, 0);
+  CSW.bmCSWStatus = bStatus;
+
+  DBG ("CSW: status=%x, residue=%d\n", bStatus, CSW.dwCSWDataResidue);
+
+  // next state
+  eState = eCSW;
+}
+
+//
+//  Checks if CBW is valid and meaningful
+//    
+//  @param [in] pCBW  Command block wrapper
+//  @param [in] iLen  Length of CBW
+//      
+//  @return TRUE if valid and meaningful
+//
+static BOOL mscbotCheckCBW (TCBW *pCBW, int iLen)
+{
+  //
+  // CBW valid?
+  //
+  if (iLen != 31) 
+  {
+    DBG ("Invalid length (%d)\n", iLen);
+    return FALSE;
+  }
+
+  if (pCBW->dwCBWSignature != CBW_SIGNATURE) 
+  {
+    DBG ("Invalid signature %x\n", pCBW->dwCBWSignature);
+    return FALSE;
+  }
+
+  //
+  // CBW meaningful?
+  //
+  if (pCBW->bCBWLun != 0) 
+  {
+    DBG ("Invalid LUN %d\n", pCBW->bCBWLun);
+    return FALSE;
+  }
+
+  if ((pCBW->bCBWCBLength < 1) || (pCBW->bCBWCBLength > 16)) 
+  {
+    DBG ("Invalid CB len %d\n", pCBW->bCBWCBLength);
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+//
+//  mscbotBOTStall
+//    Local function to stall ongoing transfer
+//    
+//  Which endpoint to stall is determined by looking at the transfer
+//  direction intended by the host.
+//
+static void mscbotBOTStall (void)
+{
+  if ((CBW.bmCBWFlags & 0x80) || (CBW.dwCBWDataTransferLength == 0)) 
+    usbHardwareEndpointStall (MSC_BULK_IN_EP, TRUE);
+  else 
+    usbHardwareEndpointStall (MSC_BULK_OUT_EP, TRUE);
+}
+
+//
+//  mscbotHandleDataIn
+//    Handles data from device-to-host
+//    
+static void mscbotHandleDataIn (void)
+{
+  int iChunk;
+  
+  //
+  //  Process data for host in SCSI layer
+  //
+  if ((pbData = mscscsiHandleData (CBW.CBWCB, CBW.bCBWCBLength, pbData, dwOffset)) == NULL)
+  {
+    mscbotBOTStall ();
+    mscbotSendCSW (STATUS_FAILED);
+    return;
+  }
+
+  //
+  //  Send data to host?
+  //
+  if (dwOffset < dwTransferSize) 
+  {
+    iChunk = MIN (64, dwTransferSize - dwOffset);
+    usbHardwareEndpointWrite (MSC_BULK_IN_EP, pbData, iChunk);
+    dwOffset += iChunk;
+  }
+  
+  //
+  // are we done now?
+  //
+  if (dwOffset == dwTransferSize) 
+  {
+    if (dwOffset != CBW.dwCBWDataTransferLength) 
+    {
+      DBG ("stalling DIN");
+      mscbotBOTStall ();
+    }
+
+    //
+    //  Done
+    //
+    mscbotSendCSW (STATUS_PASSED);
+  }
+}
+
+//
+//  mscbotHandleDataOut
+//    Handles data from host-to-device
+//
+static void mscbotHandleDataOut (void)
+{
+  int iChunk;
+
+  if (dwOffset < dwTransferSize) 
+  {
+    iChunk = usbHardwareEndpointRead (MSC_BULK_OUT_EP, pbData, dwTransferSize - dwOffset);
+    pbData = mscscsiHandleData (CBW.CBWCB, CBW.bCBWCBLength, pbData, dwOffset);
+
+    if (pbData == NULL) 
+    {
+      mscbotBOTStall ();
+      mscbotSendCSW (STATUS_FAILED);
+      return;
+    }
+
+    dwOffset += iChunk;
+  }
+
+  //
+  //  Are we done now?
+  //
+  if (dwOffset == dwTransferSize) 
+  {
+    if (dwOffset != CBW.dwCBWDataTransferLength) 
+    {
+      DBG ("stalling DOUT");
+      mscbotBOTStall ();
+    }
+
+    mscbotSendCSW (STATUS_PASSED);
+  }
+}
+    
+//
+//  Resets the BOT state machine
+//
+void mscbotReset (void)
+{
+  DBG ("BOT reset in state %d\n", eState);
+  eState = eCBW;
+  mscscsiReset ();
+}
+
+//
+//   Handles the BOT bulk OUT endpoint
+//     
+//   @param [in] bEP     Endpoint number
+//   @param [in] bEPStatus Endpoint status (indicates NAK, STALL, etc)
+//     
+int mscbotBulkOut (U8 bEP, U8 bEPStatus)
+{
+  unsigned int iLen, iChunk;
+  BOOL fHostIn, fDevIn;
+
+  //
+  //  Ignore events on stalled EP
+  //
+  if (bEPStatus & EP_STATUS_STALLED)
+    return 0;
+
+  switch (eState) 
+  {
+    case eCBW:
+      {
+        iLen = usbHardwareEndpointRead (bEP, (U8 *)&CBW, sizeof(CBW));
+
+        if (!mscbotCheckCBW(&CBW, iLen)) 
+        {
+          usbHardwareEndpointStall (MSC_BULK_IN_EP, TRUE);
+          usbHardwareEndpointStall (MSC_BULK_OUT_EP, TRUE);
+          eState = eStalled;
+          break;
+        }
+
+        DBG ("CBW: len=%d, flags=%x, cmd=%x, cmdlen=%d\n", CBW.dwCBWDataTransferLength, CBW.bmCBWFlags, CBW.CBWCB[0], CBW.bCBWCBLength);
+
+        dwOffset = 0;
+        dwTransferSize = 0;
+        fHostIn = ((CBW.bmCBWFlags & 0x80) != 0);
+
+        //
+        //  Verify request.  Unknown command if NULL
+        //
+        if ((pbData = mscscsiHandleCmd (CBW.CBWCB, CBW.bCBWCBLength, &iLen, &fDevIn)) == NULL)
+        {
+          mscbotBOTStall ();
+          mscbotSendCSW (STATUS_FAILED);
+          break;      
+        }
+
+        //
+        //  Rule: if device and host disagree on direction, send CSW with status 2
+        //
+        if ((iLen > 0) && ((fHostIn && !fDevIn) || (!fHostIn && fDevIn))) 
+        {
+          DBG ("Host and device disagree on direction\n");
+          mscbotBOTStall ();
+          mscbotSendCSW (STATUS_PHASE_ERR);
+          break;
+        }
+
+        //
+        //  Rule: if D > H, send CSW with status 2
+        //
+        if (iLen > CBW.dwCBWDataTransferLength) 
+        {
+          DBG ("Negative residue\n");
+          mscbotBOTStall ();
+          mscbotSendCSW (STATUS_PHASE_ERR);
+          break;
+        }
+
+        if (((dwTransferSize = iLen) == 0) || fDevIn) 
+        {
+          //
+          //  Data from device-to-host
+          //
+          eState = eDataIn;
+          mscbotHandleDataIn ();
+        }
+        else 
+        {
+          //
+          //  Data from host-to-device
+          //
+          eState = eDataOut;
+        }
+      }
+      break;
+
+    case eDataOut:
+      {
+        mscbotHandleDataOut ();
+      }
+      break;
+
+    case eDataIn:
+    case eCSW:
+      {
+        iChunk = usbHardwareEndpointRead (bEP, NULL, 0);
+        DBG ("Phase error in state %d, %d bytes\n", eState, iChunk);
+        eState = eCBW;
+      }
+      break;
+
+    case eStalled:
+      {
+        usbHardwareEndpointStall (MSC_BULK_OUT_EP, TRUE);
+      }
+      break;
+
+    default:
+      {
+        DBG ("Invalid state %d\n", eState);
+        ASSERT (FALSE);
+      }
+      break;
+  }
+
+  return 0;
+}
+
+//
+//   Handles the BOT bulk IN endpoint
+//     
+//   @param [in] bEP     Endpoint number
+//   @param [in] bEPStatus Endpoint status (indicates NAK, STALL, etc)
+//     
+int mscbotBulkIn (U8 bEP __attribute__ ((unused)), U8 bEPStatus)
+{
+  if (bEPStatus & EP_STATUS_STALLED)
+    return 0;
+
+  switch (eState) 
+  {
+    //
+    //  Ignore possibly old ACKs
+    //
+    case eCBW:
+    case eDataOut:
+      break;
+
+    case eDataIn:
+      mscbotHandleDataIn ();
+      break;
+
+    //
+    //  Wait for an IN token, then send the CSW
+    //
+    case eCSW:
+      usbHardwareEndpointWrite (MSC_BULK_IN_EP, (U8 *)&CSW, 13);
+      eState = eCBW;
+      break;
+
+    //
+    //  Keep stalling
+    //
+    case eStalled:
+      usbHardwareEndpointStall (MSC_BULK_IN_EP, TRUE);
+      break;
+
+    default:
+      DBG ("Invalid state %d\n", eState);
+      ASSERT (FALSE);
+      break;
+  }
+
+  return 0;
+}
diff --git a/usbmass/mscbot.h b/usbmass/mscbot.h
new file mode 100644 (file)
index 0000000..8e301bf
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+       LPCUSB, an USB device driver for LPC microcontrollers   
+       Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
+
+       Redistribution and use in source and binary forms, with or without
+       modification, are permitted provided that the following conditions are met:
+
+       1. Redistributions of source code must retain the above copyright
+          notice, this list of conditions and the following disclaimer.
+       2. Redistributions in binary form must reproduce the above copyright
+          notice, this list of conditions and the following disclaimer in the
+          documentation and/or other materials provided with the distribution.
+       3. The name of the author may not be used to endorse or promote products
+          derived from this software without specific prior written permission.
+
+       THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+       IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+       OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+       IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 
+       INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+       NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+       DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+       THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+       (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+       THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _MSCBOT_H_
+#define _MSCBOT_H_
+
+#include "sysdefs.h"
+
+#define MSC_BULK_OUT_EP                0x02
+#define MSC_BULK_IN_EP         0x85
+
+void mscbotReset (void);
+int mscbotBulkOut (U8 bEP, U8 bEPStatus);
+int mscbotBulkIn (U8 bEP, U8 bEPStatus);
+
+#endif
diff --git a/usbmass/mscdebug.h b/usbmass/mscdebug.h
new file mode 100644 (file)
index 0000000..953a523
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+       LPCUSB, an USB device driver for LPC microcontrollers   
+       Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
+
+       Redistribution and use in source and binary forms, with or without
+       modification, are permitted provided that the following conditions are met:
+
+       1. Redistributions of source code must retain the above copyright
+          notice, this list of conditions and the following disclaimer.
+       2. Redistributions in binary form must reproduce the above copyright
+          notice, this list of conditions and the following disclaimer in the
+          documentation and/or other materials provided with the distribution.
+       3. The name of the author may not be used to endorse or promote products
+          derived from this software without specific prior written permission.
+
+       THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+       IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+       OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+       IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 
+       INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+       NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+       DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+       THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+       (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+       THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _USBDEBUG_H_
+#define _USBDEBUG_H_
+
+#include <stdio.h>
+
+#ifdef USBDEBUG
+#define DBG    printf
+#define ASSERT(x)      if(!(x)){DBG("\nAssertion '%s' failed in %s:%s#%d!\n",#x,__FILE__,__FUNCTION__,__LINE__);while(1);}
+#else
+#define DBG(x ...) do { } while (0)
+#define ASSERT(x) do { } while (0)
+#endif
+
+#endif
diff --git a/usbmass/mscscsi.c b/usbmass/mscscsi.c
new file mode 100644 (file)
index 0000000..1690b55
--- /dev/null
@@ -0,0 +1,334 @@
+/*
+  LPCUSB, an USB device driver for LPC microcontrollers 
+  Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+  2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+  3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 
+  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/**
+  @file
+
+  This is the SCSI layer of the USB mass storage application example.
+  This layer depends directly on the blockdev layer.
+  
+  Windows peculiarities:
+  * Size of REQUEST SENSE CDB is 12 bytes instead of expected 6
+  * Windows requires VERIFY(10) command to do a format.
+    This command is not mandatory in the SBC/SBC-2 specification.
+*/
+
+#include "FreeRTOS.h"
+
+#include <string.h>   // memcpy
+
+#include "mscdebug.h"
+#include "mscblock.h"
+#include "mscscsi.h"
+
+//
+//
+//
+#define BLOCKSIZE   512
+
+//
+//  SBC2 mandatory SCSI commands
+//
+#define SCSI_CMD_TEST_UNIT_READY  0x00
+#define SCSI_CMD_REQUEST_SENSE    0x03
+#define SCSI_CMD_FORMAT_UNIT      0x04
+#define SCSI_CMD_READ_6           0x08  /* not implemented yet */
+#define SCSI_CMD_INQUIRY          0x12
+#define SCSI_CMD_SEND_DIAGNOSTIC  0x1D  /* not implemented yet */
+#define SCSI_CMD_READ_CAPACITY_10 0x25
+#define SCSI_CMD_READ_10          0x28
+#define SCSI_CMD_REPORT_LUNS      0xa0  /* not implemented yet */
+
+//
+//  SBC2 optional SCSI commands
+//
+#define SCSI_CMD_WRITE_6          0x0a  /* not implemented yet */
+#define SCSI_CMD_WRITE_10         0x2a
+#define SCSI_CMD_VERIFY_10        0x2f  /* required for windows format */
+
+//
+//  Sense codes
+//
+#define WRITE_ERROR           0x030C00
+#define READ_ERROR            0x031100
+#define INVALID_CMD_OPCODE    0x052000
+#define INVALID_FIELD_IN_CDB  0x052400
+
+//
+//  Sense code, which is set on error conditions
+//  Hex: 00aabbcc, where aa=KEY, bb=ASC, cc=ASCQ
+//
+static U32 dwSense;  
+
+static const U8   abInquiry[] = 
+{
+  0x00,   // PDT = direct-access device
+  0x80,   // removeable medium bit = set
+  0x05,   // version = complies to SPC3
+  0x02,   // response data format = SPC3
+  0x1F,   // additional length
+  0x00,
+  0x00,
+  0x00,
+  'L','P','C','U','S','B',' ',' ',  // vendor
+  'M','a','s','s',' ','s','t','o',  // product
+  'r','a','g','e',' ',' ',' ',' ',
+  '0','.','1',' '                   // revision
+};
+
+//
+//  Data for "request sense" command. The 0xFF are filled in later
+//
+static const U8 abSense[] = { 0x70, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0A, 
+                              0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+                              0x00, 0x00 };
+
+//
+//  Buffer for holding one block of disk data
+//
+static U8 abBlockBuf [512];
+
+typedef struct 
+{
+  U8    bOperationCode;
+  U8    abLBA [3];
+  U8    bLength;
+  U8    bControl;
+} 
+TCDB6;
+
+//
+//
+//
+void mscscsiReset (void)
+{
+  dwSense = 0;
+}
+
+//
+//  SCSIHandleCmd
+//    Verifies a SCSI CDB and indicates the direction and amount of data
+//    that the device wants to transfer.
+//    
+//  If this call fails, a sense code is set in dwSense.
+//
+//  IN  pbCDB     - Command data block
+//      iCDBLen   - Command data block len
+//  OUT *piRspLen - Length of intended response data:
+//      *pfDevIn  - TRUE if data is transferred from device-to-host
+//  
+//  Returns a pointer to the data exchange buffer if successful,
+//  return NULL otherwise.
+//
+U8 *mscscsiHandleCmd (U8 *pbCDB, U8 iCDBLen, unsigned int *piRspLen, BOOL *pfDevIn)
+{
+  static const U8 aiCDBLen [] = {6, 10, 10, 0, 16, 12, 0, 0};
+  int   i;
+  TCDB6 *pCDB;
+  U32   dwLen, dwLBA;
+  U8    bGroupCode;
+
+  pCDB = (TCDB6 *) pbCDB;
+
+  // default direction is from device to host
+  *pfDevIn = TRUE;
+
+  // check CDB length
+  bGroupCode = (pCDB->bOperationCode >> 5) & 0x7;
+
+  if (iCDBLen < aiCDBLen[bGroupCode]) 
+  {
+    DBG("Invalid CBD len (expected %d)!\n", aiCDBLen[bGroupCode]);
+    return NULL;
+  }
+
+  switch (pCDB->bOperationCode) 
+  {
+    case SCSI_CMD_TEST_UNIT_READY :
+      DBG ("TEST UNIT READY\n");
+      *piRspLen = 0;
+      break;
+
+    case SCSI_CMD_REQUEST_SENSE :
+      DBG ("REQUEST SENSE (%06X)\n", dwSense);
+      *piRspLen = MIN (18, pCDB->bLength);
+      break;
+
+    case SCSI_CMD_FORMAT_UNIT :
+      DBG ("FORMAT UNIT %02X\n", pbCDB[1]);
+      *piRspLen = 0;
+      break;
+
+    case SCSI_CMD_INQUIRY :
+      DBG ("INQUIRY\n");
+      *piRspLen = MIN (36, pCDB->bLength);
+      break;
+
+    case SCSI_CMD_READ_CAPACITY_10 :
+      DBG ("READ CAPACITY\n");
+      *piRspLen = 8;
+      break;
+
+    case SCSI_CMD_READ_10 :
+      dwLBA = (pbCDB [2] << 24) | (pbCDB [3] << 16) | (pbCDB [4] << 8) | (pbCDB [5]);
+      dwLen = (pbCDB [7] << 8) | pbCDB [8];
+      DBG ("READ10, LBA=%d, len=%d\n", dwLBA, dwLen);
+      *piRspLen = dwLen * BLOCKSIZE;
+      break;
+
+    case SCSI_CMD_WRITE_10 :
+      dwLBA = (pbCDB [2] << 24) | (pbCDB [3] << 16) | (pbCDB [4] << 8) | (pbCDB [5]);
+      dwLen = (pbCDB [7] << 8) | pbCDB [8];
+      DBG ("WRITE10, LBA=%d, len=%d\n", dwLBA, dwLen);
+      *piRspLen = dwLen * BLOCKSIZE;
+      *pfDevIn = FALSE;
+      break;
+
+    case SCSI_CMD_VERIFY_10 :
+      DBG ("VERIFY10\n");
+      if ((pbCDB [1] & (1 << 1)) != 0) 
+      {
+        DBG ("BYTCHK not supported\n");
+        return NULL;
+      }
+      *piRspLen = 0;
+      break;
+
+    default :
+      DBG ("Unhandled SCSI: ");    
+      for (i = 0; i < iCDBLen; i++)
+        DBG (" %02X", pbCDB[i]);
+      DBG ("\n");
+
+      dwSense = INVALID_CMD_OPCODE;
+      *piRspLen = 0;
+      return NULL;
+  }
+
+  return abBlockBuf;
+}
+
+//
+//  SCSIHandleData
+//    Handles a block of SCSI data.
+//    
+//  IN      pbCDB    . Command data block
+//          iCDBLen  - Command data block len
+//  IN/OUT  pbData   - Data buffer
+//  IN      dwOffset - Offset in data
+//  
+//  Returns a pointer to the next data to be exchanged if successful,
+//  returns NULL otherwise.
+//
+U8 *mscscsiHandleData (U8 *pbCDB, U8 iCDBLen __attribute__ ((unused)), U8 *pbData, U32 dwOffset)
+{
+  TCDB6 *pCDB;
+  U32   dwLBA;
+  U32   dwBufPos, dwBlockNr;
+  U32   dwDevSize, dwMaxBlock;
+
+  pCDB = (TCDB6 *)pbCDB;
+
+  switch (pCDB->bOperationCode) 
+  {
+    case SCSI_CMD_TEST_UNIT_READY :
+      if (dwSense != 0) 
+        return NULL;
+      break;
+
+    case SCSI_CMD_REQUEST_SENSE :
+      memcpy (pbData, abSense, 18);
+      pbData [2]  = (dwSense >> 16) & 0xff;
+      pbData [12] = (dwSense >> 8) & 0xff;
+      pbData [13] = (dwSense >> 0) & 0xff;
+      dwSense = 0;
+      break;
+
+    case SCSI_CMD_FORMAT_UNIT :
+      break;
+
+    case SCSI_CMD_INQUIRY :
+      memcpy (pbData, abInquiry, sizeof(abInquiry));
+      break;
+
+    case SCSI_CMD_READ_CAPACITY_10:
+      mscblockGetSize (&dwDevSize);
+      dwMaxBlock = (dwDevSize - 1) / 512;
+      pbData [0] = (dwMaxBlock >> 24) & 0xff;
+      pbData [1] = (dwMaxBlock >> 16) & 0xff;
+      pbData [2] = (dwMaxBlock >> 8) & 0xff;
+      pbData [3] = (dwMaxBlock >> 0) & 0xff;
+      pbData [4] = (BLOCKSIZE >> 24) & 0xff;
+      pbData [5] = (BLOCKSIZE >> 16) & 0xff;
+      pbData [6] = (BLOCKSIZE >> 8) & 0xff;
+      pbData [7] = (BLOCKSIZE >> 0) & 0xff;
+      break;
+
+    case SCSI_CMD_READ_10 :
+      dwLBA = (pbCDB [2] << 24) | (pbCDB [3] << 16) | (pbCDB [4] << 8) | (pbCDB [5]);
+      dwBufPos = (dwOffset & (BLOCKSIZE - 1));
+      if (dwBufPos == 0) 
+      {
+        dwBlockNr = dwLBA + (dwOffset / BLOCKSIZE);
+        DBG ("R");
+        if (mscblockRead(dwBlockNr, abBlockBuf) < 0) 
+        {
+          dwSense = READ_ERROR;
+          DBG ("mscblockRead failed\n");
+          return NULL;
+        }
+      }
+
+      return abBlockBuf + dwBufPos ;
+
+    case SCSI_CMD_WRITE_10:
+      dwLBA = (pbCDB[2] << 24) | (pbCDB[3] << 16) | (pbCDB[4] << 8) | (pbCDB[5]);
+
+      dwBufPos = ((dwOffset + 64) & (BLOCKSIZE - 1));
+      if (dwBufPos == 0) 
+      {
+        dwBlockNr = dwLBA + (dwOffset / BLOCKSIZE);
+        DBG ("W");
+        if (mscblockWrite (dwBlockNr, abBlockBuf) < 0) 
+        {
+          dwSense = WRITE_ERROR;
+          DBG ("mscblockWrite failed\n");
+          return NULL;
+        }
+      }
+      return abBlockBuf + dwBufPos;
+
+    case SCSI_CMD_VERIFY_10 :
+      break;
+
+    default :
+      dwSense = INVALID_CMD_OPCODE;
+      return NULL;
+  }
+
+  return abBlockBuf;
+}
diff --git a/usbmass/mscscsi.h b/usbmass/mscscsi.h
new file mode 100644 (file)
index 0000000..02046e2
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+  LPCUSB, an USB device driver for LPC microcontrollers 
+  Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+  2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+  3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 
+  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _MSCSCSI_H_
+#define _MSCSCSI_H_
+
+#include "sysdefs.h"
+
+void mscscsiReset (void);
+U8 *mscscsiHandleCmd (U8 *pbCDB, U8 bCDBLen, unsigned int *piRspLen, BOOL *pfDevIn);
+U8 *mscscsiHandleData (U8 *pbCDB, U8 bCDBLen, U8 *pbData, U32 dwOffset);
+
+#endif
diff --git a/usbmass/mscspi.c b/usbmass/mscspi.c
new file mode 100644 (file)
index 0000000..16f2924
--- /dev/null
@@ -0,0 +1,82 @@
+/*****************************************************************************\
+*              efs - General purpose Embedded Filesystem library              *
+*          --------------------- -----------------------------------          *
+*                                                                             *
+* Filename : lpc2000_spi.c                                                     *
+* Description : This  contains the functions needed to use efs for        *
+*               accessing files on an SD-card connected to an LPC2xxx.        *
+*                                                                             *
+* This library is free software; you can redistribute it and/or               *
+* modify it under the terms of the GNU Lesser General Public                  *
+* License as published by the Free Software Foundation; either                *
+* version 2.1 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           *
+* Lesser General Public License for more details.                             *
+*                                                                             *
+*                                                    (c)2005 Martin Thomas    *
+*                                                                             *
+\*****************************************************************************/
+
+/*
+  2006, Bertrik Sikken, modified for LPCUSB
+*/
+
+//
+//
+//
+#include "FreeRTOS.h"
+
+#include "../fatfs/spi.h"
+
+#include "mscspi.h"
+
+//
+//
+//
+#define SELECT_CARD()   do { GPIO0_IOCLR = GPIO_IO_P20; } while (0)
+#define UNSELECT_CARD() do { GPIO0_IOSET = GPIO_IO_P20; } while (0)
+
+//
+//
+//
+void mscspiInit (void)
+{
+  spiInit ();
+}
+
+//
+//
+//
+U8 mscspiTransferByte (U8 outgoing)
+{
+  U8 r;
+
+  spiChipSelect (1);
+  r = spiTransferByte (outgoing);
+  spiChipSelect (0);
+
+  return r;
+}
+
+//
+//
+//
+void mscspiSendBlock (U8 *pbBuf, int iLen)
+{
+  spiChipSelect (1);
+  spiSendBlock (pbBuf, iLen);
+  spiChipSelect (0);
+}
+
+//
+//
+//
+void mscspiReceiveBlock (U8 *pbBuf, int iLen)
+{
+  spiChipSelect (1);
+  spiReceiveBlock (pbBuf, iLen);
+  spiChipSelect (0);
+}
diff --git a/usbmass/mscspi.h b/usbmass/mscspi.h
new file mode 100644 (file)
index 0000000..5706c63
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+       LPCUSB, an USB device driver for LPC microcontrollers   
+       Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
+
+       Redistribution and use in source and binary forms, with or without
+       modification, are permitted provided that the following conditions are met:
+
+       1. Redistributions of source code must retain the above copyright
+          notice, this list of conditions and the following disclaimer.
+       2. Redistributions in binary form must reproduce the above copyright
+          notice, this list of conditions and the following disclaimer in the
+          documentation and/or other materials provided with the distribution.
+       3. The name of the author may not be used to endorse or promote products
+          derived from this software without specific prior written permission.
+
+       THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+       IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+       OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+       IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 
+       INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+       NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+       DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+       THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+       (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+       THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _MSCSPI_H_
+#define _MSCSPI_H_
+
+//
+//
+//
+#include "sysdefs.h"
+
+//
+//
+//
+#define SPI_PRESCALE_MIN  8
+
+//
+//
+//
+void   mscspiInit (void);
+U8             mscspiTransferByte (U8 outgoing);
+void   mscspiSendBlock (U8 *pbBuf, int iLen);
+void   mscspiReceiveBlock (U8 *pbBuf, int iLen);
+
+#endif
diff --git a/usbmass/mscspi2.c b/usbmass/mscspi2.c
new file mode 100644 (file)
index 0000000..7b9e20c
--- /dev/null
@@ -0,0 +1,82 @@
+/*****************************************************************************\
+*              efs - General purpose Embedded Filesystem library              *
+*          --------------------- -----------------------------------          *
+*                                                                             *
+* Filename : lpc2000_spi.c                                                     *
+* Description : This  contains the functions needed to use efs for        *
+*               accessing files on an SD-card connected to an LPC2xxx.        *
+*                                                                             *
+* This library is free software; you can redistribute it and/or               *
+* modify it under the terms of the GNU Lesser General Public                  *
+* License as published by the Free Software Foundation; either                *
+* version 2.1 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           *
+* Lesser General Public License for more details.                             *
+*                                                                             *
+*                                                    (c)2005 Martin Thomas    *
+*                                                                             *
+\*****************************************************************************/
+
+/*
+  2006, Bertrik Sikken, modified for LPCUSB
+*/
+
+//
+//
+//
+#include "FreeRTOS.h"
+
+#include "../fatfs/spi.h"
+
+#include "mscspi.h"
+
+//
+//
+//
+#define SELECT_CARD()   do { GPIO0_IOCLR = GPIO_IO_P20; } while (0)
+#define UNSELECT_CARD() do { GPIO0_IOSET = GPIO_IO_P20; } while (0)
+
+//
+//
+//
+void mscspiInit (void)
+{
+  spiInit ();
+}
+
+//
+//
+//
+U8 mscspiTransferByte (U8 outgoing)
+{
+  U8 r;
+
+  SELECT_CARD ();
+  r = spiTransferByte (outgoing);
+  UNSELECT_CARD ();
+
+  return r;
+}
+
+//
+//
+//
+void mscspiSendBlock (U8 *pbBuf, int iLen)
+{
+  SELECT_CARD ();
+  spiSendBlock (pbBuf, iLen);
+  UNSELECT_CARD ();
+}
+
+//
+//
+//
+void mscspiReceiveBlock (U8 *pbBuf, int iLen)
+{
+  SELECT_CARD ();
+  spiReceiveBlock (pbBuf, iLen);
+  UNSELECT_CARD ();
+}
diff --git a/usbmass/usbmass.c b/usbmass/usbmass.c
new file mode 100644 (file)
index 0000000..bb52c74
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+       LPCUSB, an USB device driver for LPC microcontrollers   
+       Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
+
+       Redistribution and use in source and binary forms, with or without
+       modification, are permitted provided that the following conditions are met:
+
+       1. Redistributions of source code must retain the above copyright
+          notice, this list of conditions and the following disclaimer.
+       2. Redistributions in binary form must reproduce the above copyright
+          notice, this list of conditions and the following disclaimer in the
+          documentation and/or other materials provided with the distribution.
+       3. The name of the author may not be used to endorse or promote products
+          derived from this software without specific prior written permission.
+
+       THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+       IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+       OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+       IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 
+       INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+       NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+       DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+       THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+       (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+       THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "FreeRTOS.h"
+
+#include "../usb/usbapi.h"
+
+#include "mscdebug.h"
+#include "mscbot.h"
+#include "mscblock.h"
+#include "usbmass.h"
+
+//
+//
+//
+#define MAX_PACKET_SIZE        64
+#define LE_WORD(x) ((x)&0xff),((x)>>8)
+
+//
+//
+//
+static U8 abClassReqData [4];
+
+static const U8 abDescriptors [] = 
+{
+  //
+  //  Device descriptor        
+  //
+  0x12,
+  DESC_DEVICE,                 
+  LE_WORD(0x0200),             // bcdUSB
+  0x00,                                              // bDeviceClass
+  0x00,                                              // bDeviceSubClass
+  0x00,                                              // bDeviceProtocol
+  MAX_PACKET_SIZE0,            // bMaxPacketSize
+  LE_WORD(0xFFFF),             // idVendor
+  LE_WORD(0x0003),             // idProduct
+  LE_WORD(0x0100),             // bcdDevice
+  0x01,                                              // iManufacturer
+  0x02,                                              // iProduct
+  0x03,                                              // iSerialNumber
+  0x01,                                              // bNumConfigurations
+
+  //
+  //  Configuration descriptor
+  //
+  0x09,
+  DESC_CONFIGURATION,
+  LE_WORD(32),                 // wTotalLength
+  0x01,                                        // bNumInterfaces
+  0x01,                                        // bConfigurationValue
+  0x00,                                        // iConfiguration
+  0xC0,                                        // bmAttributes
+  0x32,                                        // bMaxPower
+
+  //
+  //  Interface
+  //
+  0x09,
+  DESC_INTERFACE,
+  0x00,                                        // bInterfaceNumber
+  0x00,                                        // bAlternateSetting
+  0x02,                                        // bNumEndPoints
+  0x08,                                        // bInterfaceClass = mass storage
+  0x06,                                        // bInterfaceSubClass = transparent SCSI
+  0x50,                                        // bInterfaceProtocol = BOT
+  0x00,                                        // iInterface
+
+  //
+  //  EP
+  //
+  0x07,
+  DESC_ENDPOINT,
+  MSC_BULK_IN_EP,                            // bEndpointAddress
+  0x02,                                                    // bmAttributes = bulk
+  LE_WORD(MAX_PACKET_SIZE), // wMaxPacketSize
+  0x00,                                                    // bInterval
+
+  //
+  //  EP
+  //
+  0x07,
+  DESC_ENDPOINT,
+  MSC_BULK_OUT_EP,                   // bEndpointAddress
+  0x02,                                                    // bmAttributes = bulk
+  LE_WORD(MAX_PACKET_SIZE), // wMaxPacketSize
+  0x00,                                                    // bInterval
+
+  //
+  //  String descriptors
+  //
+  0x04,
+  DESC_STRING,
+  LE_WORD(0x0409),
+
+  0x0E,
+  DESC_STRING,
+  'L', 0, 'P', 0, 'C', 0, 'U', 0, 'S', 0, 'B', 0,
+
+  0x12,
+  DESC_STRING,
+  'P', 0, 'r', 0, 'o', 0, 'd', 0, 'u', 0, 'c', 0, 't', 0, 'X', 0,
+
+  0x1A,
+  DESC_STRING,
+  'D', 0, 'E', 0, 'A', 0, 'D', 0, 'C', 0, '0', 0, 'D', 0, 'E', 0, 'C', 0, 'A', 0, 'F', 0, 'E', 0,
+
+  // terminating zero
+  0
+};
+
+
+//
+//
+//
+static BOOL HandleClassRequest (TSetupPacket *pSetup, int *piLen, U8 **ppbData)
+{
+  if (pSetup->wIndex != 0)
+  {
+    DBG ("Invalid idx %X\n", pSetup->wIndex);
+    return FALSE;
+  }
+
+  if (pSetup->wValue != 0)
+  {
+    DBG ("Invalid val %X\n", pSetup->wValue);
+    return FALSE;
+  }
+
+  switch (pSetup->bRequest) 
+  {
+    //
+    //  Get max LUN (always return no LUNs)
+    //
+    case 0xfe:
+      {
+        *ppbData [0] = 0;
+        *piLen = 1;
+      }
+      break;
+
+    //
+    //  MSC reset
+    //
+    case 0xff:
+      {
+        if (pSetup->wLength > 0)
+          return FALSE;
+
+        mscbotReset ();
+      }
+      break;
+
+    default:
+      {
+        DBG ("Unhandled class\n");
+      }
+      return FALSE;
+  }
+
+  return TRUE;
+}
+
+//
+//
+//
+void usbmassInit (void)
+{
+  portENTER_CRITICAL ();
+       mscblockInit ();
+  usbRegisterHandlers ();
+       usbRegisterDescriptors (abDescriptors);
+       usbRegisterRequestHandler (REQTYPE_TYPE_CLASS, HandleClassRequest, abClassReqData);
+       usbHardwareRegisterEPIntHandler (MSC_BULK_IN_EP, mscbotBulkIn);
+       usbHardwareRegisterEPIntHandler (MSC_BULK_OUT_EP, mscbotBulkOut);
+       usbHardwareNakIntEnable (INACK_BI);
+  usbSetupInterruptHandler ();
+  portEXIT_CRITICAL ();
+
+       usbHardwareConnect (TRUE);
+}
diff --git a/usbmass/usbmass.h b/usbmass/usbmass.h
new file mode 100644 (file)
index 0000000..2668a58
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef _USBMASS_H_
+#define _USBMASS_H_
+
+void usbmassInit (void);
+
+#endif
diff --git a/usbser/Makefile b/usbser/Makefile
new file mode 100644 (file)
index 0000000..28f9d4d
--- /dev/null
@@ -0,0 +1,25 @@
+SRC_FILES=usbser.c
+
+#
+# Define all object files.
+#
+ARM_OBJ = $(SRC_FILES:.c=.o)
+
+.PHONY: all
+all: $(ARM_OBJ)
+
+$(ARM_OBJ) : %.o : %.c Makefile .depend
+       $(CC) -c $(CFLAGS) $< -o $@
+       $(AR) r $(COMMON)/common.a $@
+
+#
+#  The .depend files contains the list of header files that the
+#  various source files depend on.  By doing this, we'll only
+#  rebuild the .o's that are affected by header files changing.
+#
+.depend:
+                       $(CC) $(CFLAGS) -M $(SRC_FILES) > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff --git a/usbser/usbser.c b/usbser/usbser.c
new file mode 100644 (file)
index 0000000..8c351d4
--- /dev/null
@@ -0,0 +1,338 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "FreeRTOS.h"
+#include "task.h"
+#include "queue.h"
+
+#include "../usb/usbapi.h"
+#include "usbser.h"
+
+//
+//
+//
+#define EOF (-1)
+
+#define INT_IN_EP     0x81
+#define BULK_OUT_EP   0x05
+#define BULK_IN_EP    0x82
+
+#define MAX_PACKET_SIZE 64
+
+#define LE_WORD(x)    ((x)&0xFF),((x)>>8)
+
+// CDC definitions
+#define CS_INTERFACE      0x24
+#define CS_ENDPOINT       0x25
+
+#define SET_LINE_CODING         0x20
+#define GET_LINE_CODING         0x21
+#define SET_CONTROL_LINE_STATE  0x22
+
+//
+//  Data structure for GET_LINE_CODING / SET_LINE_CODING class requests
+//
+typedef struct 
+{
+  U32   dwDTERate;
+  U8    bCharFormat;
+  U8    bParityType;
+  U8    bDataBits;
+} 
+TLineCoding;
+
+static TLineCoding LineCoding = {115200, 0, 0, 8};
+static U8 abBulkBuf [64];
+static U8 abClassReqData [8];
+static xQueueHandle xRXQueue = NULL;
+static xQueueHandle xTXQueue = NULL;
+static int usbSerialInitialized = FALSE;
+
+//
+//
+//
+static const U8 abDescriptors [] = 
+{
+  //
+  //  Device descriptor
+  //
+  0x12,
+  DESC_DEVICE,
+  LE_WORD(0x0200),      // bcdUSB
+  0x02,                 // bDeviceClass
+  0x00,                 // bDeviceSubClass
+  0x00,                 // bDeviceProtocol
+  MAX_PACKET_SIZE0,     // bMaxPacketSize
+  LE_WORD(0xFFFF),      // idVendor
+  LE_WORD(0x0005),      // idProduct
+  LE_WORD(0x0100),      // bcdDevice
+  0x01,                 // iManufacturer
+  0x02,                 // iProduct
+  0x03,                 // iSerialNumber
+  0x01,                 // bNumConfigurations
+
+  //
+  //  Configuration descriptor
+  //
+  0x09,
+  DESC_CONFIGURATION,
+  LE_WORD(67),          // wTotalLength
+  0x02,                 // bNumInterfaces
+  0x01,                 // bConfigurationValue
+  0x00,                 // iConfiguration
+  0xC0,                 // bmAttributes
+  0x32,                 // bMaxPower
+
+  //
+  //  Control class interface
+  //
+  0x09,
+  DESC_INTERFACE,
+  0x00,                 // bInterfaceNumber
+  0x00,                 // bAlternateSetting
+  0x01,                 // bNumEndPoints
+  0x02,                 // bInterfaceClass
+  0x02,                 // bInterfaceSubClass
+  0x01,                 // bInterfaceProtocol, linux requires value of 1 for the cdc_acm module
+  0x00,                 // iInterface
+
+  //
+  //  Header functional descriptor
+  //
+  0x05,
+  CS_INTERFACE,
+  0x00,
+  LE_WORD(0x0110),
+
+  //
+  //  Call management functional descriptor
+  //
+  0x05,
+  CS_INTERFACE,
+  0x01,
+  0x01,                 // bmCapabilities = device handles call management
+  0x01,                 // bDataInterface
+
+  //
+  //  ACM functional descriptor
+  //
+  0x04,
+  CS_INTERFACE,
+  0x02,
+  0x02,                 // bmCapabilities
+
+  //
+  //  Union functional descriptor
+  //
+  0x05,
+  CS_INTERFACE,
+  0x06,
+  0x00,                 // bMasterInterface
+  0x01,                 // bSlaveInterface0
+
+  //
+  //  Notification EP
+  //
+  0x07,
+  DESC_ENDPOINT,
+  INT_IN_EP,            // bEndpointAddress
+  0x03,                 // bmAttributes = intr
+  LE_WORD(8),           // wMaxPacketSize
+  0x0A,                 // bInterval
+
+  //
+  //  Data class interface descriptor
+  //
+  0x09,
+  DESC_INTERFACE,
+  0x01,                 // bInterfaceNumber
+  0x00,                 // bAlternateSetting
+  0x02,                 // bNumEndPoints
+  0x0A,                 // bInterfaceClass = data
+  0x00,                 // bInterfaceSubClass
+  0x00,                 // bInterfaceProtocol
+  0x00,                 // iInterface
+
+  //
+  //  Data EP OUT
+  //
+  0x07,
+  DESC_ENDPOINT,
+  BULK_OUT_EP,              // bEndpointAddress
+  0x02,                     // bmAttributes = bulk
+  LE_WORD(MAX_PACKET_SIZE), // wMaxPacketSize
+  0x00,                     // bInterval
+
+  //
+  //  Data EP in
+  //
+  0x07,
+  DESC_ENDPOINT,
+  BULK_IN_EP,               // bEndpointAddress
+  0x02,                     // bmAttributes = bulk
+  LE_WORD(MAX_PACKET_SIZE), // wMaxPacketSize
+  0x00,                     // bInterval
+
+  //
+  //  String descriptors
+  //
+  0x04,
+  DESC_STRING,
+  LE_WORD(0x0409),
+
+  0x0E,
+  DESC_STRING,
+  'L', 0, 'P', 0, 'C', 0, 'U', 0, 'S', 0, 'B', 0,
+
+  0x14,
+  DESC_STRING,
+  'U', 0, 'S', 0, 'B', 0, 'S', 0, 'e', 0, 'r', 0, 'i', 0, 'a', 0, 'l', 0,
+
+  0x12,
+  DESC_STRING,
+  'D', 0, 'E', 0, 'A', 0, 'D', 0, 'C', 0, '0', 0, 'D', 0, 'E', 0,
+
+  //
+  //  Terminating zero
+  //
+  0
+};
+
+//
+//  Local function to handle incoming bulk data.  This needs to copy the incoming data to the VCOM RX queue.
+//
+static int usbserBulkOut (U8 bEP, U8 bEPStatus __attribute__ ((unused)))
+{
+  int i;
+  int iLen;
+  portBASE_TYPE xTaskWokenByPost = pdFALSE;
+
+  iLen = usbHardwareEndpointRead (bEP, abBulkBuf, sizeof (abBulkBuf));
+
+  for (i = 0; i < iLen; i++) 
+    xTaskWokenByPost = xQueueSendFromISR (xRXQueue, &abBulkBuf [i], xTaskWokenByPost);
+
+  return xTaskWokenByPost;
+}
+
+//
+//  Local function to handle outgoing bulk data.  This needs to copy any user data in the VCOM TX queue to the bulk endpoint.
+//
+static int usbserBulkIn (U8 bEP, U8 bEPStatus __attribute__ ((unused)))
+{
+  int i;
+  portBASE_TYPE xTaskWoken = pdFALSE;
+  
+  for (i = 0; i < MAX_PACKET_SIZE; i++)
+    if (!xQueueReceiveFromISR (xTXQueue, &abBulkBuf [i], &xTaskWoken))
+      break;
+
+  if (i > 0)
+    usbHardwareEndpointWrite (bEP, abBulkBuf, i);
+
+  return xTaskWoken;
+}
+
+//
+//  Local function to handle the USB-CDC class requests
+//
+static BOOL usbserHandleClassRequest (TSetupPacket *pSetup, int *piLen, U8 **ppbData)
+{
+  switch (pSetup->bRequest) 
+  {
+    case SET_LINE_CODING:
+      {
+        memcpy ((U8 *) &LineCoding, *ppbData, 7);
+        *piLen = 7;
+      }
+      break;
+
+    case GET_LINE_CODING:
+      {
+        *ppbData = (U8 *) &LineCoding;
+        *piLen = 7;
+      }
+      break;
+
+    case SET_CONTROL_LINE_STATE:
+      break;
+
+    default:
+      return FALSE;
+  }
+
+  return TRUE;
+}
+
+//
+//  Writes one character to VCOM port
+//
+signed portBASE_TYPE usbserPutChar (signed portCHAR cOutChar, portTickType xBlockTime)
+{
+  if (!usbSerialInitialized)
+    return pdFALSE;
+
+  return xQueueSend (xTXQueue, &cOutChar, xBlockTime);
+}
+
+signed portBASE_TYPE usbserPutString (const signed portCHAR * const pcString, portTickType xBlockTime)
+{
+  signed portCHAR *pxNext;
+
+  if (!usbSerialInitialized)
+    return pdFALSE;
+
+  pxNext = (signed portCHAR *) pcString;
+
+  while (*pxNext)
+  {
+    if (!usbserPutChar (*pxNext, xBlockTime))
+      return pdFALSE;
+
+    pxNext++;
+  }
+
+  return pdTRUE;
+}
+
+//
+//  Reads one character from VCOM port
+//
+signed portBASE_TYPE usbserGetChar (signed portCHAR *pcRxedChar, portTickType xBlockTime)
+{
+  if (!usbSerialInitialized)
+    return pdFALSE;
+
+  if (xQueueReceive (xRXQueue, pcRxedChar, xBlockTime))
+    return pdTRUE;
+  else
+    return pdFALSE;
+}
+
+void usbserGetRxQueue (xQueueHandle *qh)
+{
+  *qh = xRXQueue;
+}
+
+//
+//
+//
+void usbserInit (void)
+{
+  portENTER_CRITICAL ();
+  usbRegisterHandlers ();
+  usbRegisterDescriptors (abDescriptors);
+  usbRegisterRequestHandler (REQTYPE_TYPE_CLASS, usbserHandleClassRequest, abClassReqData);
+  usbHardwareRegisterEPIntHandler (INT_IN_EP, NULL);
+  usbHardwareRegisterEPIntHandler (BULK_IN_EP, usbserBulkIn);
+  usbHardwareRegisterEPIntHandler (BULK_OUT_EP, usbserBulkOut);
+  usbHardwareNakIntEnable (INACK_BI);
+  usbSetupInterruptHandler ();
+  xRXQueue = xQueueCreate (256, (unsigned portBASE_TYPE) sizeof (signed portCHAR));
+  xTXQueue = xQueueCreate (256, (unsigned portBASE_TYPE) sizeof (signed portCHAR));
+  usbSerialInitialized = TRUE;
+  portEXIT_CRITICAL ();
+
+  usbHardwareConnect (TRUE);
+}
diff --git a/usbser/usbser.h b/usbser/usbser.h
new file mode 100644 (file)
index 0000000..067402f
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef _USBSER_H_
+#define _USBSER_H_
+
+#include "FreeRTOS.h"
+#include "queue.h"
+
+//
+//
+//
+signed portBASE_TYPE usbserPutChar (signed portCHAR cOutChar, portTickType xBlockTime);
+signed portBASE_TYPE usbserPutString (const signed portCHAR * const pcString, portTickType xBlockTime);
+signed portBASE_TYPE usbserGetChar (signed portCHAR *pcRxedChar, portTickType xBlockTime);
+void usbserInit (void);
+void usbserGetRxQueue (xQueueHandle *qh);
+
+#endif