MakingThings
  • Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

rtos.c

Go to the documentation of this file.
00001 /*********************************************************************************
00002 
00003  Copyright 2006-2008 MakingThings
00004 
00005  Licensed under the Apache License, 
00006  Version 2.0 (the "License"); you may not use this file except in compliance 
00007  with the License. You may obtain a copy of the License at
00008 
00009  http://www.apache.org/licenses/LICENSE-2.0 
00010  
00011  Unless required by applicable law or agreed to in writing, software distributed
00012  under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
00013  CONDITIONS OF ANY KIND, either express or implied. See the License for
00014  the specific language governing permissions and limitations under the License.
00015 
00016 *********************************************************************************/
00017 
00018 /** \file rtos.c  
00019   RTOS - Real Time Operating System.
00020   Functions to work within FreeRTOS on the Make Controller Board.
00021 */
00022 
00023 /* Scheduler includes. */
00024 #include "FreeRTOS.h"
00025 #include "task.h"
00026 #include "rtos.h"
00027 #include "string.h"
00028 #include "queue.h"
00029 #include "semphr.h"
00030 
00031 void* findTask( char *taskName, int taskID );
00032 void* iterateForNextTask( void** lowTask, int* lowID, void** highTask, int* highID, int currentID, xList* pxList );
00033 void* iterateByID( int id, xList* pxList );
00034 void* iterateByName( char* taskName, xList* pxList );
00035 void* TaskGetNext_internal( void* task );
00036 
00037 /** \defgroup RTOS RTOS
00038   The RTOS subsystem provides a real-time operating system (RTOS) for the MAKE Controller.
00039   Currently, the Make Controller uses FreeRTOS, an open source Real-Time Operating System.  It implements a scheduler that 
00040   gives time to "concurrent" tasks according to their given priority.  It allows programmers to 
00041   focus on programming each process on the board separately, letting the RTOS 
00042   determine when each of those tasks should be given processor time.
00043   
00044   More info at http://www.freertos.org
00045 * \ingroup Core
00046 */
00047 
00048 /** \defgroup Tasks Tasks
00049   The individual "programs" that make up your application.
00050   Tasks can all be written separately and the RTOS will take of switching between them, 
00051   making sure they all get the processing time they need.  Each task is implemented as a continuous loop, and
00052   all tasks have the same signature:
00053   \code void MyTask( void* parameters) \endcode
00054   The void* parameters is a value that can be passed in at the time the task is created.  Make sure that you put your task
00055   to sleep when it's not doing anything so that other tasks can get time as well.  Otherwise, the Controller will lock up
00056   and none of the other tasks will run.
00057   
00058   \par Example
00059   \code
00060   void MyTask( void* p )
00061   {
00062     // some initialization here
00063     int newVal = 0;
00064     
00065     // then just sit in our loop
00066     // we're going to turn an LED on whenever an AnalogIn is over a certain value 
00067     while( 1 )
00068     {
00069       newVal = AnalogIn_GetValue( 1 );
00070       if( newVal < 512 )
00071         AppLed_SetState( 0, 1 );
00072       else
00073         AppLed_SetState( 0, 0 );
00074       Sleep( 100 ); // wait for 100 milliseconds, allowing other tasks to do their thing
00075     }
00076   }
00077   \endcode
00078   
00079   Notice we don't need to include anything about Ethernet or USB communication, or anything else that might
00080   be going on.  These are taken care of elsewhere by the RTOS, allowing us to focus on our LED blinking.
00081   
00082   More info at http://www.freertos.org
00083 * \ingroup RTOS
00084 * @{
00085 */
00086 
00087 /** 
00088   Put a task to sleep for a given number of milliseconds.
00089   This lets the processor give time to other tasks.  You'll always want to include some amount of Sleep( ) in your tasks
00090   to avoid locking up the Controller.
00091   @param timems An integer specifying how long to sleep in milliseconds.
00092   
00093 \par Example
00094 \code
00095 void MyTask( void *p) // in your task
00096 {
00097   while( 1 )
00098   {
00099     Led_SetState( 0 ); // turn the LED off
00100     Sleep( 900 ); // leave it off for 900 milliseconds
00101     Led_SetState( 1 ); // turn the LED on
00102     Sleep( 10 ); // leave it on for 10 milliseconds
00103   }
00104 }
00105 \endcode
00106 */
00107 void Sleep( int timems )
00108 {
00109   vTaskDelay( timems / portTICK_RATE_MS );
00110 }
00111 
00112 /** 
00113   Give up the remaining time allotted to this task by the processor.
00114   The presently running task immeidately gives up the remaining time it has in the current timeslice 
00115   so that other tasks can run.  While Sleep() will wait the specified number of milliseconds 
00116   before continuing, TaskYield() will cause the task to take processor time again 
00117   as soon as it's available.
00118 */
00119 void TaskYield( )
00120 {
00121   taskYIELD(); 
00122 }
00123 
00124 /** 
00125   Create a new task.
00126   
00127   When creating a new task, be sure that you allocate it enough stack space.  A task must have enough stack space 
00128   to load any of the potential data structures it will be working with, otherwise it will die and the Controller will crash.
00129   
00130   Since FreeRTOS is pre-emptive, higher priority tasks will get processor time before lower priority tasks.  The priority
00131   level is a bit arbitrary, but choose something that makes sense in relation to the other tasks you have running. Always be 
00132   sure to block a task when possible, in order to give processor time to other tasks.
00133   @param taskCode A pointer to the function that will run when the task starts.
00134   @param name A character string containing the name of the task.
00135   @param stackDepth An integer specifying in bytes the size of the task's stack.
00136   @param parameters A void* parameter which will be passed into the task at create time.
00137   @param priority An integer specifying the task's priority (0 lowest - 7 highest priority).
00138   @return A pointer to the handle for the newly created task, or NULL if it didn't succeed.
00139   @see TaskDelete( )
00140   
00141 \par Example
00142 \code
00143 // create the task MyTask, called "Me", with a stack of 1000 bytes, no parameters, at priority 1
00144 void *taskPtr = TaskCreate( MyTask, "Me", 1000, 0, 1 );
00145 
00146 void MyTask( void *p) // in your task
00147 {
00148   // set up any variables that you'll need
00149   int counter = 0;
00150   // then start your continuous loop
00151   while( 1 )
00152   {
00153     counter++;
00154     Sleep( 100 );
00155   }
00156 }
00157 \endcode
00158 */
00159 void* TaskCreate( void (taskCode)( void*), char* name, int stackDepth, void* parameters, int priority )
00160 {
00161   void* taskHandle;
00162   if( xTaskCreate( taskCode, (signed char*)name, ( stackDepth >> 2 ), parameters, priority, &taskHandle ) == 1 )
00163     return taskHandle;
00164   else
00165     return NULL;
00166 }
00167 
00168 /** 
00169   Delete an existing task.
00170   TaskCreate( ) returns a pointer to the newly created task.  You'll need to hang onto this pointer in order to delete the task.
00171   @param task A pointer to the handle of the task to be deleted.
00172   
00173 \par Example
00174 \code
00175 void *taskPtr = TaskCreate( MyTask, "Me", 1000, 0, 1 ); // create a new task
00176 // ... run the task ...
00177 TaskDelete( taskPtr ); // then delete it
00178 \endcode
00179 */
00180 void TaskDelete( void* task )
00181 {
00182   vTaskDelete( task );
00183 }
00184 
00185 /** 
00186   Specify that a task is entering a period during which it should not be interrupted.  
00187   Call this from within your task.  Be sure to minimize use of this, and to call TaskExitCritical() as soon as the 
00188   task has completed its critical stage.  Other tasks can't get any processor time while in
00189   this state, and performance might be compromised.
00190   @see TaskExitCritical( )
00191 */
00192 void  TaskEnterCritical( )
00193 {
00194   taskENTER_CRITICAL();
00195 }
00196 
00197 /** 
00198   Specify that a task is exiting a critical period, in response to TaskEnterCritical().
00199   Once the task exits a critical period, FreeRTOS will resume switching this task as usual.
00200   @see TaskEnterCritical( )
00201 */
00202 void  TaskExitCritical( )
00203 {
00204   taskEXIT_CRITICAL();
00205 }
00206 
00207 /** 
00208 Check how much stack is available for a given task.
00209 When a task is created, it is initialized with a stack depth.  This function will return the
00210 numbers of bytes available from that initial allocation.
00211 @return An integer specifying the available stack in bytes.
00212 @see TaskGetStackAllocated( )
00213 
00214 \par Example
00215 \code
00216 void *taskPtr = TaskCreate( MyTask, "Mine", 1000, 0, 1 ); // create a new task
00217 int freeBytes = TaskGetRemainingStack( taskPtr ); // check how much of the task's stack has been used
00218 \endcode
00219 */
00220 int TaskGetRemainingStack( void* task )
00221 {
00222   if( task != NULL )
00223     return usVoidTaskCheckFreeStackSpace( task );
00224   else
00225     return CONTROLLER_ERROR_INSUFFICIENT_RESOURCES;
00226 }
00227 
00228 /** 
00229   Get a pointer to a task by its name.
00230   When a task is created, it is initialized with a name.  If you don't have a pointer to the task itself
00231   but you know its name, you can still get a reference to the task.  This is a costly function, as it
00232   shuts down the scheduler to search for the task, so it should really only be used in a debug setting.
00233   @param taskName A character string specifying the name of the task to find.
00234   @return A pointer to the task, or NULL if the task was not found.
00235   @see getTaskByID()
00236   
00237 \par Example
00238 \code
00239 TaskCreate( MyTask, "Mine", 1000, 0, 1 ); // a task has been created, but we don't have a pointer to it
00240 void *taskPtr = getTaskByName( "Mine" ); // but we can still get a pointer to it by its name
00241 \endcode
00242 */
00243 void* getTaskByName( char *taskName )
00244 {
00245   void *tcb = NULL;
00246   vTaskSuspendAll();
00247   {
00248     tcb = findTask( taskName, -1 );
00249   }
00250   xTaskResumeAll();
00251   return tcb;
00252 }
00253 
00254 /** 
00255   Get a pointer to a task by its ID number.
00256   Each task is given a unique ID number by freeRTOS.  If you know this number, but don't have a pointer
00257   to the task, use this function to get a pointer to the task itself.  This is a costly function, as it
00258   shuts down the scheduler to search for the task, so it should really only be used in a debug setting.
00259   @param taskID An integer specifying the unique ID number given to the task by FreeRTOS
00260   @return A pointer to the task, or NULL if the task was not found.
00261   @see TaskGetIDNumber( )
00262 */
00263 void* getTaskByID( int taskID )
00264 {
00265   void* tcb = NULL;
00266   vTaskSuspendAll();
00267   {
00268     tcb = findTask( NULL, taskID );
00269   }
00270   xTaskResumeAll();
00271   return tcb;
00272 }
00273 
00274 /** 
00275   Get the priority of a task.
00276   When a task is created, it's given a priority from 1-7.  Use this function to get the task's priority
00277   after it has been created.
00278   @param task A pointer to the task.
00279   @return An integer specifying the task's priority
00280   
00281 \par Example
00282 \code
00283 void *taskPtr = TaskCreate( MyTask, "Mine", 1000, 0, 1 );
00284 int priority = TaskGetPriority( taskPtr ); // will return 1
00285 \endcode
00286 */
00287 int TaskGetPriority( void* task )
00288 {
00289   return xTaskGetPriority( task );
00290 }
00291 
00292 /** 
00293   Get the ID number of a task.
00294   FreeRTOS assigns each task a unique ID number.  Use this function to retrieve a particular task's ID number.
00295   Task ID numbers are not necessarily sequential.
00296   @param task A pointer to the task.
00297   @return An integer specifying the task's unique ID within freeRTOS, or -1 on fail.
00298   
00299 \par Example
00300 \code
00301 void *taskPtr = TaskCreate( MyTask, "Mine", 1000, 0, 1 );
00302 int id = TaskGetIDNumber( taskPtr );
00303 \endcode
00304 */
00305 int TaskGetIDNumber( void* task )
00306 {
00307   return xTaskGetIDNumber( task );
00308 }
00309 
00310 /** 
00311   Get the name of a task.
00312   Read back the name a task was given when it was created.
00313   @param task A pointer to the task.
00314   @return The task's name as a string
00315   
00316 \par Example
00317 \code
00318 void *taskPtr = TaskCreate( MyTask, "Mine", 1000, 0, 1 );
00319 char* name = TaskGetName( taskPtr ); // will return "Mine"
00320 \endcode
00321 */
00322 char* TaskGetName( void* task )
00323 {
00324   return (char*)xTaskGetName( task );
00325 }
00326 
00327 /** 
00328   Read the amount of stack initially allocated for a task.
00329   Each task is allocated a certain amount of stack space when it's created.  Use this function to
00330   determine how much stack space a task was originally given.
00331   @param task A pointer to the task.
00332   @return An integer specifying the amount of stack, in bytes, that this task was allocated.
00333   @see TaskGetRemainingStack( )
00334   
00335 \par Example
00336 \code
00337 void *taskPtr = TaskCreate( MyTask, "Mine", 1000, 0, 1 );
00338 int stack = TaskGetStackAllocated( taskPtr ); // will return 1000
00339 \endcode
00340 */
00341 int TaskGetStackAllocated( void* task )
00342 {
00343   return xTaskGetStackAllocated( task );
00344 }
00345 
00346 /** 
00347   Get a pointer to the task that's currently running.
00348   @return A pointer to the task that's currently running.
00349   
00350 \par Example
00351 \code
00352 void *currentTask = TaskGetCurrent( );
00353 \endcode
00354 */
00355 void* TaskGetCurrent( )
00356 {
00357   return xTaskGetCurrentTaskHandle( );
00358 }
00359 
00360 /** 
00361   Read the highest priority being used by any existing task.
00362   @return An integer specifying the priority.
00363   
00364 \par Example
00365 \code
00366 int highestPriority = TaskGetTopPriorityUsed( );
00367 \endcode
00368 */
00369 int TaskGetTopPriorityUsed( )
00370 {
00371   return xTaskGetTopUsedPriority( );
00372 }
00373 
00374 /** 
00375   Get a pointer to the task whose ID comes after a given ID.
00376   FreeRTOS assigns each task a unique ID number internally.  This function will
00377   return a pointer to the task with the next ID.  Note that this does not necessarily
00378   mean that this task will be given processor time next, just that its ID is the next 
00379   one along in the list of all tasks.
00380 
00381   This is an expensive function since it needs to stop the scheduler to search the lists
00382   of tasks.  It should only really be used in a debug setting.
00383   @param task A pointer to the previous task.
00384   @return A pointer to the task that's next in the ID list.
00385   
00386 \par Example
00387 \code
00388 void *oneTask = TaskCreate( MyTask, "Mine", 1000, 0, 1 );
00389 void *nextTask = TaskGetNext( oneTask );
00390 \endcode
00391 */
00392 void* TaskGetNext( void* task )
00393 {
00394   void* taskreturn = NULL;
00395   vTaskSuspendAll();
00396   {
00397     taskreturn = TaskGetNext_internal( task );
00398   }
00399   xTaskResumeAll( );
00400   return taskreturn;
00401 }
00402 
00403 /** 
00404   Get the total number of tasks that exist at a given moment.
00405   @return An integer specifying the number of tasks.
00406   
00407 \par Example
00408 \code
00409 int numberOfTasks = GetNumberOfTasks( );
00410 \endcode
00411 */
00412 int GetNumberOfTasks( )
00413 {
00414   return uxTaskGetNumberOfTasks( );
00415 }
00416 
00417 /** 
00418   Update the priority of a task.
00419   Higher numbers mean higher priority/more processor time.
00420   @param task A pointer to the task you want to update.
00421   @param priority An integer specifying the new priority.
00422   
00423 \par Example
00424 \code
00425 void *task = TaskCreate( MyTask, "Mine", 1000, 0, 1 ); // create a task
00426 // ... now update the task's priority to 6
00427 TaskSetPriority( task, 6 );
00428 \endcode
00429 */
00430 void TaskSetPriority( void* task, int priority )
00431 {
00432   vTaskPrioritySet( task, priority );
00433 }
00434 
00435 /** 
00436   Returns the number of ticks since the scheduler started.
00437   @return the number of ticks
00438 */
00439 int TaskGetTickCount( void )
00440 {
00441   return xTaskGetTickCount( );
00442 }
00443 
00444 /** @}
00445 */
00446 
00447 /** \defgroup Utils Utilities
00448   General utilities provided by the RTOS.
00449   
00450   FreeRTOS has several options for memory management - we've chosen a default one here which
00451   is pretty sensible in most cases, but you're of course welcome to use whatever makes most 
00452   sense for your application.  See http://www.freertos.org/a00111.html for
00453   the available options.
00454 
00455 * \ingroup RTOS
00456 * @{
00457 */
00458 
00459 /** 
00460   Dynamically allocate memory from the heap.
00461   This is pretty much the same as a normal malloc(), but for the SAM7X. 
00462   @return A pointer to the allocated memory, or NULL if the memory was not available.
00463   @see Free(), System_GetFreeMemory( )
00464   
00465   \par Example
00466   \code
00467   int bufferSize = 1024;
00468   char *bufferPtr = Malloc( bufferSize );
00469   // now you have a 1024 character buffer
00470   \endcode
00471 */
00472 void* Malloc( int size )
00473 {
00474   return pvPortMalloc( size );
00475 }
00476 
00477 /** 
00478   Same as Malloc, but keeps trying until it succeeds.
00479   This is a convenience function that will continue to call Malloc( ) at a given interval until
00480   it returns successfully.  Once this function returns, you know you have been allocated the memory
00481   you asked for.
00482   
00483   @param size An integer specifying the amount of memory, in bytes, you want to allocate.
00484   @param interval An integer specifying the number of milliseconds to wait between successive attempts to allocate memory.  
00485   It's best to not set this too low, as it will be a bit taxing on the system.
00486   @return A pointer to the allocated memory, or NULL if the memory was not available.
00487   @see Free(), System_GetFreeMemory( )
00488   
00489   \par Example
00490   \code
00491   char *bufferPtr = MallocWait( 1024, 100 );
00492   // now you have a 1024 character buffer
00493   \endcode
00494 */
00495 void* MallocWait( int size, int interval )
00496 {
00497   void* retval = NULL;
00498   while( retval == NULL )
00499   {
00500     retval = Malloc( size );
00501     if( retval )
00502       return retval;
00503     else
00504       Sleep( interval );
00505   }
00506   return NULL; // should never get here
00507 }
00508 
00509 /** 
00510   Free memory from the heap.
00511   Once you've allocated memory using Malloc(), free it when you're done with it.
00512   It's usually a good idea to set the pointer the freed memory to NULL after you've freed it.
00513   @param memory A pointer to the memory created by Malloc( )
00514   @see Malloc(), System_GetFreeMemory( )
00515   
00516   \par Example
00517   \code
00518   char *bufferPtr = Malloc( 1024 ); // allocate 1024 bytes of memory
00519   // ...your processing here...
00520   Free( bufferPtr ); // then free the memory when you're done with it
00521   \endcode
00522 */
00523 void Free( void* memory )
00524 {
00525   vPortFree( memory ); 
00526 }
00527 
00528 /** @}
00529 */
00530 
00531 /** \defgroup Queues Queues
00532   Queues allow for thread-safe inter-process communication.
00533   A queue is a list of items that can be passed from one task to another.
00534   Items are placed in a queue by copy - not by reference. It is therefore preferable, 
00535   when queuing large items, to only queue a pointer to the item.  Tasks can block on a 
00536   queue to wait for either data to become available on the queue, or space to become available to write to the queue.
00537   
00538   More info at http://www.freertos.org - some documentation here used from the FreeRTOS doc by Richard Barry.
00539 * \ingroup RTOS
00540 * @{
00541 */
00542 
00543 /** 
00544   Create a new queue.
00545   This allocates storage for the queue.  It's usually a good idea to pass around pointers on queues
00546   as opposed to whole data structures, as that's quite resource intensive.
00547   @param length The maximum number of items that the queue can contain.
00548   @param itemSize The number of bytes each item in the queue will require.  Items are queued by copy, not by reference, 
00549   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.
00550   @return A pointer to the queue on success, 0 if the queue couldn't be created.
00551   
00552   \par Example
00553   \code
00554   struct myData_
00555   {
00556     int count;
00557     char buffer[100];
00558   };
00559 
00560   // create a queue that can hold 5 pointers to myData structures
00561   struct MyData_* myData;
00562   void* myQueue = QueueCreate( 5, sizeof( myData* ) );
00563   if( myQueue == 0 )
00564     // then the queue can't be used.
00565   else
00566     // continue processing...
00567   \endcode
00568 */
00569 void* QueueCreate( uint length, uint itemSize )
00570 {
00571   return xQueueCreate( length, itemSize );
00572 }
00573 
00574 /** 
00575   Post an item onto the front of a queue.
00576   The item is queued by copy, not by reference.  This function must not be called from an interrupt service routine.
00577   See xQueueSendFromISR () for an alternative which may be used in an ISR.
00578   @param queue The queue to send to.
00579   @param itemToQueue A pointer to the item to send on the queue.  
00580   @param msToWait The maximum number of milliseconds the task should block waiting for space to become available on the queue, 
00581   should it already be full.  The call will return immediately if this is set to 0.
00582   @return 1 on success, 0 on failure.
00583   
00584   \par Example
00585   \code
00586   struct MyData_
00587   {
00588     int count;
00589     char buffer[100];
00590   };
00591 
00592   // create a queue that can hold 5 pointers to myData structures
00593   struct MyData_* myData;
00594   void* myQueue = QueueCreate( 5, sizeof( myData* ) );
00595   if( myQueue )
00596   {
00597     if( QueueSendToFront( myQueue, (void*)&myData, 10 ) ) // wait 10 ms to send if queue is full
00598       // then we're all set
00599     else
00600       // deal with an unsuccessful send
00601   }
00602   \endcode
00603 */
00604 int QueueSendToFront( void* queue, void* itemToQueue, int msToWait )
00605 {
00606   return xQueueSend( queue, itemToQueue, msToWait / portTICK_RATE_MS );
00607 }
00608 
00609 /** 
00610   Post an item onto the back of a queue.
00611   The item is queued by copy, not by reference.  This function must not be called from an interrupt service routine.
00612   See xQueueSendFromISR () for an alternative which may be used in an ISR.
00613   @param queue The queue to send to.
00614   @param itemToQueue A pointer to the item to send on the queue.  
00615   @param msToWait The maximum number of milliseconds the task should block waiting for space to become available on the queue, 
00616   should it already be full.  The call will return immediately if this is set to 0.
00617   @return 1 on success, 0 on failure.
00618   
00619   \par Example
00620   \code
00621   struct MyData_
00622   {
00623     int count;
00624     char buffer[100];
00625   };
00626 
00627   // create a queue that can hold 5 pointers to myData structures
00628   struct MyData_* myData;
00629   void* myQueue = QueueCreate( 5, sizeof( myData* ) );
00630   if( myQueue )
00631   {
00632     if( QueueSendToBack( myQueue, (void*)&myData, 10 ) ) // wait 10 ms to send if queue is full
00633       // then we're all set
00634     else
00635       // deal with an unsuccessful send
00636   }
00637   \endcode
00638 */
00639 int QueueSendToBack( void* queue, void* itemToQueue, int msToWait )
00640 {
00641   return xQueueSend( queue, itemToQueue, msToWait / portTICK_RATE_MS );
00642 }
00643 
00644 /** 
00645   Read an item off of a queue.
00646   The item is received by copy so a buffer of adequate size must be provided. 
00647   The number of bytes copied into the buffer was defined when the queue was created.
00648   The item will be removed from the queue once it is read.
00649   
00650   This function must not be used in an interrupt service routine. See QueueReceiveFromISR( ) for an alternative that can.
00651   @param queue The queue to receive from.
00652   @param buffer A pointer to the buffer the item will be read into.  
00653   @param msToWait The maximum number of milliseconds the task should block waiting for an item to show up on the queue, 
00654   should it be empty.
00655   @return 1 on success, 0 on failure.
00656   
00657   \par Example
00658   \code
00659   struct MyData_
00660   {
00661     int count;
00662     char buffer[100];
00663   };
00664   
00665   void* myQueue;
00666   
00667   void SomeTask( void* p )
00668   {
00669     // create a queue that can hold 5 pointers to myData structures
00670     myQueue = QueueCreate( 5, sizeof( myData* ) );
00671     struct MyData_ myData; // the data we'll be sending
00672     myData.count = 12;
00673     myData.buffer = "ABCDEF";
00674     
00675     QueueSendToFront( myQueue, &myData, 0 );
00676   }
00677   
00678   void AnotherTask( void* p )
00679   {
00680     int dataSize = sizeof( struct MyData_ );
00681     struct MyData_* rxData; // a pointer to some data
00682     if( myQueue )
00683     {
00684       if( QueueReceive( myQueue, rxData, 100 ) ) // wait up to 100 milliseconds for data
00685       {
00686         // now rxData points to the data posted in SomeTask
00687       }
00688     }
00689   }
00690   \endcode
00691 */
00692 int QueueReceive( void* queue, void* buffer, int msToWait )
00693 {
00694   return xQueueReceive( queue, buffer, msToWait / portTICK_RATE_MS );
00695 }
00696 
00697 /** 
00698   Return the number of messages waiting in a queue.
00699 
00700   @param queue The queue to look at.
00701   @return The number of messages waiting.
00702   
00703   \par Example
00704   \code
00705   int msgs = QueueMessagesWaiting( myQueue );
00706   \endcode
00707 */
00708 int QueueMessagesWaiting( void* queue )
00709 {
00710   return uxQueueMessagesWaiting( queue );
00711 }
00712 
00713 /** 
00714   Delete a queue - freeing all the memory allocated for storing of items placed on the queue.
00715   @param queue The queue to delete.
00716   
00717   \par Example
00718   \code
00719   QueueDelete( myQueue );
00720   \endcode
00721 */
00722 void QueueDelete( void* queue )
00723 {
00724   vQueueDelete( queue );
00725 }
00726 
00727 /** 
00728   Post an item to the front of a queue from within an interrupt service routine.
00729   Items are queued by copy not reference so it is preferable to only queue small items, especially when called from an ISR. 
00730   In most cases it would be preferable to store a pointer to the item being queued.
00731   @param queue The queue to send to.
00732   @param itemToSend A pointer to the item to send on the queue.  The size of the items the queue will hold was defined 
00733   when the queue was created, so this many bytes will be copied from itemToSend into the queue storage area.
00734   @param taskPreviouslyWoken This is included so an ISR can post onto the same queue multiple times from a single interrupt. 
00735   The first call should always pass in 0. Subsequent calls should pass in the value returned from the previous call.
00736   @return 1 if a task was woken by posting onto the queue. This is used by the ISR to determine if a context 
00737   switch may be required following the ISR.
00738   
00739   \par Example
00740   \code
00741   struct MyData_
00742   {
00743     int count;
00744     char buffer[100];
00745   };
00746   
00747   int taskWokenByPost = 0; // be sure to initialize to 0
00748 
00749   // create a queue that can hold 5 pointers to myData structures
00750   struct MyData_ myData;
00751   void* myQueue = QueueCreate( 5, sizeof( myData* ) );
00752   if( myQueue )
00753   {
00754     taskWokenByPost = QueueSendToFrontFromISR( myQueue, (void*)&myData, taskWokenByPost )
00755     if( taskWokenByPost )
00756     {
00757         // We should switch context so the ISR returns to a different task.    
00758         portYIELD_FROM_ISR( );
00759     }
00760   }
00761   \endcode
00762 */
00763 int QueueSendToFrontFromISR( void* queue, void* itemToSend, int taskPreviouslyWoken )
00764 {
00765   return xQueueSendToFrontFromISR( queue, itemToSend, taskPreviouslyWoken );
00766 }
00767 
00768 /** 
00769   Post an item to the back of a queue from within an interrupt service routine.
00770   Items are queued by copy not reference so it is preferable to only queue small items, especially when called from an ISR. 
00771   In most cases it would be preferable to store a pointer to the item being queued.
00772   @param queue The queue to send to.
00773   @param itemToSend A pointer to the item to send on the queue.  The size of the items the queue will hold was defined 
00774   when the queue was created, so this many bytes will be copied from itemToSend into the queue storage area.
00775   @param taskPreviouslyWoken This is included so an ISR can post onto the same queue multiple times from a single interrupt. 
00776   The first call should always pass in 0. Subsequent calls should pass in the value returned from the previous call.
00777   @return 1 if a task was woken by posting onto the queue. This is used by the ISR to determine if a context 
00778   switch may be required following the ISR.
00779   
00780   \par Example
00781   \code
00782   struct MyData_
00783   {
00784     int count;
00785     char buffer[100];
00786   };
00787   
00788   int taskWokenByPost = 0; // be sure to initialize to 0
00789 
00790   // create a queue that can hold 5 pointers to myData structures
00791   struct MyData_ myData;
00792   void* myQueue = QueueCreate( 5, sizeof( myData* ) );
00793   if( myQueue )
00794   {
00795     taskWokenByPost = QueueSendToBackFromISR( myQueue, (void*)&myData, taskWokenByPost )
00796     if( taskWokenByPost )
00797     {
00798         // We should switch context so the ISR returns to a different task.    
00799         portYIELD_FROM_ISR( );
00800     }
00801   }
00802   \endcode
00803 */
00804 int QueueSendToBackFromISR( void* queue, void* itemToSend, int taskPreviouslyWoken )
00805 {
00806   return xQueueSendToBackFromISR( queue, itemToSend, taskPreviouslyWoken );
00807 }
00808 
00809 /** 
00810   Receive an item from a queue from within an interrupt service routine.
00811   You'll need to have enough storage for the queue to copy the item into.  Receiving from a queue takes the item off the queue.
00812   @param queue The queue to receive from.
00813   @param buffer A pointer to the buffer into which the received item will be copied - ensure that there's enough room.
00814   @param taskWoken A task may be blocked waiting for an item to be read from the queue, freeing up space. If QueueReceiveFromISR 
00815   causes such a task to unblock *taskWoken will get set to 1, otherwise *taskWoken will remain unchanged.
00816   @return 1 if an item was successfully received from the queue, otherwise 0.
00817   switch may be required following the ISR.
00818   
00819   \par Example
00820   \code
00821   
00822   int taskWokenByReceive = 0; // be sure to initialize to 0
00823   void* myQueue = QueueCreate( 5, sizeof( char ) );
00824   if( myQueue == 0 )
00825     // queue couldn't be created...
00826   
00827   char data;
00828 
00829   while( QueueReceiveFromISR( myQueue, (void*)&data, taskWokenByReceive ) )
00830   {
00831     // process new items from queue here
00832     
00833     // If removing an item from the queue woke the task that was 
00834     // posting onto the queue, taskWokenByReceive will have been set to
00835     // 1.  No matter how many times this loop iterates only one
00836     // task will be woken.
00837   }
00838   if( taskWokenByReceive )
00839   {
00840       // We should switch context so the ISR returns to a different task.    
00841       taskYIELD ();
00842   }
00843   \endcode
00844 */
00845 int QueueReceiveFromISR( void* queue, void* buffer, long* taskWoken )
00846 {
00847   return xQueueReceiveFromISR( queue, buffer, taskWoken );
00848 }
00849 
00850 /** @}
00851 */
00852 
00853 /** \defgroup SemaphoresMutexes Semaphores & Mutexes
00854   Thread-safe methods to protect access to shared resources.
00855   
00856   Quite often you'll have more than one task trying to get access to the same resources.  To ensure that the resource
00857   is not in some intermediate state between reading and writing, it's necessary to serialize access to it.  Semaphores
00858   and mutexes provide a way to do this.
00859   
00860   Binary semaphores and mutexes are very similar but have some subtle differences: 
00861   Mutexes include a priority inheritance mechanism, binary semaphores do not. This makes binary semaphores the 
00862   better choice for implementing synchronisation (between tasks or between tasks and an interrupt), and mutexes 
00863   the better choice for implementing simple mutual exclusion.
00864 
00865   A binary semaphore need not be given back once obtained, so task synchronisation can be implemented by one task/interrupt 
00866   continuously 'giving' the semaphore while another continuously 'takes' the semaphore.
00867 
00868   The priority of a task that 'takes' a mutex can potentially be raised if another task of higher priority attempts 
00869   to obtain the same mutex. The task that owns the mutex 'inherits' the priority of the task attempting to 'take' the same mutex. 
00870   This means the mutex must always be 'given' back - otherwise the higher priority task will never be able to obtain the mutex, 
00871   and the lower priority task will never 'disinherit' the priority.
00872   
00873   More info at http://www.freertos.org - much documentation here used from the FreeRTOS doc by Richard Barry.
00874 * \ingroup RTOS
00875 * @{
00876 */
00877 
00878 /** 
00879   Create a semaphore. 
00880   @return A pointer to the newly created semaphore, or NULL on failure.
00881   
00882   \par Example
00883   \code
00884   void* mySemaphore = SemaphoreCreate( );
00885   if( mySemaphore != NULL )
00886   {
00887     // The semaphore was created successfully and can now be used.
00888   }
00889   \endcode
00890 */
00891 void* SemaphoreCreate( )
00892 {
00893   void *sem;
00894   vSemaphoreCreateBinary( sem );
00895   return sem;
00896 }
00897 
00898 #if ( configUSE_MUTEXES == 1 )
00899 void* MutexCreate( )
00900 {
00901   return xQueueCreateMutex( );
00902 }
00903 #endif
00904 
00905 /** 
00906   Obtain a semaphore. 
00907   The semaphore must have first been created with SemaphoreCreate( ).
00908   @param semaphore The semaphore to take.
00909   @param blockTime The time, in milliseconds, to wait for the semaphore to become available.
00910   @return 1 if the semaphore was obtained. 0 if blockTime expired without the semaphore becoming available.
00911   @see SemaphoreCreate( ), SemaphoreGive( )
00912   
00913   \par Example
00914   \code
00915   void* mySemaphore;
00916   SemaphoreCreate( mySemaphore );
00917   if( SemaphoreTake( mySemaphore, 100 ) ) // wait 100 milliseconds on this semaphore
00918   {
00919     // now access the protected resources
00920   }
00921   \endcode
00922 */
00923 int SemaphoreTake( void* semaphore, int blockTime )
00924 {
00925   return xSemaphoreTake( semaphore, blockTime / portTICK_RATE_MS );
00926 }
00927 
00928 /** 
00929   Release a semaphore. 
00930   This must not be used from an ISR. See SemaphoreGiveFromISR( ) for an alternative which can be used from an ISR.
00931   @param semaphore The semaphore to release.
00932   @return 1 if the semaphore was released. 0 if an error occurred. Semaphores are implemented using queues. 
00933   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.
00934   @see SemaphoreCreate( ), SemaphoreTake( )
00935   
00936   \par Example
00937   \code
00938   void* mySemaphore;
00939   SemaphoreCreate( mySemaphore );
00940   if( SemaphoreTake( mySemaphore, 1000 ) ) // wait 1000 milliseconds on this semaphore
00941   {
00942     // access the protected resources
00943     
00944     // then release the semaphore
00945     if( !SemaphoreGive( mySemaphore ) )
00946       // then handle the error here
00947   }
00948   \endcode
00949 */
00950 int SemaphoreGive( void* semaphore )
00951 {
00952   return xSemaphoreGive( semaphore );
00953 }
00954 
00955 /** 
00956   Release a semaphore from within an ISR. 
00957   See SemaphoreGive( ) for an alternative which can be used when not in an ISR.
00958   @param semaphore The semaphore to release.
00959   @param taskWoken This is included so an ISR can make multiple calls to SemaphoreGiveFromISR() from a single interrupt. 
00960   The first call should always pass in 0. Subsequent calls should pass in the value returned from the previous call.  
00961   @return 1 if the semaphore was released. 0 if an error occurred. Semaphores are implemented using queues. 
00962   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.
00963   
00964   \par Example
00965   \code
00966   void* mySemaphore;
00967   SemaphoreCreate( mySemaphore );
00968   void TimerISR( )
00969   {
00970     static int taskWoken = 0;
00971     taskWoken = SemaphoreGiveFromISR( mySemaphore, taskWoken );
00972     // If taskWoken was set to true you may want to yield (force a switch)
00973     // here.
00974   }
00975   \endcode
00976 */
00977 int SemaphoreGiveFromISR( void* semaphore, int taskWoken )
00978 {
00979   return xSemaphoreGiveFromISR( semaphore, taskWoken );
00980 }
00981 
00982 /** @}
00983 */
00984 
00985 void* TaskGetNext_internal( void* task )
00986 {
00987   int currentID;
00988   int lowID = 1024; // some large number that will be greater than the number of tasks...
00989   int highID = 1024;
00990   void* lowTask = NULL;
00991   void* highTask = NULL;
00992   void* tcb = NULL;
00993   unsigned portBASE_TYPE uxQueue = TaskGetTopPriorityUsed( ) + 1;
00994 
00995   if( task == NULL )
00996     currentID = 1;
00997   else
00998     currentID = TaskGetIDNumber( task );
00999 
01000   // look through all the possible lists of tasks
01001     do
01002     {
01003       uxQueue--;
01004       if( !listLIST_IS_EMPTY( GetReadyTaskByPriority( uxQueue ) ) )
01005       {
01006         tcb = iterateForNextTask( &lowTask, &lowID, &highTask, &highID, currentID, GetReadyTaskByPriority( uxQueue ) );
01007         if( tcb != NULL )
01008           return tcb;
01009       }   
01010     }while( uxQueue > ( unsigned portSHORT ) tskIDLE_PRIORITY );
01011 
01012     // check the list of delayed tasks
01013     if( !listLIST_IS_EMPTY( GetDelayedTaskList( ) ) )
01014     {
01015       tcb = iterateForNextTask( &lowTask, &lowID, &highTask, &highID, currentID, GetDelayedTaskList( ) );
01016       if( tcb != NULL )
01017         return tcb;
01018     }
01019     // check the list of overflow delayed tasks
01020     if( !listLIST_IS_EMPTY( GetOverflowDelayedTaskList( ) ) )
01021     {
01022       tcb = iterateForNextTask( &lowTask, &lowID, &highTask, &highID, currentID, GetOverflowDelayedTaskList( ) );
01023       if( tcb != NULL )
01024         return tcb;
01025     }
01026     // check the list of tasks about to die
01027     if( !listLIST_IS_EMPTY( GetListOfTasksWaitingTermination( ) ) )
01028     {
01029       tcb = iterateForNextTask( &lowTask, &lowID, &highTask, &highID, currentID, GetListOfTasksWaitingTermination( ) );
01030       if( tcb != NULL )
01031         return tcb;
01032     }
01033     // check the list of suspended tasks
01034     if( !listLIST_IS_EMPTY( GetSuspendedTaskList( ) ) )
01035       tcb = iterateForNextTask( &lowTask, &lowID, &highTask, &highID, currentID, GetSuspendedTaskList( ) );
01036 
01037     
01038   if( highTask )
01039     return highTask;
01040   else
01041     return lowTask;
01042 }
01043 
01044 // one function to search either by name or ID
01045 // pass in a garbage value for the parameter you're not interested in
01046 void* findTask( char *taskName, int taskID )
01047 {
01048   bool byName;
01049   if( taskName == NULL && taskID > 0 )
01050     byName = false;
01051   if( taskName != NULL && taskID < 0 )
01052     byName = true;
01053 
01054   unsigned portBASE_TYPE uxQueue = TaskGetTopPriorityUsed( ) + 1;
01055   void *tcb = NULL;
01056 
01057   // look through all the possible lists of tasks
01058     do
01059     {
01060       uxQueue--;
01061       if( !listLIST_IS_EMPTY( GetReadyTaskByPriority( uxQueue ) ) )
01062       {
01063         if( byName )
01064           tcb = iterateByName( taskName, GetReadyTaskByPriority( uxQueue ) );
01065         else
01066           tcb = iterateByID( taskID, GetReadyTaskByPriority( uxQueue ) );
01067 
01068         if( tcb != NULL )
01069           return tcb;
01070       }   
01071     }while( uxQueue > ( unsigned portSHORT ) tskIDLE_PRIORITY );
01072 
01073     // check the list of delayed tasks
01074     if( !listLIST_IS_EMPTY( GetDelayedTaskList( ) ) )
01075     {
01076       if( byName)
01077         tcb = iterateByName( taskName, GetDelayedTaskList( ) );
01078       else
01079         tcb = iterateByID( taskID, GetDelayedTaskList( ) );
01080 
01081       if( tcb != NULL )
01082         return tcb;
01083     }
01084     // check the list of overflow delayed tasks
01085     if( !listLIST_IS_EMPTY( GetOverflowDelayedTaskList( ) ) )
01086     {
01087       if( byName )
01088         tcb = iterateByName( taskName, GetOverflowDelayedTaskList( ) );
01089       else
01090         tcb = iterateByID( taskID, GetOverflowDelayedTaskList( ) );
01091       if( tcb != NULL )
01092         return tcb;
01093     }
01094     // check the list of tasks about to die
01095     if( !listLIST_IS_EMPTY( GetListOfTasksWaitingTermination( ) ) )
01096     {
01097       if( byName )
01098         tcb = iterateByName( taskName, GetListOfTasksWaitingTermination( ) );
01099       else
01100         tcb = iterateByID( taskID, GetListOfTasksWaitingTermination( ) );
01101 
01102       if( tcb != NULL )
01103         return tcb;
01104     }
01105     // check the list of suspended tasks
01106     if( !listLIST_IS_EMPTY( GetSuspendedTaskList( ) ) )
01107     {
01108       if( byName )
01109         tcb = iterateByName( taskName, GetSuspendedTaskList( ) );
01110       else
01111         tcb = iterateByID( taskID, GetSuspendedTaskList( ) );
01112     }
01113     return tcb;
01114 }
01115 
01116 void* iterateByID( int id, xList* pxList )
01117 {
01118   void *pxNextTCB, *pxFirstTCB;
01119   listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList );
01120   do
01121   {
01122     listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList );
01123     if( TaskGetIDNumber( pxNextTCB ) == id )
01124       return pxNextTCB;
01125     
01126   } while( pxNextTCB != pxFirstTCB );
01127   // if we get down here, we didn't find it.
01128   return NULL;
01129 }
01130 
01131 void* iterateByName( char* taskName, xList* pxList )
01132 {
01133   void *pxNextTCB, *pxFirstTCB;
01134   listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList );
01135   do
01136   {
01137     listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList );
01138     if( strcmp( TaskGetName( pxNextTCB ), taskName ) == 0 )
01139       return pxNextTCB;
01140     
01141   } while( pxNextTCB != pxFirstTCB );
01142   // if we get down here, we didn't find it.
01143   return NULL;
01144 }
01145 
01146 void* iterateForNextTask( void** lowTask, int* lowID, void** highTask, int* highID, int currentID, xList* pxList )
01147 {
01148   void *pxNextTCB, *pxFirstTCB;
01149   listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList );
01150   do
01151   {
01152     listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList );
01153     int id = TaskGetIDNumber( pxNextTCB );
01154     if( id == (currentID + 1) ) // if it's the ID we're looking for plus one, we got it and we're out.
01155       return pxNextTCB;
01156     if( id > currentID && id < *highID )
01157     {
01158       *highID = id;
01159       *highTask = pxNextTCB;
01160     }
01161     if( id < currentID && id < *lowID && id != 1 ) // we don't want id 1 since that's IDLE and there's no real task there.
01162     {
01163       *lowID = id;
01164       *lowTask = pxNextTCB;
01165     }
01166   } while( pxNextTCB != pxFirstTCB );
01167   // if we get down here, we didn't find it.
01168   return NULL;
01169 }
01170 
01171 
01172 
01173 
01174 

The Make Controller Kit is an open source project maintained by MakingThings.
MakingThings code is released under the Apache 2.0 license.
Bug tracker, development wiki and status can be found at http://dev.makingthings.com.
This document was last updated on 18 May 2009.