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.