/****************************************************************************
 Module
   
   SPI.c

 Revision
   1.0.1

 Description
   This implements Serial Communications with SPI 

 Notes
Lab8
 History
 When           Who     What/Why
 -------------- ---     --------
 
****************************************************************************/
/*----------------------------- 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
*/
#include "ES_Configure.h"
#include "ES_Framework.h"

#include <string.h>
#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>

#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_gpio.h"
#include "inc/hw_sysctl.h"
#include "driverlib/sysctl.h"
#include "driverlib/pin_map.h"  
#include "driverlib/gpio.h"

#include "inc/hw_pwm.h"
#include "inc/hw_nvic.h"
#include "inc/hw_timer.h"

#include "inc/tm4c123gh6pm.h" // Define PART_TM4C123GH6PM in project
#include "inc/hw_ssi.h" 

#include "CommunicationsMaster.h"
//lower level 
#include "ByteTransfer.h" 
//helper
#include "SPI.h"
/*----------------------------- Module Defines ----------------------------*/
#define BitsPerNibble 4 

//Alternative Functions for SSI
#define SSI0Clk GPIO_PIN_2 
#define SSI0Fss GPIO_PIN_3
#define SSI0Rx  GPIO_PIN_4
#define SSI0Tx  GPIO_PIN_5

#define CPSDVSR 12
#define SCR 222

#define BYTE_TIME 2 //2ms

/*---------------------------- Module Functions ---------------------------*/
/* prototypes for private functions for this service.They should be functions
   relevant to the behavior of this service
*/
static void SPIHardwareInit (void); 

/*---------------------------- Module Variables ---------------------------*/
// with the introduction of Gen2, we need a module level Priority variable
static uint8_t DataIn; 
static uint32_t counter;
static uint8_t BUFFER = 0x00;

static uint8_t CurrentRefResponseArray[4]; 
static uint8_t PreviousRefResponseArray[4];

/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
 Function
     InitSPI

 Parameters
     uint8_t : the priorty of this service

 Returns
     bool, false if error in initialization, true otherwise

 Description
     Saves away the priority, and does any
     other required initialization for this service
 Notes

 Author
     S Koppaka 
 ****************************************************************************/
  
void InitSPI(void)
{
  SPIHardwareInit(); //Initializes SPI
  //Initialize counter to 0    
  counter = 0; 
    
  // Clear Previous and Current response array 
  for (uint8_t i = 0; i < 4; i++)
  {
    PreviousRefResponseArray[i]=0;
    CurrentRefResponseArray[i]=0;
  }
  
}

//PUBLIC FUNCTIONS 

  static void SPIHardwareInit (void){
 //Enable the clock to the GPIO port A
HWREG(SYSCTL_RCGCGPIO) |= SYSCTL_RCGCGPIO_R0;
 
 //Enable the clock to the SSI module 
 HWREG(SYSCTL_RCGCSSI) |= SYSCTL_RCGCSSI_R0;
 
 //Wait for the GPIO port to be ready 
 while ((HWREG(SYSCTL_PRGPIO) & SYSCTL_RCGCGPIO_R0) != SYSCTL_RCGCGPIO_R0); 
 
 //Program the GPIO to use the alternative function on the SSI PINS (PA2-PA5)
 HWREG(GPIO_PORTA_BASE+GPIO_O_AFSEL) |= (SSI0Clk|SSI0Fss|SSI0Rx|SSI0Tx); 
 
 //Set mux position in GPIOPCTL to select the SSI use of the pins 19-22
 HWREG(GPIO_PORTA_BASE+GPIO_O_PCTL) =
(HWREG(GPIO_PORTA_BASE+GPIO_O_PCTL) & 0xff0000ff) +
(2<<(2*BitsPerNibble))+(2<<(3*BitsPerNibble))+(2<<(4*BitsPerNibble))+(2<<(5*BitsPerNibble));
    
 // Program the port lines for digital I/O
    HWREG(GPIO_PORTA_BASE+GPIO_O_DEN) |= (SSI0Clk|SSI0Fss|SSI0Rx|SSI0Tx);
 
 //Program the requried data direction on the port lines to initialize Mode3
     HWREG(GPIO_PORTA_BASE+GPIO_O_DIR) |= (SSI0Clk|SSI0Fss| SSI0Tx); //Clk, FSS, and Tx outputs; RX input
     HWREG(GPIO_PORTA_BASE+GPIO_O_DIR) &= ~(SSI0Rx);
     
 //Program the pull-on the clock line since using mode 3
HWREG(GPIO_PORTA_BASE+GPIO_O_PUR)|=SSI0Clk; 

//Wait for the SSI0 to be ready 
while ((HWREG(SYSCTL_PRSSI) & SYSCTL_PRSSI_R0) != SYSCTL_PRSSI_R0);  

//Make sure that the SSI is disabled before programming mode bits
HWREG(SSI0_BASE+SSI_O_CR1) &= ~SSI_CR1_SSE;
 
 //Select master mode (MS) & TXRIS indicating End of Trasmit (EOT) 
HWREG(SSI0_BASE+SSI_O_CR1) &= ~SSI_CR1_MS;
HWREG(SSI0_BASE+SSI_O_CR1) |= SSI_CR1_EOT;

//Configure the SSI clock source to the system clock 
 HWREG(SSI0_BASE+SSI_O_CC) &= SSI_CC_CS_SYSPLL;

//Configure the clock pre-scaler 
HWREG(SSI0_BASE+SSI_O_CPSR) |= CPSDVSR;

//Configure the clock rate (SCR), phase, polarity (SPH,SPO), mode (FRF SPI, default), data size(DSS)
HWREG(SSI0_BASE+SSI_O_CR0) = (HWREG(SSI0_BASE+SSI_O_CR0) & 0xffff0000) + (SCR<<8) + (1<<7) + (1<<6) + (0x7);

//Locally enable the interrupts (unmask transsmit FIFO interrupt in TXIM in SSIMM) 
HWREG(SSI0_BASE+SSI_O_IM) |=SSI_IM_TXIM;

//Make sure that the SSI is enabled for operations 
HWREG(SSI0_BASE+SSI_O_CR1) |= SSI_CR1_SSE;

//Globally enable interrupts
__enable_irq();

//Enable the NVIC interrupt for the SSI when starting to transmit 
 //it is interrupt number 7 so appears in EN0 at bit 7
HWREG(NVIC_EN0) |= BIT7HI;
//ENABLE IN KEIL 
 }

 //ISR EOT
void CommTransmitResponse( void ){
  
//clear the source of the EOT interrupt in the NVIC; *this might be sketch
HWREG(SSI0_BASE+SSI_O_ICR) |= SSI_ICR_RTIC;
 
//Get the tramitted data 
 GetData(); //Can call GetData 

counter++;
}

void SendData(uint8_t DataOut)
{
  HWREG(SSI0_BASE+SSI_O_DR) = DataOut;  ///In order to receive from the CommandGenerator, we query the commandgenerator by sending 0xAA
  for (uint8_t i = 0; i < 3; i++)
  {
   HWREG(SSI0_BASE+SSI_O_DR) = BUFFER; 
  }
  HWREG(SSI0_BASE+SSI_O_IM) |= SSI_IM_TXIM; //Enabling the EOT interrupt in the IM register after trasmit
}

void GetData(void)
{
  // Store CurrentArray into PreviousArray
  for (uint8_t i = 0; i < 4; i++) 
  {
    PreviousRefResponseArray[i] = CurrentRefResponseArray[i];
  }

  // Get new data and place in CurrentArray
  for (uint8_t j = 0; j < 4; j++)
  {
    DataIn = HWREG(SSI0_BASE+SSI_O_DR);  //DataIn is what has been received (From REF to TIVA)
    CurrentRefResponseArray[j] = DataIn;  
  }
  
  //Post event to ComMaster
  ES_Event_t  Event; 
  Event.EventType = ES_EOTREF;
  PostComMasterSM(Event);
  //Start Byte Transfer Timer
  ES_Timer_InitTimer(BYTE_TIMER, BYTE_TIME);
  
  //HWREG(SSI0_BASE+SSI_O_IM) |= SSI_IM_RXIM; 
  return; 
}

// Getter functions for the Current and Response in byte sized pieces
uint8_t GetCurrentByte0(void)
{
  return CurrentRefResponseArray[0];
}

uint8_t GetCurrentByte1(void)
{
  return CurrentRefResponseArray[1];
}

uint8_t GetCurrentByte2(void)
{
  return CurrentRefResponseArray[2];
}

uint8_t GetCurrentByte3(void)
{
  return CurrentRefResponseArray[3];
}

uint8_t GetPreviousByte0(void)
{
  return PreviousRefResponseArray[0];
}

uint8_t GetPreviousByte1(void)
{
  return PreviousRefResponseArray[1];
}

uint8_t GetPreviousByte2(void)
{
  return PreviousRefResponseArray[2];
}

uint8_t GetPreviousByte3(void)
{
  return PreviousRefResponseArray[3];
}