]> git.sur5r.net Git - freertos/blob - Demo/Common/Minimal/crhook.c
First version under SVN is V4.0.1
[freertos] / Demo / Common / Minimal / crhook.c
1 /*\r
2         FreeRTOS V4.0.1 - Copyright (C) 2003-2006 Richard Barry.\r
3 \r
4         This file is part of the FreeRTOS distribution.\r
5 \r
6         FreeRTOS is free software; you can redistribute it and/or modify\r
7         it under the terms of the GNU General Public License as published by\r
8         the Free Software Foundation; either version 2 of the License, or\r
9         (at your option) any later version.\r
10 \r
11         FreeRTOS is distributed in the hope that it will be useful,\r
12         but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
14         GNU General Public License for more details.\r
15 \r
16         You should have received a copy of the GNU General Public License\r
17         along with FreeRTOS; if not, write to the Free Software\r
18         Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
19 \r
20         A special exception to the GPL can be applied should you wish to distribute\r
21         a combined work that includes FreeRTOS, without being obliged to provide\r
22         the source code for any proprietary components.  See the licensing section \r
23         of http://www.FreeRTOS.org for full details of how and when the exception\r
24         can be applied.\r
25 \r
26         ***************************************************************************\r
27         See http://www.FreeRTOS.org for documentation, latest information, license \r
28         and contact details.  Please ensure to read the configuration and relevant \r
29         port sections of the online documentation.\r
30         ***************************************************************************\r
31 */\r
32 \r
33 /*\r
34  * This demo file demonstrates how to send data between an ISR and a \r
35  * co-routine.  A tick hook function is used to periodically pass data between\r
36  * the RTOS tick and a set of 'hook' co-routines.\r
37  *\r
38  * hookNUM_HOOK_CO_ROUTINES co-routines are created.  Each co-routine blocks\r
39  * to wait for a character to be received on a queue from the tick ISR, checks\r
40  * to ensure the character received was that expected, then sends the number\r
41  * back to the tick ISR on a different queue.\r
42  * \r
43  * The tick ISR checks the numbers received back from the 'hook' co-routines \r
44  * matches the number previously sent.\r
45  *\r
46  * If at any time a queue function returns unexpectedly, or an incorrect value\r
47  * is received either by the tick hook or a co-routine then an error is \r
48  * latched.\r
49  *\r
50  * This demo relies on each 'hook' co-routine to execute between each \r
51  * hookTICK_CALLS_BEFORE_POST tick interrupts.  This and the heavy use of \r
52  * queues from within an interrupt may result in an error being detected on \r
53  * slower targets simply due to timing.\r
54  */\r
55 \r
56 /* Scheduler includes. */\r
57 #include "FreeRTOS.h"\r
58 #include "croutine.h"\r
59 #include "queue.h"\r
60 \r
61 /* Demo application includes. */\r
62 #include "crhook.h"\r
63 \r
64 /* The number of 'hook' co-routines that are to be created. */\r
65 #define hookNUM_HOOK_CO_ROUTINES        ( 4 )\r
66 \r
67 /* The number of times the tick hook should be called before a character is \r
68 posted to the 'hook' co-routines. */\r
69 #define hookTICK_CALLS_BEFORE_POST      ( 250 )\r
70 \r
71 /* There should never be more than one item in any queue at any time. */\r
72 #define hookHOOK_QUEUE_LENGTH           ( 1 )\r
73 \r
74 /* Don't block when initially posting to the queue. */\r
75 #define hookNO_BLOCK_TIME               ( 0 )\r
76 \r
77 /* The priority relative to other co-routines (rather than tasks) that the\r
78 'hook' co-routines should take. */\r
79 #define mainHOOK_CR_PRIORITY                    ( 1 )\r
80 /*-----------------------------------------------------------*/\r
81 \r
82 /*\r
83  * The co-routine function itself.\r
84  */\r
85 static void prvHookCoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex );\r
86 \r
87 \r
88 /*\r
89  * The tick hook function.  This receives a number from each 'hook' co-routine\r
90  * then sends a number to each co-routine.  An error is flagged if a send or \r
91  * receive fails, or an unexpected number is received.\r
92  */\r
93 void vApplicationTickHook( void );\r
94 \r
95 /*-----------------------------------------------------------*/\r
96 \r
97 /* Queues used to send data FROM a co-routine TO the tick hook function.\r
98 The hook functions received (Rx's) on these queues.  One queue per\r
99 'hook' co-routine. */\r
100 static xQueueHandle xHookRxQueues[ hookNUM_HOOK_CO_ROUTINES ];\r
101 \r
102 /* Queues used to send data FROM the tick hook TO a co-routine function.\r
103 The hood function transmits (Tx's) on these queues.  One queue per\r
104 'hook' co-routine. */\r
105 static xQueueHandle xHookTxQueues[ hookNUM_HOOK_CO_ROUTINES ];\r
106 \r
107 /* Set to true if an error is detected at any time. */\r
108 static portBASE_TYPE xCoRoutineErrorDetected = pdFALSE;\r
109 \r
110 /*-----------------------------------------------------------*/\r
111 \r
112 void vStartHookCoRoutines( void )\r
113 {\r
114 unsigned portBASE_TYPE uxIndex, uxValueToPost = 0;\r
115 \r
116         for( uxIndex = 0; uxIndex < hookNUM_HOOK_CO_ROUTINES; uxIndex++ )\r
117         {\r
118                 /* Create a queue to transmit to and receive from each 'hook' \r
119                 co-routine. */\r
120                 xHookRxQueues[ uxIndex ] = xQueueCreate( hookHOOK_QUEUE_LENGTH, sizeof( unsigned portBASE_TYPE ) );\r
121                 xHookTxQueues[ uxIndex ] = xQueueCreate( hookHOOK_QUEUE_LENGTH, sizeof( unsigned portBASE_TYPE ) );\r
122 \r
123                 /* To start things off the tick hook function expects the queue it \r
124                 uses to receive data to contain a value.  */\r
125                 xQueueSend( xHookRxQueues[ uxIndex ], &uxValueToPost, hookNO_BLOCK_TIME );\r
126 \r
127                 /* Create the 'hook' co-routine itself. */\r
128                 xCoRoutineCreate( prvHookCoRoutine, mainHOOK_CR_PRIORITY, uxIndex );\r
129         }\r
130 }\r
131 /*-----------------------------------------------------------*/\r
132 \r
133 static unsigned portBASE_TYPE uxCallCounter = 0, uxNumberToPost = 0;\r
134 void vApplicationTickHook( void )\r
135 {\r
136 unsigned portBASE_TYPE uxReceivedNumber;\r
137 signed portBASE_TYPE xIndex, xCoRoutineWoken;\r
138 \r
139         /* Is it time to talk to the 'hook' co-routines again? */\r
140         uxCallCounter++;\r
141         if( uxCallCounter >= hookTICK_CALLS_BEFORE_POST )\r
142         {\r
143                 uxCallCounter = 0;\r
144 \r
145                 for( xIndex = 0; xIndex < hookNUM_HOOK_CO_ROUTINES; xIndex++ )\r
146                 {\r
147                         xCoRoutineWoken = pdFALSE;\r
148                         if( crQUEUE_RECEIVE_FROM_ISR( xHookRxQueues[ xIndex ], &uxReceivedNumber, &xCoRoutineWoken ) != pdPASS )\r
149                         {\r
150                                 /* There is no reason why we would not expect the queue to \r
151                                 contain a value. */\r
152                                 xCoRoutineErrorDetected = pdTRUE;\r
153                         }\r
154                         else\r
155                         {\r
156                                 /* Each queue used to receive data from the 'hook' co-routines \r
157                                 should contain the number we last posted to the same co-routine. */\r
158                                 if( uxReceivedNumber != uxNumberToPost )\r
159                                 {\r
160                                         xCoRoutineErrorDetected = pdTRUE;\r
161                                 }\r
162 \r
163                                 /* Nothing should be blocked waiting to post to the queue. */\r
164                                 if( xCoRoutineWoken != pdFALSE )\r
165                                 {\r
166                                         xCoRoutineErrorDetected = pdTRUE;\r
167                                 }\r
168                         }\r
169                 }\r
170 \r
171                 /* Start the next cycle by posting the next number onto each Tx queue. */\r
172                 uxNumberToPost++;\r
173 \r
174                 for( xIndex = 0; xIndex < hookNUM_HOOK_CO_ROUTINES; xIndex++ )\r
175                 {\r
176                         if( crQUEUE_SEND_FROM_ISR( xHookTxQueues[ xIndex ], &uxNumberToPost, pdFALSE ) != pdTRUE )\r
177                         {\r
178                                 /* Posting to the queue should have woken the co-routine that \r
179                                 was blocked on the queue. */\r
180                                 xCoRoutineErrorDetected = pdTRUE;\r
181                         }\r
182                 }\r
183         }\r
184 }\r
185 /*-----------------------------------------------------------*/\r
186 \r
187 static void prvHookCoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )\r
188 {\r
189 static unsigned portBASE_TYPE uxReceivedValue[ hookNUM_HOOK_CO_ROUTINES ];\r
190 portBASE_TYPE xResult;\r
191 \r
192         /* Each co-routine MUST start with a call to crSTART(); */\r
193         crSTART( xHandle );\r
194 \r
195         for( ;; )\r
196         {\r
197                 /* Wait to receive a value from the tick hook. */\r
198                 xResult = pdFAIL;\r
199                 crQUEUE_RECEIVE( xHandle, xHookTxQueues[ uxIndex ], &( uxReceivedValue[ uxIndex ] ), portMAX_DELAY, &xResult );\r
200 \r
201                 /* There is no reason why we should not have received something on\r
202                 the queue. */\r
203                 if( xResult != pdPASS )\r
204                 {\r
205                         xCoRoutineErrorDetected = pdTRUE;\r
206                 }\r
207 \r
208                 /* Send the same number back to the idle hook so it can verify it. */\r
209                 xResult = pdFAIL;\r
210                 crQUEUE_SEND( xHandle, xHookRxQueues[ uxIndex ], &( uxReceivedValue[ uxIndex ] ), hookNO_BLOCK_TIME, &xResult );\r
211                 if( xResult != pdPASS )\r
212                 {\r
213                         /* There is no reason why we should not have been able to post to \r
214                         the queue. */\r
215                         xCoRoutineErrorDetected = pdTRUE;\r
216                 }\r
217         }\r
218 \r
219         /* Each co-routine MUST end with a call to crEND(). */\r
220         crEND();\r
221 }\r
222 /*-----------------------------------------------------------*/\r
223 \r
224 portBASE_TYPE xAreHookCoRoutinesStillRunning( void )\r
225 {\r
226         if( xCoRoutineErrorDetected )\r
227         {\r
228                 return pdFALSE;\r
229         }\r
230         else\r
231         {\r
232                 return pdTRUE;\r
233         }\r
234 }\r
235 \r
236 \r
237 \r