Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: LCD_DISCO_F429ZI mbed TS_DISCO_F429ZI mbed-os BSP_DISCO_F429ZI
SecurityUnlockDemo-Animation.cpp
00001 00002 // ---------------------------------------------------------------------- 00003 // SecurityUnlockDemo-Animation.cpp 00004 // 00005 // Fredric L. Rice, June 2019 00006 // 00007 // This module draws a mushroom on the display and then animates it as 00008 // the mushroom moves around "randomly." Every 10 moves or so it will 00009 // "teleport" to a "random" place on the screen. 00010 // 00011 // The random number generator provided by mbed is not very good 00012 // so we attempt to use the analog inputs on PF_3, PF_4, PF_5 to help 00013 // drive some randomness. 00014 // 00015 // Conceivably more than one sprite could be animated merely by 00016 // making some of the data elements arrays -- and of course using C++ 00017 // to instantiate objects and then animating them is the correct way 00018 // to do such things. This is a concept demonstration projjct, so we 00019 // do not expect to make a proper class and allow any number of them 00020 // to be instantiated and get automated. 00021 // 00022 // That would be neat but that's something for another project. 00023 // 00024 // ---------------------------------------------------------------------- 00025 00026 #include "mbed.h" // The mbed operating system 00027 #include "LCD_DISCO_F429ZI.h" // For controlling the LCD 00028 #include "TS_DISCO_F429ZI.h" // For controlling the touch screen 00029 #include "SecurityUnlockDemo-Main.h" // For the main module's prototypes 00030 #include "SecurityUnlockDemo-Animation.h" // Always include our own header 00031 00032 // ---------------------------------------------------------------------- 00033 // Describe data which is defined externally that we may access 00034 // 00035 // ---------------------------------------------------------------------- 00036 00037 // We may be accessing the LCD 00038 extern LCD_DISCO_F429ZI st_lcd; 00039 00040 // We may be accessing the touch screen 00041 extern TS_DISCO_F429ZI st_touchScreen; 00042 00043 // ---------------------------------------------------------------------- 00044 // Define local data storage 00045 // 00046 // ---------------------------------------------------------------------- 00047 00048 // We define a "sprite" like entity consisting of a bit map showing 00049 // the colors of pixes that will display a mushroom which we will 00050 // move around the screen. The sprite consists of 22 pixes across 00051 // and 17 pixels down so it's a small graphic. The letters describe 00052 // the color of each pixel. 00053 static char * pau8_mushroomMap[SPRITE_HEIGHT_IN_PIXELS] = 00054 { // 1234567890123456789012 00055 "wwwwwwwwwbbbbbbwwwwwww", // 1 00056 "wwwwwwwbbbwggwbbbwwwww", // 2 00057 "wwwwwwbbwwggwwwbbwwwww", // 3 00058 "wwwwwbbgwwggggwwbbwwww", // 4 00059 "wwwwwbwgggggggggggbwww", // 5 00060 "wwwwbbwwggwwwwggwwbbww", // 6 00061 "wwwwbwwwgwwwwwwgwwwbww", // 7 00062 "wwwwbwwwgwwwwwwgwwwbww", // 8 00063 "wwwwbwwggwwwwwwwggwwbw", // 9 00064 "wwwwbwwggwwwwwwwggwwbw", // 10 00065 "wwwwbgggggwwwwwgggggbw", // 11 00066 "wwwwbggbbbbbbbbbbbggbw", // 12 00067 "wwwwbbbbwwbwwbwwbbbbbw", // 13 00068 "wwwwwwbwwwbwwbwwwwbwww", // 14 00069 "wwwwwwbwwwwwwwwwwwbwww", // 15 00070 "wwwwwwbbwwwwwwwwwbbwww", // 16 00071 "wwwwwwwbbbbbbbbbbbwwww" 00072 } ; 00073 00074 // There are 8 different directions that this animation supports, 00075 // the coordinate offsets to add/subtract from the current pixel 00076 // position depending upon the direction is mapped here. 00077 // 00078 // Directions: 00079 // 1 2 3 Left up, Up, Right Up 00080 // 4 6 Left, N/A, Right 00081 // 7 8 9 Right Down, Down, Right Down 00082 static int8_t i8_movementMatrix[3][6] = 00083 { 00084 -1, -1, -1, 0, -1, 1, 00085 -1, 0, 0, 0, 1, 0, 00086 -1, 1, 0, 1, 1, 1 00087 } ; 00088 00089 // We maintain local data indicating where the sprite was last drawn 00090 static uint16_t u16_spriteCurrentX; 00091 static uint16_t u16_spriteCurrentY; 00092 static uint8_t u8_spriteCurrentDirection; 00093 00094 // When we are first asked to start animation, we launch 00095 // a thread to continue the animation forever 00096 static Thread st_animationThread; 00097 00098 // To know whether animation is running, we maintain this boolean 00099 static bool b_animationThreadRunning; 00100 00101 // After every 10 movements along a given direction, rather than 00102 // pick a direction and then move toward it we will "teleport" 00103 // the sprite to a "random" location on the screen and maintain 00104 // the direction -- unless we're up against a boundary, then a 00105 // new direction will be selected 00106 static uint8_t u8_teleportCounter; 00107 00108 // When we teleport, we display a message indicating that/ 00109 // After about 1 second we want to remove that message from 00110 // the screen so we maintain this count down timer 00111 static uint16_t u16_teleportMessageRemovalCountDown; 00112 00113 // In an effort to assist the random number generator we will read 00114 // vaues from some of the analog inputs which should be near zero 00115 // but perhaps not entirely 00116 static AnalogIn st_analog1(PF_3); 00117 static AnalogIn st_analog2(PF_4); 00118 static AnalogIn st_analog3(PF_5); 00119 00120 // ---------------------------------------------------------------------- 00121 // AnimationDrawSpriteAtThisLocation() 00122 // 00123 // This function will draw or erase the sprite at the X and Y 00124 // coordinate position passed to it, or it will erase the sprite 00125 // depending upon the argument passed to it. 00126 // 00127 // The colors that are supported are described in the sprite's 00128 // bit mapping. 00129 // 00130 // Note that we do not attempt to store the original pixel's color 00131 // value before writing it with a new value, so we can not restore 00132 // the pixel once the sprite moves off of it. This is a stark 00133 // divergence from real spite automation which restores the original, 00134 // but we are demo code, not a real project, so we don't even try. 00135 // 00136 // ---------------------------------------------------------------------- 00137 static void AnimationDrawOrEraseSpriteAtThisLocation(uint16_t u16_thisX, uint16_t u16_thisY, bool b_drawSprite) 00138 { 00139 uint8_t u8_lineCount = 0; 00140 uint16_t u16_currentX = u16_thisX; 00141 uint16_t u16_currentY = u16_thisY; 00142 uint8_t u8_currentPixel = 0; 00143 uint32_t u32thisColor = LCD_COLOR_BLUE; 00144 00145 // Record where we are placing the sprite this time 00146 u16_spriteCurrentX = u16_thisX; 00147 u16_spriteCurrentY = u16_thisY; 00148 00149 // Place the sprite on the screen pixel by pixel 00150 for (u8_lineCount = 0; u8_lineCount < SPRITE_HEIGHT_IN_PIXELS; u8_lineCount++) 00151 { 00152 for (u8_currentPixel = 0; 00153 u8_currentPixel < strlen(pau8_mushroomMap[u8_lineCount]); 00154 u8_currentPixel++) 00155 { 00156 // Are we drawing the sprite rather than erasing it? 00157 if (true == b_drawSprite) 00158 { 00159 // Find out what the color of this pixel should be 00160 switch(pau8_mushroomMap[u8_lineCount][u8_currentPixel]) 00161 { 00162 case 'w': 00163 case 'W': 00164 { 00165 u32thisColor = LCD_COLOR_WHITE; 00166 break; 00167 } 00168 case 'b': 00169 case 'B': 00170 { 00171 u32thisColor = LCD_COLOR_BLUE; 00172 break; 00173 } 00174 case 'g': 00175 case 'G': 00176 { 00177 u32thisColor = LCD_COLOR_GREEN; 00178 break; 00179 } 00180 case 'r': 00181 case 'R': 00182 { 00183 u32thisColor = LCD_COLOR_RED; 00184 break; 00185 } 00186 case 'k': 00187 case 'K': 00188 { 00189 u32thisColor = LCD_COLOR_BLACK; 00190 break; 00191 } 00192 case 'y': 00193 case 'Y': 00194 { 00195 u32thisColor = LCD_COLOR_YELLOW; 00196 break; 00197 } 00198 } 00199 } 00200 else 00201 { 00202 // Since we are erasing the sprite, the color is white 00203 u32thisColor = LCD_COLOR_WHITE; 00204 } 00205 00206 // Place the pixel on the screen with the correct color 00207 st_lcd.DrawPixel(u16_currentX, u16_currentY, u32thisColor); 00208 00209 // Next pixel 00210 u16_currentX++; 00211 } 00212 00213 // Start working on the next line 00214 u16_currentY++; 00215 00216 u16_currentX = u16_thisX; 00217 } 00218 } 00219 00220 // ---------------------------------------------------------------------- 00221 // AnimationGetANewDirectionToTravel() 00222 // 00223 // We acquire a "random" direction to travel. Note that the mbed random 00224 // number generator is highly flawed, it produces the same numbers 00225 // despite how hard one seeds it. We could utilize an ununsed analog 00226 // input and use the noise that might be found there, but for purposes 00227 // of demonstrating animation, we'll just use what mben provided. 00228 // 00229 // ---------------------------------------------------------------------- 00230 static uint8_t AnimationGetANewDirectionToTravel(void) 00231 { 00232 uint8_t u8_newDirection = 5; 00233 00234 // Keep looking for a "random" number until one is valid 00235 while(5 == u8_newDirection || 00236 u8_newDirection < SPRITE_DIRECTION_LEFT_UP || 00237 u8_newDirection > SPRITE_DIRECTION_RIGHT_DOWN) 00238 { 00239 // Get a new direction to tavel 00240 u8_newDirection = (rand() % SPRITE_DIRECTION_RIGHT_DOWN); 00241 } 00242 00243 // Return the new direction of travel 00244 return u8_newDirection; 00245 } 00246 00247 // ---------------------------------------------------------------------- 00248 // AnimationInit() 00249 // 00250 // Initializes any locally-held data and performs all other start-up 00251 // functionality required for the animated functionality, if any. 00252 // 00253 // ---------------------------------------------------------------------- 00254 void AnimationInit(void) 00255 { 00256 // Initialize locally-held data 00257 u16_spriteCurrentX = 0; 00258 u16_spriteCurrentY = 0; 00259 b_animationThreadRunning = false; 00260 u8_spriteCurrentDirection = AnimationGetANewDirectionToTravel(); 00261 u8_teleportCounter = 0; 00262 u16_teleportMessageRemovalCountDown = 0; 00263 } 00264 00265 // ---------------------------------------------------------------------- 00266 // AnimationMoveSprite() 00267 // 00268 // This function is the one that performs the actual move by 1 pixel 00269 // of the sprite. The sprite is erased from the screen and then the 00270 // new location is computed. If that places the sprite outside of the 00271 // boundaries, a new direction is selected and then the proposed 00272 // new location is selected. 00273 // 00274 // Once there is a new sprite location proposed, it gets re-drawn. 00275 // 00276 // ---------------------------------------------------------------------- 00277 static void AnimationMoveSprite(void) 00278 { 00279 uint16_t u16_proposedX = u16_spriteCurrentX; 00280 uint16_t u16_proposedY = u16_spriteCurrentY; 00281 int8_t i8_proposedOffsetX = 0; 00282 int8_t i8_proposedOffsetY = 0; 00283 bool b_haveNewLocation = false; 00284 00285 // Did we teleport and display a message indicating that we did? 00286 if (u16_teleportMessageRemovalCountDown > 0) 00287 { 00288 // Yes, so count down the timer / counter and see if it expired 00289 if (0 == --u16_teleportMessageRemovalCountDown) 00290 { 00291 // Clear the message line 00292 st_lcd.ClearStringLine(4); 00293 } 00294 } 00295 00296 // Erase the entire sprite from where it currently exists 00297 AnimationDrawOrEraseSpriteAtThisLocation(u16_spriteCurrentX, u16_spriteCurrentY, false); 00298 00299 // We loop until we have a new location to move the sprite to. 00300 // We look for a valid location more than once since we may 00301 // run in to a boundary and have to change our direction of travel 00302 while(false == b_haveNewLocation) 00303 { 00304 // Compute the new location of the sprite 00305 switch(u8_spriteCurrentDirection) 00306 { 00307 // Extract the proposed offsets for X and Y 00308 case SPRITE_DIRECTION_LEFT_UP: 00309 { 00310 i8_proposedOffsetX = i8_movementMatrix[0][0]; 00311 i8_proposedOffsetY = i8_movementMatrix[0][1]; 00312 break; 00313 } 00314 case SPRITE_DIRECTION_UP: 00315 { 00316 i8_proposedOffsetX = i8_movementMatrix[0][2]; 00317 i8_proposedOffsetY = i8_movementMatrix[0][3]; 00318 break; 00319 } 00320 case SPRITE_DIRECTION_RIGHT_UP: 00321 { 00322 i8_proposedOffsetX = i8_movementMatrix[0][4]; 00323 i8_proposedOffsetY = i8_movementMatrix[0][5]; 00324 break; 00325 } 00326 case SPRITE_DIRECTION_LEFT: 00327 { 00328 i8_proposedOffsetX = i8_movementMatrix[1][0]; 00329 i8_proposedOffsetY = i8_movementMatrix[1][1]; 00330 break; 00331 } 00332 case SPRITE_DIRECTION_RIGHT: 00333 { 00334 i8_proposedOffsetX = i8_movementMatrix[1][4]; 00335 i8_proposedOffsetY = i8_movementMatrix[1][5]; 00336 break; 00337 } 00338 default: 00339 case SPRITE_DIRECTION_NOT_VALID: 00340 { 00341 // We should never be able to get here 00342 return; 00343 } 00344 case SPRITE_DIRECTION_LEFT_DOWN: 00345 { 00346 i8_proposedOffsetX = i8_movementMatrix[2][0]; 00347 i8_proposedOffsetY = i8_movementMatrix[2][1]; 00348 break; 00349 } 00350 case SPRITE_DIRECTION_DOWN: 00351 { 00352 i8_proposedOffsetX = i8_movementMatrix[2][2]; 00353 i8_proposedOffsetY = i8_movementMatrix[2][3]; 00354 break; 00355 } 00356 case SPRITE_DIRECTION_RIGHT_DOWN: 00357 { 00358 i8_proposedOffsetX = i8_movementMatrix[2][4]; 00359 i8_proposedOffsetY = i8_movementMatrix[2][5]; 00360 break; 00361 } 00362 } 00363 00364 // Apply the proposed offsets to the proposed new coordinates 00365 u16_proposedX += i8_proposedOffsetX; 00366 u16_proposedY += i8_proposedOffsetY; 00367 00368 // Are the proposed coordinates within the bounds of where we 00369 // want the sprite to move within? 00370 if (u16_proposedX < SPRITE_MINIMUM_X || u16_proposedX > SPRITE_MAXIMUM_X || 00371 u16_proposedY < SPRITE_MINIMUM_Y || u16_proposedY > SPRITE_MAXIMUM_Y) 00372 { 00373 // We have encountered a boundary so we must choose 00374 // a new location and then try again 00375 u8_spriteCurrentDirection = AnimationGetANewDirectionToTravel(); 00376 00377 // Increment the teleport counter and see if it's time to teleport 00378 if (++u8_teleportCounter == 10) 00379 { 00380 // It is time to teleport, pick a new "random" location 00381 u16_proposedX = (rand() % LCD_WIDTH); 00382 u16_proposedY = (rand() % LCD_HEIGHT); 00383 00384 // Start counting for the next teleport 00385 u8_teleportCounter = 0; 00386 00387 // Report that we teleported! 00388 st_lcd.DisplayStringAt(1, LINE(4), (uint8_t *)"Teleported!", CENTER_MODE); 00389 00390 // After a while we will remove that message so this is a timer/counter 00391 u16_teleportMessageRemovalCountDown = 40; 00392 } 00393 else 00394 { 00395 // Start over from where we currently are 00396 u16_proposedX = u16_spriteCurrentX; 00397 u16_proposedY = u16_spriteCurrentY; 00398 } 00399 00400 // Try for a new location 00401 continue; 00402 } 00403 00404 // We have a new proposed location 00405 b_haveNewLocation = true; 00406 } 00407 00408 // Place the sprite at the new location 00409 AnimationDrawOrEraseSpriteAtThisLocation(u16_proposedX, u16_proposedY, true); 00410 } 00411 00412 // ---------------------------------------------------------------------- 00413 // AnimationThread() 00414 // 00415 // This is the main thread for the animation functionality. The thread 00416 // usually runs forever however there is a mechanism for terminating 00417 // it provided in this module. 00418 // 00419 // The thread wakes up about 40 times a second so that the animation 00420 // can move fairly quickly and smoothly. 00421 // 00422 // ---------------------------------------------------------------------- 00423 void AnimationThread(void) 00424 { 00425 // This thread will run until it gets terminated upon request 00426 while(true) 00427 { 00428 // Wake up 40 times a second 00429 wait(0.025); 00430 00431 // Move ths sprite in the cirrent direction of travel 00432 AnimationMoveSprite(); 00433 } 00434 } 00435 00436 // ---------------------------------------------------------------------- 00437 // AnimationPerformAnimation() 00438 // 00439 // This function is called when it is time to start animating the 00440 // sprite. It checks to make sure that the animation thread is not 00441 // yet started before it starts the animation. 00442 // 00443 // ---------------------------------------------------------------------- 00444 void AnimationPerformAnimation(uint32_t u32_randomSeeder) 00445 { 00446 // Are we currently not running the animation? 00447 if (false == b_animationThreadRunning) 00448 { 00449 // Place the sprite on to the screen 00450 AnimationDrawOrEraseSpriteAtThisLocation(LCD_WIDTH / 2, LCD_HEIGHT / 2, true); 00451 00452 // Start the animation thread 00453 st_animationThread.start(AnimationThread); 00454 00455 // Flag the fact that the thread is running 00456 b_animationThreadRunning = true; 00457 00458 // In an effort to add more "randomness," read some of the 00459 // analog inputs and add their values, if any, to the seed 00460 u32_randomSeeder = (st_analog1 * 100) + (st_analog2 * 100) + (st_analog3 * 100); 00461 00462 // In order to "seed" the random number generator, we acquire 00463 // and discard up to 2000 random numbers 00464 u32_randomSeeder %= 2000; 00465 00466 // Acquire up to 2000 random numbers 00467 while (u32_randomSeeder-- > 0) 00468 { 00469 // Acquire the number and then discard it 00470 (void)AnimationGetANewDirectionToTravel(); 00471 } 00472 } 00473 } 00474 00475 // ---------------------------------------------------------------------- 00476 // AnimationStopAnimation() 00477 // 00478 // In the event the animation thread needs to be stopped, this function 00479 // may be called to terminate the animation thread. 00480 // 00481 // ---------------------------------------------------------------------- 00482 void AnimationStopAnimation(void) 00483 { 00484 // Is the animation thread running? 00485 if (true == b_animationThreadRunning) 00486 { 00487 // Stop the animation thread 00488 st_animationThread.terminate(); 00489 00490 // Flag the fact that animation is no longer running 00491 b_animationThreadRunning = false; 00492 } 00493 } 00494 00495 // End of file 00496
Generated on Fri Jul 15 2022 16:50:53 by
1.7.2