/**************************************************************************** Module CompassService.c Revision 1.0.1 Description This is the highest level module for ME 218B Lab 8. Implements a flat state machine under the Gen2 Events and Services Framework. Notes Team 3 History When Who What/Why -------------- --- -------- 02/04/2019 pablo created file ****************************************************************************/ /*----------------------------- Include Files -----------------------------*/ /* include header files for this state machine as well as any machines at the next lower level in the hierarchy that are sub-machines to this machine */ // This module #include "CompassService.h" // Event & Services Framework #include "ES_Configure.h" #include "ES_Framework.h" #include "ES_DeferRecall.h" #include "ES_ShortTimer.h" #include "ES_Port.h" // Hardware #include "inc/hw_pwm.h" #include "inc/hw_gpio.h" #include "inc/hw_sysctl.h" #include "inc/hw_memmap.h" #include "inc/hw_types.h" #include "inc/hw_nvic.h" #include "inc/hw_ssi.h" #include "inc/hw_Timer.h" //Include other files #include "GameControlService.h" #include "GameplayHSM.h" /*----------------------------- Module Defines ----------------------------*/ #define BitsPerNibble 4 //Void byte for sending to Compass and receiving data #define VOIDBYTE 0x00 //Pins for preprogrammed queries #define QUERYCOLOR 0XD2 #define QUERYECOP 0xB4 #define QUERYSTATUS 0x78 #define QUERYRECYCLE 0x69 //Mask Defines #define TEAMBYTE 0x01 #define TEAMCOLOR 0x0E #define TEAMFREQ 0xF0 #define STATUS 0x03 #define ERECYCLE 0x1C #define WRECYCLE 0xE0 /*---------------------------- Module Functions ---------------------------*/ /* prototypes for private functions for this machine.They should be functions relevant to the behavior of this state machine */ static void InitSPIComms(void); static void TransmitSPI(uint8_t SendData); static uint16_t ReadSPI(void); static void InitSPIComms(void); /*---------------------------- Module Variables ---------------------------*/ // everybody needs a state variable, you may need others as well. // type of state variable should match that of enum in header file static uint8_t MyPriority; static CompassState_t CurrentState; //Save query values static uint8_t TeamAssigned; static uint8_t ColorAssigned; static uint8_t FreqAssigned; static uint8_t EastRecycleColor; static uint8_t WestRecycleColor; static uint8_t GameState; //Flag for game status static bool GameActive = false; /**************************************************************************** Function InitializeCompassService Parameters void Returns void Description Initializes SPI communications, and relevant hardware ports Notes Author Pablo Martinez Alanis ****************************************************************************/ bool InitCompassService(uint8_t Priority) { ES_Event_t ThisEvent; MyPriority = Priority; /******************************************** in here you write your initialization code ********************************************/ //Finish initializing SPI communication module //InitSPIComms(); //Enable Global interrupts, may be replaced in global initialization variable //__enable_irq(); ThisEvent.EventType = ES_INIT; if (ES_PostToService(MyPriority, ThisEvent) == true) { return true; } else { return false; } } /**************************************************************************** Function PostCompassService Parameters EF_Event ThisEvent ,the event to post to the queue Returns bool false if the Enqueue operation failed, true otherwise Description Posts an event to this state machine's queue Notes Author J. Edward Carryer, 10/23/11, 19:25 ****************************************************************************/ bool PostCompassService(ES_Event_t ThisEvent) { return ES_PostToService(MyPriority, ThisEvent); } /**************************************************************************** Function RunCompassService Parameters ES_Event : the event to process Returns ES_Event, ES_NO_EVENT if no error ES_ERROR otherwise Description add your description here Notes Author J. Edward Carryer, 01/15/12, 15:23 ****************************************************************************/ ES_Event_t RunCompassService(ES_Event_t ThisEvent) { ES_Event_t ReturnEvent; ES_Event_t NextEvent; ReturnEvent.EventType = ES_NO_EVENT; // assume no errors switch (CurrentState) { case InitCState: { //Start with initial transition event if (ThisEvent.EventType == ES_INIT) { //Set transition to wait for REG byte state CurrentState = WaitforREG; //Initialize delay timer ES_Timer_InitTimer(CompassDelayTimer, 2); } } break; case WaitforREG: { //Waiting for registration byte if (ThisEvent.EventType == TEAM_SELECT) { //Team select byte received, send to SPI communication function TransmitSPI(ThisEvent.EventParam); //Transition to wait for ACK byte state CurrentState = WaitForACK; } } break; case WaitForACK: { //Waiting for acknowledge byte from EOT if (ThisEvent.EventType == DATA_RECEIVED) { //Received byte from COMPASS, post REG_Complete event to GameControlService NextEvent.EventType = REG_COMPLETE; PostGameControlService(NextEvent); //Initialize query timer ES_Timer_InitTimer(CompassQueryTimer, 500); //Transition to query timer state CurrentState = WaitForQuery; } } break; case WaitForQuery: { //Waiting for Timeout if ((ThisEvent.EventType == ES_TIMEOUT) && (ThisEvent.EventParam == CompassQueryTimer)) { //Querying Timeout //printf("Sending data to SPI\n\r"); //Timeout happened, send query for 0XD2 TransmitSPI(QUERYCOLOR); //Transition into wait for TEAM byte CurrentState = WaitForTEAM; } } break; case WaitForTEAM: { //Waiting for EOT if (ThisEvent.EventType == DATA_RECEIVED) { //Received data event, save to module variables //Mask Team Selection TeamAssigned = (ThisEvent.EventParam & TEAMBYTE); //Mask Color selection (shift 1 bit to the left) ColorAssigned = (ThisEvent.EventParam & TEAMCOLOR) >> 1; //Mask Frequency selection (shift 4 bits to the left FreqAssigned = (ThisEvent.EventParam & TEAMFREQ) >> 4; //Querying values //Start delay timer ES_Timer_InitTimer(CompassDelayTimer, 500); //Switch to next case CurrentState = WaitForDelay; } } break; case WaitForDelay: { //Waiting for timeout if ((ThisEvent.EventType == ES_TIMEOUT) && (ThisEvent.EventParam == CompassDelayTimer)) { //Send query for Status TransmitSPI(QUERYSTATUS); //Transition into wait for STAT byte CurrentState = WaitForStat; } } break; case WaitForStat: { //Wait for EOT if (ThisEvent.EventType == DATA_RECEIVED) { //Received data event, save to module variables //Mask GameState //printf("Byte recieved; %d\n\r",ThisEvent.EventParam); GameState = (ThisEvent.EventParam & STATUS); //Mask East Recycling color (shift 2 bits to the left) EastRecycleColor = (ThisEvent.EventParam & ERECYCLE) >> 2; //Mask West Recycling color (shift 5 bits to the left WestRecycleColor = (ThisEvent.EventParam & WRECYCLE) >> 5; //Check if game has started or ended if ((GameState == 1) && (GameActive == false)) { //Game has started, post to relevant machines: // - GameControl, Gameplay, Compass NextEvent.EventType = GAME_STARTED; PostGameControlService(NextEvent); PostGameplayMasterSM(NextEvent); PostCompassService(NextEvent); GameActive = true; } else if ((GameState == 2) && (GameActive == true)) { printf("Game Over"); //Game has ended, post to relevant machines: // - GameControl, Gameplay, Compass, BallSorting NextEvent.EventType = GAME_OVER; PostGameControlService(NextEvent); PostGameplayMasterSM(NextEvent); PostCompassService(NextEvent); GameActive = false; } //Initialize query timer ES_Timer_InitTimer(CompassQueryTimer, 500); //Transition to query timer (and repeat process) CurrentState = WaitForQuery; } } } return ReturnEvent; } /*************************************************************************** Getter functions ***************************************************************************/ uint8_t GetTeamAssignment(void) { return TeamAssigned; } uint8_t GetColorAssignment(void) { return ColorAssigned; } uint16_t GetFreqAssignment(void) { uint16_t FrequencyAssigned = GetOurRecycleBeaconFreq(); if (FrequencyAssigned == WestRecycleColor) { FrequencyAssigned = WestAcceptedFreq; } else if (FrequencyAssigned == EastRecycleColor) { FrequencyAssigned = EastAcceptedFreq; } return FrequencyAssigned; } uint8_t GetEastRecycleColor(void) { return EastRecycleColor; } uint8_t GetWestRecycleColor(void) { return WestRecycleColor; } bool QueryGameStatus(void) { return GameActive; } /*************************************************************************** private functions ***************************************************************************/ /**************************************************************************** Function TransmitSPI Parameters uint8_t SendData data to send to the Command module Returns void Description Writes to the communication value the data to write Notes Author Pablo Martinez Alan ****************************************************************************/ static void TransmitSPI(uint8_t SendData) { // Writes SendData to SSI Data Register HWREG(SSI0_BASE + SSI_O_DR) = SendData; //Sends trash bits for communication purposes HWREG(SSI0_BASE + SSI_O_DR) = VOIDBYTE; HWREG(SSI0_BASE + SSI_O_DR) = VOIDBYTE; //HWREG(SSI0_BASE + SSI_O_DR) = VOIDBYTE; // Activates Local Interrupt to send data HWREG(SSI0_BASE + SSI_O_IM) |= SSI_IM_TXIM; // Debbuging aids //printf("DataSent %x\n\r",SendData); //printf("IE"); } /**************************************************************************** Function TransmitSPI Parameters uint8_t SendData data to send to the Command module Returns void Description Writes to the communication value the data to write Notes Author Pablo Martinez Alanis ****************************************************************************/ static uint16_t ReadSPI(void) { uint16_t SPIResponse = 0x0000; //Read first trash byte, should be 0x00 HWREG(SSI0_BASE + SSI_O_DR); //Read second trash byte, should be 0xFF HWREG(SSI0_BASE + SSI_O_DR); // Writes first data byte from the SPI SPIResponse = HWREG(SSI0_BASE + SSI_O_DR); //printf("SPI Function call: %X ",SPIResponse); //Write the second value //SPIResponse|=HWREG(SSI0_BASE + SSI_O_DR); return SPIResponse; } /**************************************************************************** Function ReceiveSPI Parameters void Returns void Description Interrupt Service Routine for receiving interrupt after EOT Notes Author Pablo Martinez Alanis ****************************************************************************/ void ReceiveSPI(void) { // Disables Local interrupts HWREG(SSI0_BASE + SSI_O_IM) &= (~SSI_IM_TXIM); //Sends EOT Event to Cpmpass Service ES_Event_t PostEvent; PostEvent.EventType = DATA_RECEIVED; PostEvent.EventParam = ReadSPI(); //printf("%x0\n\r",PostEvent.EventParam); //Posts to this event the SPI received value PostCompassService(PostEvent); //printf("Received SPI: %d \n\r",LastSPICommand); } static void InitSPIComms(void) { //Activates clock to GPIO PortA HWREG(SYSCTL_RCGCGPIO) |= SYSCTL_RCGCGPIO_R0; // Enables clock to SSI module 0 HWREG(SYSCTL_RCGCSSI) |= SYSCTL_RCGCSSI_R0; // Waits for GPIO port to be ready while ((HWREG(SYSCTL_PRGPIO) & BIT0HI) != BIT0HI) {} // Programs GPIO for alternate functions HWREG(GPIO_PORTA_BASE + GPIO_O_AFSEL) |= (BIT2HI | BIT3HI | BIT4HI | BIT5HI); // PA2=SSIOClk, PA3=SSIOFss, PA4=SSIORx, PA5 SSIOTx // Writes in GPIOCTL to select desired functions HWREG(GPIO_PORTA_BASE + GPIO_O_PCTL) = (HWREG(GPIO_PORTA_BASE + GPIO_O_PCTL) & 0xff0000ff) + (2 << BitsPerNibble * 2) + (2 << BitsPerNibble * 3) + (2 << BitsPerNibble * 4) + (2 << BitsPerNibble * 5); // Programs PA2 to PA5 for digital I/O HWREG(GPIO_PORTA_BASE + GPIO_O_DEN) |= (BIT2HI | BIT3HI | BIT4HI | BIT5HI); // Programs PA2 to PA4 data directions // (PA2, PA3 and PA5 are outputs, PA4 is input) HWREG(GPIO_PORTA_BASE + GPIO_O_DIR) |= (BIT2HI | BIT3HI | BIT5HI); HWREG(GPIO_PORTA_BASE + GPIO_O_DIR) &= (BIT4LO); // Programs Pull-up for the clock line for SPI mode 3 HWREG(GPIO_PORTA_BASE + GPIO_O_PUR) |= (BIT2HI); //Waits for SSI0 to be ready while ((HWREG(SYSCTL_RCGCSSI) & SYSCTL_RCGCSSI_R0) != SYSCTL_RCGCSSI_R0) {} // Disables SSI0 0 HWREG(SSI0_BASE + SSI_O_CR1) &= (~SSI_CR1_SSE); // Select Master mode, and TXRIS for End of Transmission HWREG(SSI0_BASE + SSI_O_CR1) &= (~SSI_CR1_MS); HWREG(SSI0_BASE + SSI_O_CR1) |= (SSI_CR1_EOT); // Configures SSI clock source to be the system clock HWREG(SSI0_BASE + SSI_O_CC) = (SSI_CC_CS_SYSPLL); // Configures clock prescaler (Bit Rate 15 kHz) CPSR = 132 HWREG(SSI0_BASE + SSI_O_CPSR) = HWREG(SSI0_BASE + SSI_O_CPSR) & (0xFFFFFF00) + 132; // Set SCR to 19 HWREG(SSI0_BASE + SSI_O_CR0) = ((HWREG(SSI0_BASE + SSI_O_CR0) + (19 << SSI_CR0_SCR_S))); // Configure SPH = 1 because data is captured at the second edge HWREG(SSI0_BASE + SSI_O_CR0) |= SSI_CR0_SPH; // Configure SPO = 1 because idle state is high HWREG(SSI0_BASE + SSI_O_CR0) |= SSI_CR0_SPO; // Freescale SPI Mode HWREG(SSI0_BASE + SSI_O_CR0) = ((HWREG(SSI0_BASE + SSI_O_CR0) & (~SSI_CR0_FRF_M)) | SSI_CR0_FRF_MOTO); // Sending 8 bit data between command generator & TIVA HWREG(SSI0_BASE + SSI_O_CR0) = ((HWREG(SSI0_BASE + SSI_O_CR0) & (~SSI_CR0_DSS_M)) | SSI_CR0_DSS_8); // Locally enable interrupts (TXIM in SSIIM) HWREG(SSI0_BASE + SSI_O_IM) |= SSI_IM_TXIM; // Enable SSI HWREG(SSI0_BASE + SSI_O_CR1) |= (SSI_CR1_SSE); // Enable NVIC bit 7 in EN0 HWREG(NVIC_EN0) |= BIT7HI; // Globally enable interrupts //__enable_irq(); // commented out because this is done in CommandFSM init }