Rock, Paper, Scissors game coordinator

Dependencies:   fsl_phy_mcr20a fsl_smac mbed-rtos mbed

Fork of mcr20_RPS_Coordinator by Freescale

main.cpp

Committer:
mnorman4
Date:
2015-11-17
Revision:
0:9c8c234fd5ae

File content as of revision 0:9c8c234fd5ae:

#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);
}