- 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.