]> git.sur5r.net Git - freertos/commitdiff
Start of new Win32 emulator project. Currently working but not well tested, and...
authorrichardbarry <richardbarry@1d2547de-c912-0410-9cb9-b8ca96c0e9e2>
Sun, 14 Nov 2010 21:01:50 +0000 (21:01 +0000)
committerrichardbarry <richardbarry@1d2547de-c912-0410-9cb9-b8ca96c0e9e2>
Sun, 14 Nov 2010 21:01:50 +0000 (21:01 +0000)
git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@1140 1d2547de-c912-0410-9cb9-b8ca96c0e9e2

Source/portable/MSVC-MingW/port.c [new file with mode: 0644]
Source/portable/MSVC-MingW/portmacro.h [new file with mode: 0644]

diff --git a/Source/portable/MSVC-MingW/port.c b/Source/portable/MSVC-MingW/port.c
new file mode 100644 (file)
index 0000000..dbd4959
--- /dev/null
@@ -0,0 +1,576 @@
+/*\r
+    FreeRTOS V6.1.0 - Copyright (C) 2010 Real Time Engineers Ltd.\r
+\r
+    ***************************************************************************\r
+    *                                                                         *\r
+    * If you are:                                                             *\r
+    *                                                                         *\r
+    *    + New to FreeRTOS,                                                   *\r
+    *    + Wanting to learn FreeRTOS or multitasking in general quickly       *\r
+    *    + Looking for basic training,                                        *\r
+    *    + Wanting to improve your FreeRTOS skills and productivity           *\r
+    *                                                                         *\r
+    * then take a look at the FreeRTOS books - available as PDF or paperback  *\r
+    *                                                                         *\r
+    *        "Using the FreeRTOS Real Time Kernel - a Practical Guide"        *\r
+    *                  http://www.FreeRTOS.org/Documentation                  *\r
+    *                                                                         *\r
+    * A pdf reference manual is also available.  Both are usually delivered   *\r
+    * to your inbox within 20 minutes to two hours when purchased between 8am *\r
+    * and 8pm GMT (although please allow up to 24 hours in case of            *\r
+    * exceptional circumstances).  Thank you for your support!                *\r
+    *                                                                         *\r
+    ***************************************************************************\r
+\r
+    This file is part of the FreeRTOS distribution.\r
+\r
+    FreeRTOS is free software; you can redistribute it and/or modify it under\r
+    the terms of the GNU General Public License (version 2) as published by the\r
+    Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
+    ***NOTE*** The exception to the GPL is included to allow you to distribute\r
+    a combined work that includes FreeRTOS without being obliged to provide the\r
+    source code for proprietary components outside of the FreeRTOS kernel.\r
+    FreeRTOS is distributed in the hope that it will be useful, but WITHOUT\r
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\r
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\r
+    more details. You should have received a copy of the GNU General Public\r
+    License and the FreeRTOS license exception along with FreeRTOS; if not it\r
+    can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
+    by writing to Richard Barry, contact details for whom are available on the\r
+    FreeRTOS WEB site.\r
+\r
+    1 tab == 4 spaces!\r
+\r
+    http://www.FreeRTOS.org - Documentation, latest information, license and\r
+    contact details.\r
+\r
+    http://www.SafeRTOS.com - A version that is certified for use in safety\r
+    critical systems.\r
+\r
+    http://www.OpenRTOS.com - Commercial support, development, porting,\r
+    licensing and training services.\r
+*/\r
+\r
+/* Scheduler includes. */\r
+#include "FreeRTOS.h"\r
+#include "task.h"\r
+#include <stdio.h>\r
+\r
+\r
+\r
+\r
+\r
+typedef struct xTaskControlBlock\r
+{\r
+       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. */\r
+\r
+       #if ( portUSING_MPU_WRAPPERS == 1 )\r
+               xMPU_SETTINGS xMPUSettings;                             /*< The MPU settings are defined as part of the port layer.  THIS MUST BE THE SECOND MEMBER OF THE STRUCT. */\r
+       #endif  \r
+       \r
+       xListItem                               xGenericListItem;       /*< List item used to place the TCB in ready and blocked queues. */\r
+       xListItem                               xEventListItem;         /*< List item used to place the TCB in event lists. */\r
+       unsigned portBASE_TYPE  uxPriority;                     /*< The priority of the task where 0 is the lowest priority. */\r
+       portSTACK_TYPE                  *pxStack;                       /*< Points to the start of the stack. */\r
+       signed char                             pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created.  Facilitates debugging only. */\r
+\r
+       #if ( portSTACK_GROWTH > 0 )\r
+               portSTACK_TYPE *pxEndOfStack;                   /*< Used for stack overflow checking on architectures where the stack grows up from low memory. */\r
+       #endif\r
+\r
+       #if ( portCRITICAL_NESTING_IN_TCB == 1 )\r
+               unsigned portBASE_TYPE uxCriticalNesting;\r
+       #endif\r
+\r
+       #if ( configUSE_TRACE_FACILITY == 1 )\r
+               unsigned portBASE_TYPE  uxTCBNumber;    /*< This is used for tracing the scheduler and making debugging easier only. */\r
+       #endif\r
+\r
+       #if ( configUSE_MUTEXES == 1 )\r
+               unsigned portBASE_TYPE uxBasePriority;  /*< The priority last assigned to the task - used by the priority inheritance mechanism. */\r
+       #endif\r
+\r
+       #if ( configUSE_APPLICATION_TASK_TAG == 1 )\r
+               pdTASK_HOOK_CODE pxTaskTag;\r
+       #endif\r
+\r
+       #if ( configGENERATE_RUN_TIME_STATS == 1 )\r
+               unsigned long ulRunTimeCounter;         /*< Used for calculating how much CPU time each task is utilising. */\r
+       #endif\r
+\r
+} xTCB;\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+FILE *pfTraceFile = NULL;\r
+//#define vPortTrace( x ) if( pfTraceFile == NULL ) pfTraceFile = fopen( "c:/temp/trace.txt", "w" ); if( pfTraceFile != NULL ) fprintf( pfTraceFile, x )\r
+#define vPortTrace( x ) ( void ) x\r
+\r
+#define portMAX_INTERRUPTS                             ( ( unsigned long ) sizeof( unsigned long ) * 8UL ) /* The number of bits in an unsigned long. */\r
+#define portNO_CRITICAL_NESTING                ( ( unsigned long ) 0 )\r
+\r
+/*\r
+ * Created as a high priority thread, this function uses a timer to simulate\r
+ * a tick interrupt being generated on an embedded target.  In this Windows\r
+ * environment the timer does not achieve real time performance though.\r
+ */\r
+static DWORD WINAPI prvSimulatedPeripheralTimer( LPVOID lpParameter );\r
+\r
+/* \r
+ * Process all the simulated interrupts - each represented by a bit in \r
+ * ulPendingInterrupts variable.\r
+ */\r
+static void prvProcessEvents( void );\r
+\r
+/*-----------------------------------------------------------*/\r
+\r
+/* The WIN32 simulator runs each task in a thread.  The context switching is\r
+managed by the threads, so the task stack does not have to be managed directly,\r
+although the task stack is still used to hold an xThreadState structure this is\r
+the only thing it will ever hold.  The structure indirectly maps the task handle \r
+to a thread handle. */\r
+typedef struct\r
+{\r
+       portSTACK_TYPE ulCriticalNesting;       /* Critical nesting count of the task. */\r
+       void * pvThread;                                        /* Handle of the thread that executes the task. */\r
+} xThreadState;\r
+\r
+/* The parameters passed to a thread when it is created. */\r
+typedef struct XPARAMS\r
+{\r
+       pdTASK_CODE pxCode;             /* The entry point of the task (rather than thread) code. */\r
+       void *pvParameters;             /* The parameters that are passed to the task (rather than thread. */\r
+} xParams;\r
+\r
+/* Pseudo interrupts waiting to be processed.  This is a bit mask where each\r
+bit represents one interrupt, so a maximum of 32 interrupts can be simulated. */\r
+static volatile unsigned long ulPendingInterrupts = 0UL;\r
+\r
+/* An event used to inform the interrupt dispatch thread (a high priority thread\r
+that simulated interrupt processing) that an IRQ or SWI type interrupt is\r
+pending. */\r
+static void *pvInterruptEvent = NULL;\r
+\r
+/* Mutex used to protect all the pseudo interrupt variables that are accessed by\r
+multiple threads. */\r
+static void *pvInterruptEventMutex = NULL;\r
+\r
+/* The main thread, which also acts as the pseudo interrupt handler. */\r
+static void *pvMainThreadAndInterrupHandler;\r
+\r
+/* Events used to manage sequencing. */\r
+static void *pvTickAcknowledgeEvent = NULL, *pvInterruptAcknowledgeEvent = NULL;\r
+\r
+/* The critical nesting count for the currently executing task.  This is \r
+initialised to a non-zero value so interrupts do not become enabled during \r
+the initialisation phase.  As each task has its own critical nesting value \r
+ulCriticalNesting will get set to zero when the first task runs.  This \r
+initialisation is probably not critical in this simulated environment as the\r
+pseudo interrupt handlers/dispatchers do not get created until the FreeRTOS\r
+scheduler is started. */\r
+static unsigned portLONG ulCriticalNesting = 9999UL;\r
+\r
+/* Handlers for all the simulated software interrupts.  The first two positions\r
+are used for the Yield and Tick interrupts so are handled slightly differently,\r
+all the other interrupts can be user defined. */\r
+static void (*vIsrHandler[ portMAX_INTERRUPTS ])( void ) = { 0 };\r
+\r
+/* Pointer to the TCB of the currently executing task. */\r
+extern void *pxCurrentTCB;\r
+\r
+/*-----------------------------------------------------------*/\r
+\r
+static DWORD WINAPI prvSimulatedPeripheralTimer( LPVOID lpParameter )\r
+{\r
+void *pvTimer;\r
+LARGE_INTEGER liDueTime;\r
+void *pvObjectList[ 2 ];\r
+const long long ll_ms_In_100ns_units = ( long long ) -1000;\r
+extern volatile unsigned long ulTicks;\r
+\r
+       /* Just to prevent compiler warnings. */\r
+       ( void ) lpParameter;\r
+\r
+       /* The timer is created as a one shot timer even though we want it to repeat\r
+       at a given frequency.  This is because Windows is not a real time environment,\r
+       and attempting to set a high frequency periodic timer will result in event\r
+       overruns.  Therefore the timer is just reset after each time the pseudo \r
+       interrupt handler has processed each tick event. */\r
+       pvTimer = CreateWaitableTimer( NULL, TRUE, NULL );\r
+       \r
+       liDueTime.QuadPart = ( long long ) portTICK_RATE_MS * ll_ms_In_100ns_units;\r
+\r
+       /* Block on the timer itself and the event mutex that grants access to the \r
+       interrupt variables. */\r
+       pvObjectList[ 0 ] = pvInterruptEventMutex;\r
+       pvObjectList[ 1 ] = pvTimer;\r
+\r
+       for(;;)\r
+       {\r
+               ulTicks++;\r
+\r
+               /* The timer is reset on each itteration of this loop rather than being set\r
+               to function periodicallys - this is for the reasons stated in the comments\r
+               where the timer is created. */\r
+               vPortTrace( "prvSimulatedPeripheralTimer: Tick acked, setting new tick timer\r\n" );\r
+               SetWaitableTimer( pvTimer, &liDueTime, 0, NULL, NULL, TRUE );\r
+\r
+               /* Wait until the timer expires and we can access the pseudo interrupt \r
+               variables. */\r
+               //WaitForMultipleObjects( ( sizeof( pvObjectList ) / sizeof( void * ) ), pvObjectList, TRUE, INFINITE );\r
+               WaitForSingleObject( pvTimer, INFINITE );\r
+               vPortTrace( "prvSimulatedPeripheralTimer: Timer signalled, waiting interrupt event mutex\r\n" );\r
+               WaitForSingleObject( pvInterruptEventMutex, INFINITE );\r
+               vPortTrace( "prvSimulatedPeripheralTimer: Got interrupt event mutex\r\n" );\r
+               \r
+               /* The timer has expired, generate the simulated tick event. */\r
+               ulPendingInterrupts |= ( 1 << portINTERRUPT_TICK );\r
+               if( pvInterruptEvent != NULL )\r
+               {\r
+                       vPortTrace( "prvSimulatedPeripheralTimer: Setting interrupt event to signal tick\r\n" );\r
+                       SetEvent( pvInterruptEvent );\r
+               }\r
+\r
+               /* Give back the mutex so the pseudo interrupt handler unblocks and can\r
+               access the interrupt handler variables.  This high priority task will then\r
+               loop back round to wait for the lower priority psuedo interrupt handler \r
+               thread to acknowledge the tick. */\r
+               if( pvInterruptEventMutex != NULL )\r
+               {\r
+                       vPortTrace( "prvSimulatedPeripheralTimer: Releasing interrupt event mutex so tick can be processed\r\n" );\r
+                       ReleaseMutex( pvInterruptEventMutex );\r
+               }\r
+\r
+               /* Wait for the previous tick to be acknowledged before resetting the timer.\r
+               As mentioned above this is done to prevent timer overruns in the non real-\r
+               time environment.  THIS IS NOT HOW A REAL PORT SHOULD USE TIMERS! */\r
+               WaitForSingleObject( pvTickAcknowledgeEvent, INFINITE );\r
+       }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters )\r
+{\r
+xThreadState *pxThreadState = NULL;\r
+xParams *pxThreadParams = ( void * ) pvPortMalloc( sizeof( xParams ) );\r
+\r
+       if( pxThreadParams != NULL )\r
+       {\r
+               /* In this simulated case a stack is not initialised, but instead a thread\r
+               is created that will execute the task being created.  The thread handles\r
+               the context switching itself.  The xThreadState object is placed onto\r
+               the stack that was created for the task - so the stack buffer is still\r
+               used, just not in the conventional way.  It will not be used for anything\r
+               other than holding this structure. */\r
+               pxThreadState = ( xThreadState * ) ( pxTopOfStack - sizeof( xThreadState ) );\r
+\r
+               /* The parameters that are passed into the thread so it knows how to\r
+               start the task executing. */\r
+               pxThreadParams->pxCode = pxCode;\r
+               pxThreadParams->pvParameters = pvParameters;\r
+\r
+               /* Create the thread itself. */\r
+               //pxThreadState->pvThread = ( void * ) CreateThread( NULL, 0, ( LPTHREAD_START_ROUTINE ) prvThreadEntryPoint, pxThreadParams, CREATE_SUSPENDED, NULL );\r
+               pxThreadState->pvThread = ( void * ) CreateThread( NULL, 0, ( LPTHREAD_START_ROUTINE ) pxCode, pvParameters, CREATE_SUSPENDED, NULL );\r
+               pxThreadState->ulCriticalNesting = portNO_CRITICAL_NESTING;\r
+               SetThreadPriority( pxThreadState->pvThread, THREAD_PRIORITY_IDLE );\r
+       }\r
+       \r
+       return ( portSTACK_TYPE * ) pxThreadState;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+portBASE_TYPE xPortStartScheduler( void )\r
+{\r
+void *pvHandle;\r
+long lSuccess = pdPASS;\r
+xThreadState *pxThreadState;\r
+\r
+       /* Set the priority of this thread such that it is above the priority of the\r
+       threads that run tasks, but below the priority of the thread that generates\r
+       the pseudo tick interrupts.  This priority is chosen because this is the\r
+       thread that actually handles the psuedo interrupts. */\r
+       pvHandle = GetCurrentThread();\r
+       if( pvHandle == NULL )\r
+       {\r
+               lSuccess = pdFAIL;\r
+       }\r
+       \r
+       if( lSuccess == pdPASS )\r
+       {\r
+               if( SetThreadPriority( pvHandle, THREAD_PRIORITY_BELOW_NORMAL ) == 0 )\r
+               {\r
+                       lSuccess = pdFAIL;\r
+               }\r
+       }\r
+\r
+       if( lSuccess == pdPASS )\r
+       {\r
+               /* Create the events and mutexes that are used to synchronise all the\r
+               threads. */\r
+               pvInterruptEventMutex = CreateMutex( NULL, FALSE, NULL );\r
+               pvInterruptEvent = CreateEvent( NULL, FALSE, FALSE, NULL );\r
+               pvTickAcknowledgeEvent = CreateEvent( NULL, FALSE, FALSE, NULL );\r
+               pvInterruptAcknowledgeEvent = CreateEvent( NULL, FALSE, FALSE, NULL );\r
+\r
+               /* Start the thread that simulates the timer peripheral to generate\r
+               tick interrupts. */\r
+               pvHandle = CreateThread( NULL, 0, prvSimulatedPeripheralTimer, NULL, 0, NULL );\r
+               if( pvHandle != NULL )\r
+               {\r
+                       SetThreadPriority( pvHandle, THREAD_PRIORITY_ABOVE_NORMAL );\r
+               }\r
+               \r
+               /* Start the highest priority task by obtaining its associated thread state\r
+               structure, in which is stored the thread handle. */\r
+               pxThreadState = ( xThreadState * ) *( ( unsigned long * ) pxCurrentTCB );\r
+               ulCriticalNesting = portNO_CRITICAL_NESTING;\r
+\r
+               vPortTrace( "Created system threads, starting task" );\r
+\r
+               ResumeThread( pxThreadState->pvThread );\r
+       }       \r
+       \r
+       /* Handle all pseudo interrupts - including yield requests and simulated ticks. */\r
+       prvProcessEvents();\r
+\r
+       /* Would not expect to return from prvProcessEvents(), so should not get here. */\r
+       return 0;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvProcessEvents( void )\r
+{\r
+long lSwitchRequired, lAcknowledgeTick, lAcknowledgeInterrupt;\r
+xThreadState *pxThreadState;\r
+void *pvObjectList[ 2 ];\r
+unsigned long i;\r
+char cTraceBuffer[ 256 ];\r
+\r
+       vPortTrace( "Entering prvProcessEvents\r\n" );\r
+\r
+       /* Going to block on the mutex that ensured exclusive access to the pdeudo \r
+       interrupt objects, and the event that signals that an interrupt is waiting\r
+       to be processed. */\r
+       pvObjectList[ 0 ] = pvInterruptEventMutex;\r
+       pvObjectList[ 1 ] = pvInterruptEvent;\r
+\r
+       for(;;)\r
+       {\r
+               vPortTrace( "prvProcessEvents: Waiting for next interrupt event\r\n" );\r
+               WaitForMultipleObjects( sizeof( pvObjectList ) / sizeof( void * ), pvObjectList, TRUE, INFINITE );\r
+               vPortTrace( "prvProcessEvents: Got interrupt event and mutex\r\n" );\r
+               //vPortTrace( "prvProcessEvents: Waiting for next interrupt event\r\n" );\r
+               //WaitForSingleObject( pvInterruptEvent, INFINITE );\r
+               //vPortTrace( "prvProcessEvents: Waiting interrupt event mutex to access interrupt data\r\n" );\r
+               //WaitForSingleObject( pvInterruptEventMutex, INFINITE );\r
+\r
+               lSwitchRequired = pdFALSE;\r
+               lAcknowledgeTick = pdFALSE;\r
+               lAcknowledgeInterrupt = pdFALSE;\r
+\r
+               /* For each interrupt we are interested in processing, each of which is \r
+               represented by a bit in the 32bit ulPendingInterrupts variable. */\r
+               for( i = 0; i < portMAX_INTERRUPTS; i++ )\r
+               {\r
+                       /* Is the pseudo interrupt pending? */\r
+                       if( ulPendingInterrupts & ( 1UL << i ) )\r
+                       {\r
+                               switch( i )\r
+                               {\r
+                                       case portINTERRUPT_YIELD:\r
+\r
+                                               vPortTrace( "prvProcessEvents: Processing Yield\r\n" );\r
+                                               /* Yield interrupts occur no matter what the critical nesting count. */\r
+                                               lSwitchRequired = pdTRUE;\r
+\r
+                                               /* Clear the interrupt pending bit. */\r
+                                               ulPendingInterrupts &= ~( 1UL << portINTERRUPT_YIELD );\r
+\r
+                                               lAcknowledgeInterrupt = pdTRUE;\r
+                                               break;\r
+\r
+                                       case portINTERRUPT_TICK:\r
+                                       \r
+                                               /* Tick interrupts should only be processed if the critical nesting count\r
+                                               is zero.  The critical nesting count represents the interrupt mask on \r
+                                               real target hardware. */\r
+                                               vPortTrace( "prvProcessEvents: Processing tick event\r\n" );\r
+                                               if( ulCriticalNesting == 0 )\r
+                                               {\r
+                                                       /* Process the tick itself. */\r
+                                                       vPortTrace( "prvProcessEvents: Incrementing tick\r\n" );\r
+                                                       vTaskIncrementTick();\r
+                                                       #if( configUSE_PREEMPTION != 0 )\r
+                                                       {\r
+                                                               /* A context switch is only automatically performed from the tick\r
+                                                               interrupt if the pre-emptive scheduler is being used. */\r
+                                                               lSwitchRequired = pdTRUE;\r
+                                                       }\r
+                                                       #endif\r
+                                                       \r
+                                                       lAcknowledgeTick = pdTRUE;\r
+\r
+                                                       /* Clear the interrupt pending bit. */\r
+                                                       ulPendingInterrupts &= ~( 1UL << portINTERRUPT_TICK );\r
+                                               }\r
+                                               break;\r
+\r
+                                       default:\r
+\r
+                                               /* Is a handler installed? */\r
+                                               if( vIsrHandler[ i ] != NULL )\r
+                                               {\r
+                                                       lSwitchRequired = pdTRUE;\r
+\r
+                                                       /* Run the actual handler. */\r
+                                                       vIsrHandler[ i ]();\r
+\r
+                                                       /* Clear the interrupt pending bit. */\r
+                                                       ulPendingInterrupts &= ~( 1UL << i );\r
+\r
+                                                       lAcknowledgeInterrupt = pdTRUE;\r
+                                               }\r
+                                               break;\r
+                               }\r
+                       }\r
+               }\r
+\r
+               if( lSwitchRequired != pdFALSE )\r
+               {\r
+                       void *pvOldCurrentTCB;\r
+\r
+                       pvOldCurrentTCB = pxCurrentTCB;\r
+\r
+                       /* Save the state of the current thread before suspending it. */\r
+                       pxThreadState = ( xThreadState *) *( ( unsigned long * ) pxCurrentTCB );\r
+                       pxThreadState->ulCriticalNesting = ulCriticalNesting ;\r
+                       \r
+                       /* Select the next task to run. */\r
+                       vTaskSwitchContext();\r
+                       \r
+                       /* If the task selected to enter the running state is not the task\r
+                       that is already in the running state. */\r
+                       if( pvOldCurrentTCB != pxCurrentTCB )\r
+                       {\r
+                               /* Suspend the old thread. */\r
+                               SuspendThread( pxThreadState->pvThread );\r
+                               sprintf( cTraceBuffer, "Event processor: suspending %s, resuming %s\r\n", ((xTCB*)pvOldCurrentTCB)->pcTaskName, ((xTCB*)pxCurrentTCB)->pcTaskName );\r
+                               vPortTrace( cTraceBuffer );\r
+\r
+                               /* Obtain the state of the task now selected to enter the Running state. */\r
+                               pxThreadState = ( xThreadState * ) ( *( unsigned long *) pxCurrentTCB );\r
+                               ulCriticalNesting = pxThreadState->ulCriticalNesting;\r
+                               ResumeThread( pxThreadState->pvThread );\r
+                       }\r
+               }\r
+\r
+               /* Was a tick processed? */\r
+               if( lAcknowledgeTick != pdFALSE )\r
+               {\r
+                       vPortTrace( "prvProcessEvents: Acking tick\r\n" );\r
+                       SetEvent( pvTickAcknowledgeEvent );\r
+               }\r
+\r
+               if( lAcknowledgeInterrupt != pdFALSE )\r
+               {\r
+                       vPortTrace( "prvProcessEvents: Acking interrupt\r\n" );\r
+                       SetEvent( pvInterruptAcknowledgeEvent );\r
+               }\r
+\r
+               ReleaseMutex( pvInterruptEventMutex );\r
+       }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+void vPortEndScheduler( void )\r
+{\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+void vPortGeneratePseudoInterrupt( unsigned long ulInterruptNumber )\r
+{\r
+       if( ( ulInterruptNumber < portMAX_INTERRUPTS ) && ( pvInterruptEventMutex != NULL ) )\r
+       {\r
+               /* Yield interrupts are processed even when critical nesting is non-zero. */\r
+               if( ( ulCriticalNesting == 0 ) || ( ulInterruptNumber == portINTERRUPT_YIELD ) )\r
+               {\r
+                       /* In case this task has just started running, reset the interrupt\r
+                       acknowledge event as it might have been set due to the activities\r
+                       of a thread that has already been executed and suspended. */\r
+                       ResetEvent( pvInterruptAcknowledgeEvent );\r
+\r
+                       WaitForSingleObject( pvInterruptEventMutex, INFINITE );\r
+                       ulPendingInterrupts |= ( 1 << ulInterruptNumber );\r
+                       vPortTrace( "vPortGeneratePseudoInterrupt: Got interrupt mutex, about to signal interrupt event\r\n" );\r
+                       SetEvent( pvInterruptEvent );\r
+                       vPortTrace( "vPortGeneratePseudoInterrupt: About to release interrupt event mutex\r\n" );\r
+                       ReleaseMutex( pvInterruptEventMutex );\r
+                       vPortTrace( "vPortGeneratePseudoInterrupt: Interrupt event mutex released, going to wait for next interrupt input\r\n" );\r
+\r
+                       WaitForSingleObject( pvInterruptAcknowledgeEvent, INFINITE );\r
+                       vPortTrace( "vPortGeneratePseudoInterrupt: Interrupt acknowledged, leaving vPortGeneratePseudoInterrupt()\r\n" );\r
+               }\r
+       }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+void vPortSetInterruptHandler( unsigned long ulInterruptNumber, void (*pvHandler)( void ) )\r
+{\r
+       if( ulInterruptNumber < portMAX_INTERRUPTS )\r
+       {\r
+               if( pvInterruptEventMutex != NULL )\r
+               {\r
+                       WaitForSingleObject( pvInterruptEventMutex, INFINITE );\r
+                       vIsrHandler[ ulInterruptNumber ] = pvHandler;\r
+                       ReleaseMutex( pvInterruptEventMutex );\r
+               }\r
+               else\r
+               {\r
+                       vIsrHandler[ ulInterruptNumber ] = pvHandler;\r
+               }\r
+       }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+void vPortEnterCritical( void )\r
+{\r
+       ulCriticalNesting++;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+void vPortExitCritical( void )\r
+{\r
+       if( ulCriticalNesting > portNO_CRITICAL_NESTING )\r
+       {\r
+               ulCriticalNesting--;\r
+\r
+               if( ulCriticalNesting == 0 )\r
+               {\r
+                       /* Were any interrupts set to pending while interrupts were \r
+                       (pseudo) disabled? */\r
+                       if( ulPendingInterrupts != 0UL )\r
+                       {\r
+                               WaitForSingleObject( pvInterruptEventMutex, INFINITE );\r
+                               vPortTrace( "vPortExitCritical:  Setting interrupt event\r\n" );\r
+                               SetEvent( pvInterruptEvent );\r
+                               ReleaseMutex( pvInterruptEventMutex );\r
+\r
+                               vPortTrace( "vPortExitCritical:  Waiting interrupt ack\r\n" );\r
+                               WaitForSingleObject( pvInterruptAcknowledgeEvent, INFINITE );\r
+                               vPortTrace( "vPortExitCritical: Interrupt acknowledged, leaving critical section code\r\n" );\r
+\r
+                               /* Just in case the Yield does not happen immediately.  This\r
+                               line could be dangerious if not all interrupts are being\r
+                               processed. */\r
+//                             while( ulPendingInterrupts != 0UL );\r
+                       }\r
+               }\r
+       }\r
+}\r
diff --git a/Source/portable/MSVC-MingW/portmacro.h b/Source/portable/MSVC-MingW/portmacro.h
new file mode 100644 (file)
index 0000000..94cca44
--- /dev/null
@@ -0,0 +1,112 @@
+/*\r
+    FreeRTOS V6.1.0 - Copyright (C) 2010 Real Time Engineers Ltd.\r
+\r
+    ***************************************************************************\r
+    *                                                                         *\r
+    * If you are:                                                             *\r
+    *                                                                         *\r
+    *    + New to FreeRTOS,                                                   *\r
+    *    + Wanting to learn FreeRTOS or multitasking in general quickly       *\r
+    *    + Looking for basic training,                                        *\r
+    *    + Wanting to improve your FreeRTOS skills and productivity           *\r
+    *                                                                         *\r
+    * then take a look at the FreeRTOS books - available as PDF or paperback  *\r
+    *                                                                         *\r
+    *        "Using the FreeRTOS Real Time Kernel - a Practical Guide"        *\r
+    *                  http://www.FreeRTOS.org/Documentation                  *\r
+    *                                                                         *\r
+    * A pdf reference manual is also available.  Both are usually delivered   *\r
+    * to your inbox within 20 minutes to two hours when purchased between 8am *\r
+    * and 8pm GMT (although please allow up to 24 hours in case of            *\r
+    * exceptional circumstances).  Thank you for your support!                *\r
+    *                                                                         *\r
+    ***************************************************************************\r
+\r
+    This file is part of the FreeRTOS distribution.\r
+\r
+    FreeRTOS is free software; you can redistribute it and/or modify it under\r
+    the terms of the GNU General Public License (version 2) as published by the\r
+    Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
+    ***NOTE*** The exception to the GPL is included to allow you to distribute\r
+    a combined work that includes FreeRTOS without being obliged to provide the\r
+    source code for proprietary components outside of the FreeRTOS kernel.\r
+    FreeRTOS is distributed in the hope that it will be useful, but WITHOUT\r
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\r
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\r
+    more details. You should have received a copy of the GNU General Public\r
+    License and the FreeRTOS license exception along with FreeRTOS; if not it\r
+    can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
+    by writing to Richard Barry, contact details for whom are available on the\r
+    FreeRTOS WEB site.\r
+\r
+    1 tab == 4 spaces!\r
+\r
+    http://www.FreeRTOS.org - Documentation, latest information, license and\r
+    contact details.\r
+\r
+    http://www.SafeRTOS.com - A version that is certified for use in safety\r
+    critical systems.\r
+\r
+    http://www.OpenRTOS.com - Commercial support, development, porting,\r
+    licensing and training services.\r
+*/\r
+\r
+#ifndef PORTMACRO_H\r
+#define PORTMACRO_H\r
+\r
+#include <Windows.h>\r
+//#include <tchar.h>\r
+\r
+/******************************************************************************\r
+       Defines\r
+******************************************************************************/\r
+/* Type definitions. */\r
+#define portCHAR               char\r
+#define portFLOAT              float\r
+#define portDOUBLE             double\r
+#define portLONG               long\r
+#define portSHORT              short\r
+#define portSTACK_TYPE unsigned portLONG\r
+#define portBASE_TYPE  portLONG\r
+\r
+#if( USE_16_BIT_TICKS == 1 )\r
+    typedef unsigned portSHORT portTickType;\r
+    #define portMAX_DELAY ( portTickType ) 0xffff\r
+#else\r
+    typedef unsigned portLONG portTickType;\r
+    #define portMAX_DELAY ( portTickType ) 0xffffffff\r
+#endif\r
+\r
+/* Hardware specifics. */\r
+#define portSTACK_GROWTH                       ( -1 )\r
+#define portTICK_RATE_MS                       ( ( portTickType ) 1000 / configTICK_RATE_HZ )  \r
+#define portBYTE_ALIGNMENT                     4\r
+\r
+#define portYIELD()                                    vPortGeneratePseudoInterrupt( portINTERRUPT_YIELD )\r
+#define portDISABLE_INTERRUPTS()\r
+#define portENABLE_INTERRUPTS()\r
+\r
+/* Critical section handling. */\r
+void vPortEnterCritical( void );\r
+void vPortExitCritical( void );\r
+\r
+#define portENTER_CRITICAL()           vPortEnterCritical()\r
+#define portEXIT_CRITICAL()                    vPortExitCritical()\r
+\r
+/* Task function macros as described on the FreeRTOS.org WEB site. */\r
+#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void * pvParameters )\r
+#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void * pvParameters )\r
+\r
+\r
+#define portINTERRUPT_YIELD                            ( 0UL )\r
+#define portINTERRUPT_TICK                             ( 1UL )\r
+\r
+/* \r
+ * Raise a simulated interrupt represented by the bit mask in ulInterruptMask.\r
+ * Each bit can be used to represent an individual interrupt - with the first\r
+ * two bits being used for the Yield and Tick interrupts respectively.\r
+*/\r
+void vPortGeneratePseudoInterrupt( unsigned long ulInterruptNumber );\r
+\r
+\r
+#endif\r