How to write a multithreaded Pong game

To further illustrate how to use the features of CMSIS-RTOS that we've introduced in this chapter, we'll return to the Pong program that we first introduced in Chapter 2, C Language Programming. We'll call this recipe: RTOS_Pong_v8v0. Due to space limitations, we're only showing those parts of the code that are relevant to the RTOS implementation. Refer to Chapter 2, C Language Programming for details of helper functions defined in the pong_utils.c file.

How to do it…

To create a multithreaded pong game, follow the steps given:

  1. Create a new project (new folder) called RTOS_Pong. Set the RTE to include board support for the ADC and GLCD. Include CMSIS-RTOS.
  2. Create a file named RTOS_Pong.c and add a task to handle the GLCD:
    void taskGLCD (void const *argument) {
      BallInfo init_pstn = thisGame.ball;
    
      for (;;) {
        osEvent evt = osMailGet(mail_box, osWaitForever);
        if (evt.status == osEventMail) {
          mail_t *mail = (mail_t*)evt.value.p;
          thisGame.p1.y = mail->pdl;            
          osMailFree(mail_box, mail);
    
          osMutexWait(mut_GLCD, osWaitForever);   
          update_player();
     
          if (thisGame.ball.x<BAR_W) {    /* reset pstn */       
            osDelay(T_LONG);
            erase_ball();      
            thisGame.ball = init_pstn;
          } 
          draw_ball();         
          osMutexRelease(mut_GLCD);
    
          osDelay(T_SHORT);
          osSignalSet(tid_taskBall, 0x0001);
        }
      }
    }
  3. Add a task to update the ball and check for collisions:
    void taskBall (void const *argument) {
    
       for (;;) {
        osSignalWait(0x0001, osWaitForever);
    
        update_ball();   
        check_collision();
    
        osSignalSet(tid_taskGLCD, 0x0001);
       }
    }
  4. Add a task to handle the ADC:
    void taskADC (void const *argument) {
    uint32_t adcValue;
      for (;;) {
        mail_t *mail = (mail_t*)osMailAlloc(mail_box, 
                                           osWaitForever);
        ADC_StartConversion();
        adcValue = ADC_GetValue ();
              
        mail->pdl = (adcValue >> 4) * (HEIGHT-BAR_H)/256;
        osMailPut(mail_box, mail);
        osDelay(T_SHORT);
      }
    }
  5. Add main(), save RTOS_Pong.c, and add the file to the project:
    int main (void) {
      HAL_Init ( );
      SystemClock_Config ( );
    
      game_Initialize();
      ADC_Initialize();
      GLCD_Initialize ();
      GLCD_Clear (White);             /* Clear the GLCD */
      GLCD_SetBackColor (White);  /* Set the Back Color */
      GLCD_SetTextColor (Blue);   /* Set the Text Color */
    
      mail_box = osMailCreate(osMailQ(mail_box), NULL);
      mut_GLCD = osMutexCreate(osMutex(mut_GLCD));
     
      tid_taskGLCD = osThreadCreate(osThread(taskGLCD), NULL);
      tid_taskBall = osThreadCreate(osThread(taskBall), NULL);
      tid_taskADC = osThreadCreate(osThread(taskADC), NULL);
    
      osDelay(osWaitForever);
      while(1)
        ;
    }
  6. Create an appropriate header file named RTOS_Pong.h:
    #ifndef _RTOS_PONG_H
    #define _RTOS_PONG_H
    
    #include "cmsis_os.h"
    
    #define __FI    1               /* Font index 16x24 */
    
    /* Mailbox */
    typedef struct {
      uint32_t pdl; /* paddle position */
    } mail_t;
    
    osMailQDef(mail_box, 1, mail_t);
    osMailQId  mail_box;
    
    /* Mutex */
    osMutexDef(mut_GLCD);
    osMutexId mut_GLCD; /* Mutex to control GLCD access */
    
    /* Function Prototypes for Tasks */
    void taskGLCD (void const *argument);
    void taskBall (void const *argument);
    void taskADC (void const *argument);
    
    /* Declare Task IDs */
    osThreadId tid_taskGLCD;  /* id of thread: taskGLCD */
    osThreadId tid_taskBall;  /* id of thread: taskGreq */
    osThreadId tid_taskADC;  /* id of thread: taskMotor */
    
    /* Define Threads */
    osThreadDef(taskGLCD, osPriorityNormal, __FI, 0);
    osThreadDef(taskBall, osPriorityNormal, __FI, 0);
    osThreadDef(taskADC, osPriorityNormal, __FI, 0);
    
    #endif /* _RTOS_PONG_H */
  7. Copy the pong_utils.c and pong_utils.h files (refer to Chapter 2, C Language Programming.) and add these to the project.
  8. Build, download, and run the program.

How it works…

The tasks named taskGLCD( ) and taskBall( ) are synchronized using a flag so the ball position is updated every time the screen is refreshed. The task named taskADC( ) sends the position of the paddle to a mailbox; taskGLCD( ) receives this value and uses it to render the paddle. The tasks are illustrated in the following diagram:

How it works…

The tasks are loosely coupled and can be independently tested. For example, during debuging, the taskADC( ) function and statements within taskGLCD( ), which read the mailbox and render the paddle, can be "commented out," leaving a simpler program that just moves the ball around the screen. The mailbox has only one slot. This is a key design decision that ensures that the paddle is rendered each time the ADC is read, so everything is synchronized to taskADC().

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.9.124