Rock, Paper, Scissors game coordinator

Dependencies:   fsl_phy_mcr20a fsl_smac mbed-rtos mbed

Fork of mcr20_RPS_Coordinator by Freescale

Revision:
0:9c8c234fd5ae
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Tue Nov 17 17:14:10 2015 +0000
@@ -0,0 +1,477 @@
+#include "mbed.h"
+#include "rtos.h"
+#include "Phy.h"
+#include "SMAC_Interface.h"
+#include "SMAC_Config.h"
+#include "MemManager.h"
+#include "circular_buffer.h"
+
+/* Constant Strings */
+char const StartupMessage[]= "\rGame Controller Bridge is online.\r\n\n";
+char const LetsPlay[] = "Let's play Rock, Paper, Scissors!\r\n";
+char const PlayerAString[] = "Player A";
+char const PlayerBString[] = "Player B";
+char const StrRock[] = "Rock";
+char const StrPaper[] = "Paper";
+char const StrScissors[] = "Scissors";
+
+/* Hardware Resources */
+/* LEDs */
+DigitalOut k64f_led_red(LED_RED, 1);
+DigitalOut k64f_led_green(LED_GREEN, 1);
+DigitalOut k64f_led_blue(LED_BLUE, 1);
+DigitalOut cr20a_led_red(PTC11, 1);
+DigitalOut cr20a_led_green(PTC10, 1);
+DigitalOut cr20a_led_blue(PTB11, 1);
+
+#define LED_ON                  (0)
+#define LED_OFF                 (1)
+
+/* Pushbuttons */
+InterruptIn k64f_sw2(SW2);
+InterruptIn k64f_sw3(SW3);
+InterruptIn cr20a_sw1(PTB23);
+InterruptIn cr20a_sw2(PTA1);
+InterruptIn cr20a_sw3(PTC4);
+
+#define gPushbutton_K64F_SW2    (1<<1)
+#define gPushbutton_K64F_SW3    (1<<2)
+#define gPushbutton_CR20A_SW1   (1<<3)
+#define gPushbutton_CR20A_SW2   (1<<4)
+#define gPushbutton_CR20A_SW3   (1<<5)
+
+/* OpenSDA Serial Port (UART) */
+Serial uart(USBTX, USBRX);
+CircularBuffer uartBuf;
+#define gDefaultBaudRate_UART_c 115200UL
+
+/* Event Flags */
+#define gMcps_Cnf_EVENT_c        (1<<1)
+#define gMcps_Ind_EVENT_c        (1<<2)
+#define gMlme_EdCnf_EVENT_c      (1<<3)
+#define gMlme_CcaCnf_EVENT_c     (1<<4)
+#define gMlme_TimeoutInd_EVENT_c (1<<5)
+#define gWUSelf_EVENT_c          (1<<6)
+
+#ifdef VERBOSE
+static bool_t bCCAFailed;
+static bool_t bACKFailed;
+#endif
+
+uint32_t gTaskEventFlags;
+static uint8_t gau8TxDataBuffer[gMaxSmacSDULength_c  + sizeof(rxPacket_t)];  
+txPacket_t *gAppTxPacket;
+rxPacket_t *gAppRxPacket;
+static txContextConfig_t txConfigContext;
+
+void InitProject(void);
+void InitApp(void);
+
+extern smacErrors_t smacToAppMlmeSap(smacToAppMlmeMessage_t* pMsg, instanceId_t instance);
+extern smacErrors_t smacToAppMcpsSap(smacToAppDataMessage_t* pMsg, instanceId_t instance);
+
+osThreadId PushbuttonThreadID;
+osThreadId EventsThreadID;
+
+void k64f_sw2_press(void)   { osSignalSet(PushbuttonThreadID, gPushbutton_K64F_SW2); }
+void k64f_sw3_press(void)   { osSignalSet(PushbuttonThreadID, gPushbutton_K64F_SW3); }
+void cr20a_sw1_press(void)  { osSignalSet(PushbuttonThreadID, gPushbutton_CR20A_SW1); }
+void cr20a_sw2_press(void)  { osSignalSet(PushbuttonThreadID, gPushbutton_CR20A_SW2); }
+void cr20a_sw3_press(void)  { osSignalSet(PushbuttonThreadID, gPushbutton_CR20A_SW3); }
+
+/* Constants used to build the single byte game selection */
+char const PlayerA  = 0xA0;
+char const PlayerB  = 0xB0;
+char const Rock     = 0x01;
+char const Paper    = 0x02;
+char const Scissors = 0x03;
+char const Winner   = 0x08;
+char const Loser    = 0x0F;
+char const Draw     = 0xFF;
+
+/* RPS States */
+#define GameStateWaitingBoth    (1<<0)
+#define GameStateWaitingA       (1<<1)
+#define GameStateWaitingB       (1<<2)
+#define GameStateReady          (1<<3)
+#define GameStateAWins          (1<<4)
+#define GameStateBWins          (1<<5)
+#define GameStateDraw           (1<<6)
+
+int     GameState       = GameStateWaitingBoth;
+uint8_t Aselection      = 0;
+uint8_t Bselection      = 0; 
+
+/* Stats */
+int     GameNum         = 0;
+int     NumWinsA        = 0;
+int     NumWinsB        = 0; 
+int     NumDraws        = 0;
+
+void HeartbeatThread(void const *argument)
+{
+    while (true) {
+        k64f_led_green = LED_ON;
+        Thread::wait(50);
+        k64f_led_green = LED_OFF;
+        Thread::wait(1950);
+    }
+}
+
+void PushbuttonThread(void const *argument)
+{
+    PushbuttonThreadID = Thread::gettid();
+    osEvent event;
+
+    while (true) {
+        event = Thread::signal_wait(0, osWaitForever);
+
+//TODO: Consider using pushbuttons on bridge to set game mode (single/dual player, etc.)
+
+        if (event.value.signals & gPushbutton_K64F_SW2) {
+            uart.printf("K64F_SW2\r\n");
+        }
+        if (event.value.signals & gPushbutton_K64F_SW3) {
+            uart.printf("K64F_SW3\r\n");
+        }
+        if (event.value.signals & gPushbutton_CR20A_SW1) {
+            uart.printf("CR20A_SW1\r\n");
+        }
+        if (event.value.signals & gPushbutton_CR20A_SW2) {
+            uart.printf("CR20A_SW2\r\n");
+        }
+        if (event.value.signals & gPushbutton_CR20A_SW3) {
+            uart.printf("CR20A_SW3\r\n");
+        }
+    }
+}
+
+void PrintSelection (uint8_t selection)
+{
+    const char *PlayerString;
+    const char *WeaponString;
+    uint8_t player = ((selection & 0xF0) >> 4);
+    uint8_t weapon = ((selection & 0x0F) >> 0);
+    
+    if (player == 0xA)
+        PlayerString = PlayerAString;
+    else if (player == 0xB)
+        PlayerString = PlayerBString;
+    else {
+        uart.printf("Invalid Player\r\n");
+        return;
+    }
+    
+    switch (weapon)
+    {
+        case Rock:
+            WeaponString = StrRock;
+            break;
+        case Paper:
+            WeaponString = StrPaper;
+            break;
+        case Scissors:
+            WeaponString = StrScissors;
+            break;
+        default:
+            uart.printf("Invalid Weapon: 0x%d\r\n", weapon);
+            return;
+    }
+    
+    uart.printf("%s: %s\r\n", PlayerString, WeaponString);
+}
+
+void RockPaperScissors (uint8_t selection)
+{
+    uint8_t player = ((selection & 0xF0) >> 4);
+    uint8_t weapon = ((selection & 0x0F) >> 0);
+    
+    switch (GameState) {
+        case GameStateWaitingBoth:
+            if (player == 0xA) {
+                Aselection = weapon;
+                GameState = GameStateWaitingB;
+                uart.printf("Player A: Ready\r\n");
+            }
+            if (player == 0xB) {
+                Bselection = weapon;
+                GameState = GameStateWaitingA;
+                uart.printf("Player B: Ready\r\n");
+            }
+            break;
+        case GameStateWaitingA:
+            if (player == 0xA) {
+                Aselection = weapon;
+                uart.printf("Player A: Ready\r\n");
+                GameState = GameStateReady;
+            }
+            break;
+        case GameStateWaitingB:
+            if (player == 0xB) {
+                Bselection = weapon;
+                uart.printf("Player B: Ready\r\n");
+                GameState = GameStateReady;
+            }
+            break;
+    }
+
+    if (GameState == GameStateReady)
+    {
+        if (Aselection == Rock)
+        {
+            uart.printf("\nRock vs. ");
+            if (Bselection == Rock)
+            {
+                uart.printf("Rock\r\n");
+                GameState = GameStateDraw;
+            }
+            if (Bselection == Paper)
+            {
+                uart.printf("Paper\r\n");
+                GameState = GameStateBWins;
+            }
+            if (Bselection == Scissors)
+            {
+                uart.printf("Scissors\r\n");
+                GameState = GameStateAWins;
+            }
+        }
+        if (Aselection == Paper)
+        {
+            uart.printf("\nPaper vs. ");
+            if (Bselection == Rock)
+            {
+                uart.printf("Rock\r\n");
+                GameState = GameStateAWins;
+            }
+            if (Bselection == Paper)
+            {
+                uart.printf("Paper\r\n");
+                GameState = GameStateDraw;
+            }
+            if (Bselection == Scissors)
+            {
+                uart.printf("Scissors\r\n");
+                GameState = GameStateBWins;
+            }
+        }
+        if (Aselection == Scissors)
+        {
+            uart.printf("\nScissors vs. ");
+            if (Bselection == Rock)
+            {
+                uart.printf("Rock\r\n");
+                GameState = GameStateBWins;
+            }
+            if (Bselection == Paper)
+            {
+                uart.printf("Paper\r\n");
+                GameState = GameStateAWins;
+            }
+            if (Bselection == Scissors)
+            {
+                uart.printf("Scissors\r\n");
+                GameState = GameStateDraw;
+            }
+        }
+    }
+    if (GameState == GameStateAWins)
+    {
+        uart.printf("Player A Wins!\r\n\n");
+        (void)uartBuf.addToBuffer(uint8_t(PlayerA | Winner)); 
+        ++NumWinsA; 
+        GameState = GameStateWaitingBoth;
+    }
+    if (GameState == GameStateBWins)
+    {
+        uart.printf("Player B Wins!\r\n\n");
+        (void)uartBuf.addToBuffer(uint8_t(PlayerB | Winner)); 
+        ++NumWinsB; 
+        GameState = GameStateWaitingBoth;
+    }
+    if (GameState == GameStateDraw)
+    {
+        uart.printf("It's a draw.\r\n\n");
+        (void)uartBuf.addToBuffer(uint8_t(Draw)); 
+        ++NumDraws; 
+        GameState = GameStateWaitingBoth;
+    }
+    if (GameState == GameStateWaitingBoth)
+    {
+        uart.printf("%s", LetsPlay);
+    }
+    if (uartBuf.getCount())
+    {
+        gTaskEventFlags |= gWUSelf_EVENT_c;
+        osSignalSet(EventsThreadID, 0x1);
+    }    
+}
+
+void EventsThread(void const *argument)
+{
+    EventsThreadID = Thread::gettid();
+    uint8_t rcvd = 0, c = 0; 
+
+    while (true)
+    {
+        Thread::signal_wait(0x1);
+        if(gMcps_Cnf_EVENT_c == (gTaskEventFlags & gMcps_Cnf_EVENT_c))
+        {
+            MLMERXEnableRequest(gAppRxPacket, 0); 
+        }
+        if(gMcps_Ind_EVENT_c == (gTaskEventFlags & gMcps_Ind_EVENT_c))
+        {
+            rcvd = gAppRxPacket->smacPdu.smacPdu[0];
+            RockPaperScissors(rcvd);
+            MLMERXEnableRequest(gAppRxPacket, 0);
+        }
+        if(gMlme_TimeoutInd_EVENT_c == (gTaskEventFlags & gMlme_TimeoutInd_EVENT_c))
+        {
+            uart.printf("MlmeTimeoutInd: \r\n");
+        }
+        if(gMlme_EdCnf_EVENT_c == (gTaskEventFlags & gMlme_EdCnf_EVENT_c))
+        {
+            uart.printf("EdCnf: \r\n");
+        }
+        if(gMlme_CcaCnf_EVENT_c == (gTaskEventFlags & gMlme_CcaCnf_EVENT_c))
+        {
+            uart.printf("CcaCnf: \r\n");
+        }
+        if(gWUSelf_EVENT_c == (gTaskEventFlags & gWUSelf_EVENT_c))
+        {
+            if (buffer_Ok_c == uartBuf.getFromBuffer(&c))
+            {
+                gAppTxPacket->smacPdu.smacPdu[0] = c;
+                gAppTxPacket->u8DataLength = 1;
+                (void)MLMERXDisableRequest();
+                (void)MCPSDataRequest(gAppTxPacket);
+            }
+        }
+        gTaskEventFlags = 0;
+    }
+}
+
+int main()
+{
+    MEM_Init();
+    Thread heartbeat(HeartbeatThread);
+    Thread pushbuttons(PushbuttonThread);
+    Thread events(EventsThread);
+    Phy_Init();
+    InitSmac();
+    
+    //Tell SMAC who to call when it needs to pass a message to the application thread.
+    Smac_RegisterSapHandlers((SMAC_APP_MCPS_SapHandler_t)smacToAppMcpsSap,(SMAC_APP_MLME_SapHandler_t)smacToAppMlmeSap,0);
+
+    InitApp();
+
+    //uart.printf(StartupMessage);
+    uart.printf("%s", LetsPlay);
+
+    while (true) 
+    {
+        Thread::yield();
+    }
+}
+
+void InitApp()
+{
+  gAppTxPacket = (txPacket_t*)gau8TxDataBuffer;   //Map TX packet to buffer
+  gAppRxPacket = (rxPacket_t*)MEM_BufferAlloc(gMaxSmacSDULength_c + sizeof(rxPacket_t));
+  
+  InitProject();
+  
+  SMACFillHeader(&(gAppTxPacket->smacHeader), gDefaultAddress_c);                  
+  
+  (void)MLMEPAOutputAdjust(gDefaultOutputPower_c);
+  (void)MLMESetChannelRequest(gDefaultChannelNumber_c);         
+  (void)MLMEConfigureTxContext(&txConfigContext);
+  //AppDelayTmr = TMR_AllocateTimer();
+  gAppRxPacket->u8MaxDataLength = gMaxSmacSDULength_c;
+  (void)MLMERXEnableRequest(gAppRxPacket, 0);
+}
+
+/* (Management) Sap handler for managing timeout indication and ED confirm
+   This is running in INTERRUPT context, so need to send messages to one of the task */
+smacErrors_t smacToAppMlmeSap(smacToAppMlmeMessage_t* pMsg, instanceId_t instance)
+{
+  switch(pMsg->msgType)
+  {
+    case gMlmeEdCnf_c:
+        gTaskEventFlags |= gMlme_EdCnf_EVENT_c;
+        break;
+    case gMlmeCcaCnf_c:
+        gTaskEventFlags |= gMlme_CcaCnf_EVENT_c;
+        break;
+    case gMlmeTimeoutInd_c:
+        gTaskEventFlags |= gMlme_TimeoutInd_EVENT_c;
+        break;
+    default:
+        break;
+  }
+  osSignalSet(EventsThreadID, 0x1);
+  MEM_BufferFree(pMsg);
+  return gErrorNoError_c;
+}
+
+/* (Data) Sap handler for managing data confirm and data indication
+   This is running in INTERRUPT context, so need to send messages to one of the task */
+smacErrors_t smacToAppMcpsSap(smacToAppDataMessage_t* pMsg, instanceId_t instance)
+{  
+    switch(pMsg->msgType)
+    {
+        case gMcpsDataInd_c:
+            if(pMsg->msgData.dataInd.pRxPacket->rxStatus == rxSuccessStatus_c)
+            {       
+                gTaskEventFlags |= gMcps_Ind_EVENT_c;
+            }
+            break;
+
+        case gMcpsDataCnf_c:
+#ifdef VERBOSE
+            if(pMsg->msgData.dataCnf.status == gErrorChannelBusy_c)
+            {
+                bCCAFailed = TRUE;
+            }
+
+            if(pMsg->msgData.dataCnf.status == gErrorNoAck_c)
+            {
+                bACKFailed = TRUE;
+            }
+#endif
+            gTaskEventFlags |= gMcps_Cnf_EVENT_c;
+            break;
+        default:
+            break;
+    }
+    osSignalSet(EventsThreadID, 0x1);
+    MEM_BufferFree(pMsg);
+
+    return gErrorNoError_c;
+}
+
+void InitProject(void)
+{   
+    /*Global Data init*/
+    #ifdef VERBOSE
+    bACKFailed                        = FALSE;
+    bCCAFailed                        = FALSE;
+    #endif
+    
+    gTaskEventFlags = 0;
+    
+    txConfigContext.autoAck           = FALSE;
+    txConfigContext.ccaBeforeTx       = FALSE;
+    txConfigContext.retryCountAckFail = 0;
+    txConfigContext.retryCountCCAFail = 0;
+  
+    /* Setup UART */
+    uart.baud(gDefaultBaudRate_UART_c);
+
+    /* Setup Pushbutton Interrupt Callbacks */
+    k64f_sw2.fall(&k64f_sw2_press);
+    k64f_sw3.fall(&k64f_sw3_press);
+    cr20a_sw1.fall(&cr20a_sw1_press);
+    cr20a_sw2.fall(&cr20a_sw2_press);
+    cr20a_sw3.fall(&cr20a_sw3_press);
+}