Rock, Paper, Scissors game coordinator
Dependencies: fsl_phy_mcr20a fsl_smac mbed-rtos mbed
Fork of mcr20_RPS_Coordinator by
Revision 0:9c8c234fd5ae, committed 2015-11-17
- Comitter:
- mnorman4
- Date:
- Tue Nov 17 17:14:10 2015 +0000
- Commit message:
- Initial commit of Rock, Paper, Scissors game coordinator
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/circular_buffer.cpp Tue Nov 17 17:14:10 2015 +0000 @@ -0,0 +1,77 @@ +#include "circular_buffer.h" + +CircularBuffer::CircularBuffer() +{ + size = gCircularBufferSize_c; + readIndex = 0; + writeIndex = 0; + count = 0; + MEM_Init(); + buffer = (uint8_t *) MEM_BufferAlloc(size * sizeof(uint8_t)); + if ( NULL == buffer ) + { + /*if buffer alloc fails stop the program execution*/ + while(1); + } +} + +CircularBuffer::CircularBuffer(uint32_t sz) +{ + size = sz; + readIndex = 0; + writeIndex = 0; + count = 0; + MEM_Init(); + buffer = (uint8_t *) MEM_BufferAlloc(size * sizeof(uint8_t)); + if ( NULL == buffer ) + { + /*if buffer alloc fails stop the program execution*/ + while(1); + } +} + +CircularBuffer::~CircularBuffer() +{ + size = 0; + readIndex = 0; + writeIndex = 0; + count = 0; + MEM_BufferFree(buffer); +} + +bufferStatus_t CircularBuffer :: addToBuffer (uint8_t c) +{ + buffer[writeIndex] = c; + writeIndex++; + if (writeIndex >= size) + { + writeIndex = 0; + } + count++; + if (count >= size) + { + return buffer_Full_c; + } + return buffer_Ok_c; +} + +bufferStatus_t CircularBuffer :: getFromBuffer (uint8_t *c) +{ + if ( 0 == count ) + { + return buffer_Empty_c; + } + (*c) = buffer[readIndex]; + readIndex++; + if (readIndex >= size) + { + readIndex = 0; + } + count--; + return buffer_Ok_c; +} + +uint32_t CircularBuffer :: getCount() +{ + return count; +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/circular_buffer.h Tue Nov 17 17:14:10 2015 +0000 @@ -0,0 +1,34 @@ +#ifndef __CIRCULAR_BUFFER_H__ +#define __CIRCULAR_BUFFER_H__ + +#include "EmbeddedTypes.h" +#include "MemManager.h" + +#ifndef gCircularBufferSize_c +#define gCircularBufferSize_c 32 +#endif + +typedef enum bufferStatus_tag +{ + buffer_Ok_c = 0, + buffer_Empty_c, + buffer_Full_c +}bufferStatus_t; + +class CircularBuffer { + public: + CircularBuffer(); + CircularBuffer(uint32_t sz); + ~CircularBuffer(); + bufferStatus_t addToBuffer (uint8_t c); + bufferStatus_t getFromBuffer (uint8_t *c); + uint32_t getCount(); + private: + uint8_t *buffer; + uint32_t size; + uint32_t readIndex; + uint32_t writeIndex; + uint32_t count; +}; + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fsl_phy_mcr20a.lib Tue Nov 17 17:14:10 2015 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/teams/Freescale/code/fsl_phy_mcr20a/#764779eedf2d
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fsl_smac.lib Tue Nov 17 17:14:10 2015 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/teams/Freescale/code/fsl_smac/#401ba973869e
--- /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); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed-rtos.lib Tue Nov 17 17:14:10 2015 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed-rtos/#6d90423c236e
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Tue Nov 17 17:14:10 2015 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/9296ab0bfc11 \ No newline at end of file