]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/MB96350_Softune_Dice_Kit/DiceTask.c
5cdebbe1a28e13102357ea21842ff4f71c49cb4a
[freertos] / FreeRTOS / Demo / MB96350_Softune_Dice_Kit / DiceTask.c
1 /*\r
2  * FreeRTOS Kernel V10.2.0\r
3  * Copyright (C) 2019 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  *\r
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
6  * this software and associated documentation files (the "Software"), to deal in\r
7  * the Software without restriction, including without limitation the rights to\r
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
9  * the Software, and to permit persons to whom the Software is furnished to do so,\r
10  * subject to the following conditions:\r
11  *\r
12  * The above copyright notice and this permission notice shall be included in all\r
13  * copies or substantial portions of the Software.\r
14  *\r
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
17  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
21  *\r
22  * http://www.FreeRTOS.org\r
23  * http://aws.amazon.com/freertos\r
24  *\r
25  * 1 tab == 4 spaces!\r
26  */\r
27 \r
28 \r
29 /* \r
30  * Defines the 'dice' tasks as described at the top of main.c\r
31  */\r
32 \r
33 \r
34 /* Kernel includes. */\r
35 #include "FreeRTOS.h"\r
36 #include "task.h"\r
37 #include "semphr.h"\r
38 \r
39 /* Delays used within the dice functionality.  All delays are defined in milliseconds. */\r
40 #define diceDELAY_BETWEEN_RANDOM_NUMBERS_ms             ( 20 / portTICK_PERIOD_MS )\r
41 #define diceSHAKE_TIME                                                  ( ( 2000 / portTICK_PERIOD_MS ) / diceDELAY_BETWEEN_RANDOM_NUMBERS_ms )\r
42 #define diceSHORT_PAUSE_BEFORE_SHAKE                    ( 250 / portTICK_PERIOD_MS )\r
43 #define diceDELAY_WHILE_DISPLAYING_RESULT               ( 5000 / portTICK_PERIOD_MS )\r
44 \r
45 /* Macro to access the display ports. */\r
46 #define dice7SEG_Value( x )             ( *( pucDisplayOutput[ x ] ) )\r
47 \r
48 /* Checks the semaphore use to communicate button push events.  A block time\r
49 can be specified - this is the time to wait for a button push to occur should\r
50 one have not already occurred. */\r
51 #define prvButtonHit( ucIndex, xTicksToWait ) xSemaphoreTake( xSemaphores[ ucIndex ], xTicksToWait )\r
52 \r
53 /* Defines the outputs required for each digit on the display. */\r
54 static const char cDisplaySegments[ 2 ][ 11 ] =\r
55 {\r
56         { 0x48, 0xeb, 0x8c, 0x89, 0x2b, 0x19, 0x18, 0xcb, 0x08, 0x09, 0xf7 }, /* Left display. */\r
57         { 0xa0, 0xf3, 0xc4, 0xc1, 0x93, 0x89, 0x88, 0xe3, 0x80, 0x81, 0x7f }  /* Right display. */\r
58 };\r
59 \r
60 /* The semaphores used to communicate button push events between the button\r
61 input interrupt handlers and the dice tasks.  Two dice tasks are created so two\r
62 semaphores are required. */\r
63 static SemaphoreHandle_t xSemaphores[ 2 ] = { 0 };\r
64 \r
65 /* Defines the ports used to write to the display.  This variable is defined in\r
66 partest.c, which contains the LED set/clear/toggle functions. */\r
67 extern volatile unsigned char *pucDisplayOutput[ 2 ];\r
68 \r
69 /*-----------------------------------------------------------*/\r
70 \r
71 /* \r
72  * Defines the 'dice' tasks as described at the top of main.c\r
73  */\r
74 void vDiceTask( void *pvParameters )\r
75 {\r
76 unsigned char ucDiceValue, ucIndex;\r
77 unsigned long ulDiceRunTime;\r
78 extern void vSuspendFlashTasks( unsigned char ucIndex, short sSuspendTasks );\r
79 \r
80 \r
81 \r
82         /* Two instances of this task are created so the task parameter is used\r
83         to pass in a constant that indicates whether this task is controlling\r
84         the left side or right side display.  The constant is used as an index\r
85         into the arrays defined at file scope within this file. */\r
86         ucIndex = ( unsigned char ) pvParameters;\r
87         \r
88         /* A binary semaphore is used to signal button push events.  Create the\r
89         semaphore before it is used. */\r
90         vSemaphoreCreateBinary( xSemaphores[ ucIndex ] );\r
91 \r
92         /* Make sure the semaphore starts in the wanted state - no button pushes \r
93         pending. This call will just clear any button pushes that are latched.\r
94         Passing in 0 as the block time means the call will not wait for any further\r
95         button pushes but instead return immediately. */\r
96         prvButtonHit( ucIndex, 0 );\r
97 \r
98         /* Seed the random number generator. */\r
99         srand( ( unsigned char ) diceSHAKE_TIME );\r
100 \r
101 \r
102 \r
103 \r
104         /* Start the task proper.  A loop will be performed each time a button is\r
105         pushed.  The task will remain in the blocked state (sleeping) until a \r
106         button is pushed. */\r
107         for( ;; )\r
108         {\r
109                 /* Wait for a button push.  This task will enter the Blocked state\r
110                 (will not run again) until after a button has been pushed. */\r
111                 prvButtonHit( ucIndex, portMAX_DELAY );\r
112                 \r
113                 /* The next line will only execute after a button has been pushed -\r
114                 initialise the variable used to control the time the dice is shaken\r
115                 for. */\r
116                 ulDiceRunTime = diceSHAKE_TIME;                         \r
117 \r
118                 /* Suspend the flash tasks so this task has exclusive access to the\r
119                 display. */\r
120                 vSuspendFlashTasks( ucIndex, pdTRUE );\r
121 \r
122                 /* Clear the display and pause for a short time, before starting to\r
123                 shake. */\r
124                 *pucDisplayOutput[ ucIndex ] = 0xff;\r
125                 vTaskDelay( diceSHORT_PAUSE_BEFORE_SHAKE );\r
126 \r
127                 /* Keep generating and displaying random numbers until the shake time\r
128                 expires. */\r
129                 while( ulDiceRunTime > 0 )\r
130                 {\r
131                         ulDiceRunTime--;\r
132 \r
133                         /* Generate and display a random number. */\r
134                         ucDiceValue = rand() % 6 + 1;\r
135                         dice7SEG_Value( ucIndex ) = ( dice7SEG_Value( ucIndex ) | 0xf7 ) & cDisplaySegments[ ucIndex ][ ucDiceValue ];\r
136 \r
137                         /* Block/sleep for a very short time before generating the next\r
138                         random number. */\r
139                         vTaskDelay( diceDELAY_BETWEEN_RANDOM_NUMBERS_ms );\r
140                 }\r
141 \r
142 \r
143 \r
144                 /* Clear any button pushes that are pending because a button bounced, or\r
145                 was pressed while the dice were shaking.  Again a block time of zero is \r
146                 used so the function does not wait for any pushes but instead returns\r
147                 immediately. */\r
148                 prvButtonHit( ucIndex, 0 );\r
149 \r
150                 /* Delay for a short while to display the dice shake result.  Use a queue\r
151                 peek here instead of a vTaskDelay() allows the delay to be interrupted by\r
152                 a button push.  If a button is pressed xQueuePeek() will return but the\r
153                 button push will remain pending to be read again at the top of this for\r
154                 loop.  It is safe to uses a queue function on a semaphore handle as\r
155                 semaphores are implemented as macros that uses queues, so the two are \r
156                 basically the same thing. */\r
157                 xQueuePeek( xSemaphores[ ucIndex ], NULL, diceDELAY_WHILE_DISPLAYING_RESULT );\r
158 \r
159                 /* Clear the display then resume the tasks or co-routines that were using\r
160                 the segments of the display. */\r
161                 *pucDisplayOutput[ ucIndex ] = 0xff;\r
162                 vSuspendFlashTasks( ucIndex, pdFALSE );\r
163         }\r
164 }\r
165 /*-----------------------------------------------------------*/\r
166 \r
167 /* Handler for the SW2 button push interrupt. */\r
168 __interrupt void vExternalInt8Handler( void )\r
169 {\r
170 short sHigherPriorityTaskWoken = pdFALSE;\r
171 \r
172         /* Reset the interrupt. */\r
173         EIRR1_ER8 = 0;\r
174 \r
175         /* Check the semaphore has been created before attempting to use it. */\r
176         if( xSemaphores[ configLEFT_DISPLAY ] != NULL )\r
177         {\r
178                 /* Send a message via the semaphore to the dice task that controls the\r
179                 left side display.  This will unblock the task if it is blocked waiting\r
180                 for a button push. */\r
181                 xSemaphoreGiveFromISR( xSemaphores[ configLEFT_DISPLAY ], &sHigherPriorityTaskWoken );\r
182         }\r
183 \r
184         /* If sending the semaphore unblocked a task, and the unblocked task has a\r
185         priority that is higher than the currently running task, then force a context\r
186         switch. */\r
187         if( sHigherPriorityTaskWoken != pdFALSE )\r
188         {\r
189                 portYIELD_FROM_ISR();\r
190         }\r
191 }\r
192 /*-----------------------------------------------------------*/\r
193 \r
194 /* As per vExternalInt8Handler(), but for SW3 and the right side display. */\r
195 __interrupt void vExternalInt9Handler( void )\r
196 {\r
197 short sHigherPriorityTaskWoken = pdFALSE;\r
198 \r
199         /* Reset the interrupt. */\r
200         EIRR1_ER9 = 0;\r
201 \r
202         if( xSemaphores[ configRIGHT_DISPLAY ] != NULL )\r
203         {\r
204                 xSemaphoreGiveFromISR( xSemaphores[ configRIGHT_DISPLAY ], &sHigherPriorityTaskWoken );\r
205         }\r
206 \r
207         if( sHigherPriorityTaskWoken != pdFALSE )\r
208         {\r
209                 portYIELD_FROM_ISR();\r
210         }\r
211 }\r
212 \r
213 \r
214 \r
215 \r
216 \r
217 \r
218 \r