/************************************************************************** SPI querying module **************************************************************************/ /*---------------------------- Include Files ----------------------------*/ #include <stdio.h> #include <hidef.h> /* common defines and macros */ #include "S12eVec.h" /* interrupts */ #include <timers12.h> #include "game.h" #include "SPI.h" /*--------------------------- Module Defines ----------------------------*/ #define SEND_QUEUE_SIZE 10 #define JUNK_COMMAND 0x50 #define NEW_COM_TIME 100 #define SEND_COM_TIME 1 #define SEND_JUNK_TIME 1 #define RECEIVE_RESP_TIME 1 #define QUERY_DISPENSE_PENDING 0xB0 #define DISPENSE_NUMBER 0xC0 #define REQUEST_PENDING 0xD1 #define REQUEST_SUCCEEDED 0xDF #define REQUEST_FAILED 0xD0 #define GAME_PAUSED 0xE0 #define GAME_RUNNING 0xE1 #define GAME_OVER_RED_WON 0xE2 #define GAME_OVER_GREEN_WON 0xE4 #define INVALID_COMMAND 0xFE #define PRINT_SPI 1 /*---------------------------- Module Types -----------------------------*/ typedef enum { SENDING_COMMAND, SENDING_JUNK, RECEIVING_RESPONSE, WAITING_FOR_NEW_COMMAND } SPI_STATE_t; /*-------------------------- Module Variables ---------------------------*/ static unsigned char sendQueue[SEND_QUEUE_SIZE]; static unsigned char currSendIndex; static unsigned char requestedCommand; SPI_STATE_t currSPIState; game_info_s *game_info; /*-------------------------- Module Functions ---------------------------*/ void HandleSPIResponse(unsigned char response); /*----------------------------- Module Code -----------------------------*/ void InitSPI(game_info_s *gameInfo) { unsigned int i; // setup SPI to mode 3, master, MSB first, no interrupts SPICR1 |= _S12_MSTR; // Set E128 as master SPICR1 &= ~_S12_LSFBE; // Set to send/receive most significant bit first SPIBR |= (_S12_SPPR0 | _S12_SPPR1| _S12_SPPR2); // SPPR = 7; SPIBR |= _S12_SPR1; // SPR = 2, so divisor = (1+7)*2^(2+1) = 64 (24 Mhz / 64 = 375 KHz) SPICR1 |= _S12_CPOL | _S12_CPHA; // Polarity: Active Low, sample even edges (mode 3) SPICR1 |= _S12_SSOE; // Enable slave select output SPICR2 |= _S12_MODFEN; // Hardware automatically lowers/raises SS SPICR1 |= _S12_SPE; // Enable SPI for (i=0; i<SEND_QUEUE_SIZE; i++) { sendQueue[i] = QUERY_GAME; } currSendIndex = 0; requestedCommand = QUERY_GAME; currSPIState = WAITING_FOR_NEW_COMMAND; TMRS12_InitTimer(SPI_TIMER, NEW_COM_TIME); game_info = gameInfo; printf("printspi: %d \r\n", PRINT_SPI); } // Add new command to send queue void AddNewCommand(unsigned char command) { requestedCommand = command; if(currSendIndex < SEND_QUEUE_SIZE - 2) sendQueue[currSendIndex+1] = command; else sendQueue[0] = command; } void UpdateSPI(void) { unsigned char temp, response; SPI_STATE_t nextState; switch(currSPIState) { case WAITING_FOR_NEW_COMMAND: // If the new command timer has expired and it is OK to transmit if(TMRS12_IsTimerExpired(SPI_TIMER) == TMRS12_EXPIRED && (SPISR & _S12_SPTEF) == _S12_SPTEF) { TMRS12_ClearTimerExpired(SPI_TIMER); // Load in new command to send queue SPIDR = sendQueue[currSendIndex]; nextState = SENDING_COMMAND; TMRS12_InitTimer(SPI_TIMER, SEND_COM_TIME); } else { nextState = WAITING_FOR_NEW_COMMAND; } break; case SENDING_COMMAND: // If the send command timer has expired and data was transferred to the SPIDR if(TMRS12_IsTimerExpired(SPI_TIMER) == TMRS12_EXPIRED && (SPISR & _S12_SPIF) == _S12_SPIF) { TMRS12_ClearTimerExpired(SPI_TIMER); // Read the SPIDR to begin transmission temp = SPIDR; nextState = SENDING_JUNK; TMRS12_InitTimer(SPI_TIMER, SEND_JUNK_TIME); } else { nextState = SENDING_COMMAND; } break; case SENDING_JUNK: // If the send junk timer has expired and it is OK to transmit if(TMRS12_IsTimerExpired(SPI_TIMER) == TMRS12_EXPIRED && (SPISR & _S12_SPTEF) == _S12_SPTEF) { TMRS12_ClearTimerExpired(SPI_TIMER); SPIDR = JUNK_COMMAND; nextState = RECEIVING_RESPONSE; TMRS12_InitTimer(SPI_TIMER, RECEIVE_RESP_TIME); } else { nextState = SENDING_JUNK; } break; case RECEIVING_RESPONSE: // If the receving response timer has expired and data was transferred to the SPIDR if(TMRS12_IsTimerExpired(SPI_TIMER) == TMRS12_EXPIRED && (SPISR & _S12_SPIF) == _S12_SPIF) { TMRS12_ClearTimerExpired(SPI_TIMER); response = SPIDR; HandleSPIResponse(response); // Replace last send command with default sendQueue[currSendIndex] = QUERY_GAME; currSendIndex = (currSendIndex+1)%SEND_QUEUE_SIZE; // Move over to the next command we need to send nextState = WAITING_FOR_NEW_COMMAND; TMRS12_InitTimer(SPI_TIMER, NEW_COM_TIME); } else { nextState = RECEIVING_RESPONSE; } break; } currSPIState = nextState; } void HandleSPIResponse(unsigned char response) { unsigned char commandtype = 0; unsigned char secondByte = 0; unsigned char nextSendIndex; nextSendIndex = (currSendIndex+1)%(SEND_QUEUE_SIZE-1); // Don't overwrite the query game slot switch(sendQueue[currSendIndex]) { case QUERY_STATE: switch(response) { case REQUEST_PENDING: // Query state again printf("Request pending \r\n"); sendQueue[nextSendIndex] = QUERY_STATE; break; // If requested command failed, send it again case REQUEST_FAILED: sendQueue[nextSendIndex] = requestedCommand; printf("Requested command failed! \r\n"); break; // If requested succeeded, update flags accordingly case REQUEST_SUCCEEDED: if (requestedCommand == HOOP_2) { printf("Set to HOOP2 \r\n"); } else if (requestedCommand == HOOP_3) { printf("Set to HOOP3 \r\n"); } else { // Ball has been dispensed printf("Ball Dispensed \r\n"); game_info->ballDispensed[response%4] = 1; } break; } break; case QUERY_GAME: switch(response) { case GAME_PAUSED: game_info->currGameCondition = PAUSED; printf("Game Paused \r\n"); break; case GAME_RUNNING: game_info->currGameCondition = RUNNING; //printf("Game Running \r\n"); break; case GAME_OVER_RED_WON: printf("Game Over, Red Won \r\n"); game_info->currGameCondition = RED_WON; break; case GAME_OVER_GREEN_WON: printf("Game Over, Green Won \r\n"); game_info->currGameCondition = GREEN_WON; break; } break; // Ball dispension/Hoop3/Hoop2/Ball Query default: switch(response) { // If requested command forwarded, start querying status of last request case REQUEST_PENDING: sendQueue[nextSendIndex] = QUERY_STATE; break; // If requested command not forwarded, send it again case REQUEST_FAILED: printf("Request failed!!! \r\n"); sendQueue[nextSendIndex] = requestedCommand; break; // Query of dispenser pending, query again case QUERY_DISPENSE_PENDING+0: case QUERY_DISPENSE_PENDING+4: case QUERY_DISPENSE_PENDING+8: case QUERY_DISPENSE_PENDING+12: printf("Query of dispenser pending, querying again \r\n"); sendQueue[nextSendIndex] = requestedCommand; // Dispenser xx has yy balls available break; // Received number of balls in dispenser case DISPENSE_NUMBER+0+0: case DISPENSE_NUMBER+0+1: case DISPENSE_NUMBER+0+2: case DISPENSE_NUMBER+0+3:; game_info->availableBalls[0] = response%4; printf("Dispenser 0 has %d balls available \r\n", game_info->availableBalls[0]); game_info->queryComplete = 1; break; case DISPENSE_NUMBER+4+0: case DISPENSE_NUMBER+4+1: case DISPENSE_NUMBER+4+2: case DISPENSE_NUMBER+4+3: game_info->availableBalls[1] = response%4; printf("Dispenser 1 has %d balls available \r\n", game_info->availableBalls[1]); game_info->queryComplete = 1; break; case DISPENSE_NUMBER+8+0: case DISPENSE_NUMBER+8+1: case DISPENSE_NUMBER+8+2: case DISPENSE_NUMBER+8+3: game_info->availableBalls[2] = response%4; printf("Dispenser 2 has %d balls available \r\n", game_info->availableBalls[2]); game_info->queryComplete = 1; break; case DISPENSE_NUMBER+12+0: case DISPENSE_NUMBER+12+1: case DISPENSE_NUMBER+12+2: case DISPENSE_NUMBER+12+3: game_info->availableBalls[3] = response%4; printf("Dispenser 3 has %d balls available \r\n", game_info->availableBalls[3]); game_info->queryComplete = 1; break; default: printf("Unexpected response %x to command %x \r\n", response, sendQueue[currSendIndex]); break; } break; } }