//###########################################################################
//
// FILE:   Example_2837xDSpi_FFDLB.c
//
// TITLE:  SPI Digital Loop Back program.
//
//! \addtogroup cpu01_example_list
//! <h1>SPI Digital Loop Back (spi_loopback)</h1>
//!
//!  This program uses the internal loop back test mode of the peripheral.
//!  Other then boot mode pin configuration, no other hardware configuration
//!  is required. Interrupts are not used.
//!
//!  A stream of data is sent and then compared to the received stream.
//!  The sent data looks like this: \n
//!  0000 0001 0002 0003 0004 0005 0006 0007 .... FFFE FFFF \n
//!  This pattern is repeated forever.
//!
//!  \b Watch \b Variables \n
//!  - \b sdata - sent data
//!  - \b rdata - received data
//!
//
//###########################################################################
// $TI Release: F2837xD Support Library v210 $
// $Release Date: Tue Nov  1 14:46:15 CDT 2016 $
// $Copyright: Copyright (C) 2013-2016 Texas Instruments Incorporated -
//             http://www.ti.com/ ALL RIGHTS RESERVED $
//###########################################################################

//
// Included Files
//
#include "F28x_Project.h"

// Prototype statements for functions found within this file.
// __interrupt void ISRTimer2(void);
void delay_loop(void);   //延时
void spi_xmit(Uint16 a); //发送一个数据
void spi_fifo_init(void);//初始化fifo寄存器
void spi_init(void);     //初始化spi
void error(void);
void Ready_Config(); //从机芯片ready标志位，此位读到1表明从机已经准备好，才可以与从机进行通信
void SPI_RXbuff(unsigned char *buff,unsigned int len);
void SPI_TXbuff(unsigned char *buff,unsigned int len);
int CRC32_MPEG_2(const unsigned short int *data,int length,unsigned short int r_buf[]); //CRC校验码生成函数

//声明
unsigned char cmd_loadkey[6] = {0xAA,0xC3,0x00,0xA2,0x00,0x24};  // 密钥装载cmd
unsigned short int data_length = 20;  //自定义数据长度 16+4
unsigned char key_length = 36;  //自定义密钥长度 32+4
unsigned char cmd_encrypt[6] = {0xAA,0xC3,0x00,0xA1,0x00,0x14}; //加密cmd
unsigned char cmd_decrypt[6] = {0xAA,0xC3,0x01,0xA1,0x00,0x14}; //解密cmd
unsigned char key[32] = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10}; //密钥
unsigned char encrypt_data[16] = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10}; //加密数据
unsigned char decrypt_data[16] = {}; //解密数据
unsigned char cmd_result[2] = {0x00}; //命令接收状态
unsigned char result_len[2] = {0x00}; //接收数据长度  对应Result_SW
unsigned char result[100]; //接收返回数据 足够长
unsigned char Crc[4] = {0};

int test_1 = 0;

void main(void)
{

   //无中断无FIFO模式、LOOPBACK模式禁用、软件片选、波特率115200
    Ready_Config();
    //Uint16 sdata;  //send data
    //Uint16 rdata;  // received data


// Step 1. Initialize System Control:
// PLL, WatchDog, enable Peripheral Clocks
// This example function is found in the F2837xS_SysCtrl.c file.
   InitSysCtrl();

// Step 2. Initialize GPIO:
// This example function is found in the F2837xS_Gpio.c file and
// illustrates how to set the GPIO to it's default state.
   InitGpio();  // Skipped for this example
// Setup only the GP I/O only for SPI-A functionality
// This function is found in F2837xS_Spi.c
   InitSpiaGpio();

// Step 3. Clear all __interrupts and initialize PIE vector table:
// Disable CPU __interrupts
   DINT;

// Initialize PIE control registers to their default state.
// The default state is all PIE __interrupts disabled and flags
// are cleared.
// This function is found in the F2837xS_PieCtrl.c file.
   InitPieCtrl();

// Disable CPU __interrupts and clear all CPU __interrupt flags:
   IER = 0x0000;
   IFR = 0x0000;

// Initialize the PIE vector table with pointers to the shell Interrupt
// Service Routines (ISR).
// This will populate the entire table, even if the __interrupt
// is not used in this example.  This is useful for debug purposes.
// The shell ISR routines are found in F2837xS_DefaultIsr.c.
// This function is found in F2837xS_PieVect.c.
   InitPieVectTable();

// Step 4. Initialize the Device Peripherals:
   //spi_fifo_init();     // Initialize the Spi FIFO
   InitSpi();        // init SPI
   if(1)  //1可改为密钥加载条件判断语句
   {
       CRC32_MPEG_2(key,data_length,Crc);  //软件生成CRC校验码
       SPI_TXbuff(cmd_loadkey,6);  //装载密钥指令发送给加密芯片
       DELAY_US(10);
       //delay_loop();
      // while(SpiaRegs.SPIFFRX.bit.RXFFST !=1) { } //等待FIFO里面有数据
       SPI_RXbuff(cmd_result,2);  //接收加密芯片返回的指令接收状态
       DELAY_US(10);
       //delay_loop();
       SPI_TXbuff(key,32);
       DELAY_US(10);
       //delay_loop();
       SPI_TXbuff(Crc,4);
     //  while(SpiaRegs.SPIFFRX.bit.RXFFST !=1) { }
       SPI_RXbuff(result_len, 2);
   }
   if(cmd_result[0] == 0x9A && cmd_result[1] == 0x00)  //测试加密芯片是否成功接收密钥装载指令 cmd_result是否为正常的9A00（十六进制）
   {
       if(result_len[0] == 0x90 && result_len[1] == 0x00)  //测试result_len是否正常返回返回值9000（十六进制）
       {
          test_1 = 1 ;
       }
       else
       {
          test_1 = 2;
       }
   }
   else
   {
       test_1 = 3;
   }
// Step 5. User specific code:
// Interrupts are not used in this example.
   //sdata = 0x0000;    // ReceivedChar = SciaRegs.SCIRXBUF.all;把sdata改成receivedchar
 //  for(;;)  //循环，对应stm32程序中的while(1)循环
 //  {
     // Transmit data
     //spi_xmit(sdata);

     // Wait until data is received 相当于RXflag==1
  //   while(SpiaRegs.SPIFFRX.bit.RXFFST !=1) { }
     // Check against sent data
 //    rdata = SpiaRegs.SPIRXBUF;
 //    if(rdata != sdata) error();// scia_xmit(ReceivedChar);
 //    sdata++;  //可替换为loopcount
  // }
}

// Step 7. Insert all local Interrupt Service Routines (ISRs) and functions here:

void delay_loop()
{
    long      i;
    for (i = 0; i < 1000000; i++) {}
}

void error(void)
{
    asm("     ESTOP0");                     // Test failed!! Stop!
    for (;;);
}

//void spi_init()
//{
    //原例程配置
    //SpiaRegs.SPICCR.all =0x000F;               // Reset on, rising edge, 16-bit char bits
    //SpiaRegs.SPICCR.bit.SPICHAR = 7;             //设置输出数据长度为一次输出8位
    //SpiaRegs.SPICTL.all =0x0006;               // Enable master mode, normal phase,
                                                 // enable talk, and SPI int disabled.
    //SpiaRegs.SPIBRR.all =0x007F;
    //SpiaRegs.SPICCR.all =0x009F;               // Relinquish SPI from Reset
    //SpiaRegs.SPICCR.bit.SPICHAR = 7;             //设置输出数据长度为一次输出8位
    //SpiaRegs.SPIPRI.bit.FREE = 1;                // Set so breakpoints don't disturb xmission

    //SpiaRegs.SPICCR.bit.SPISWRESET = 0;//软件复位SPI
    //配置
    //SpiaRegs.SPICCR.all = 0x0007;//数据长度为8位；禁止Loopback模式；CPOL:0 CPHA:0（同时，SpiaRegs.SPICTL.bit.3 位，即CLOCK PHASE位在这里要为0）
    //SpiaRegs.SPICTL.all = 0x0016;//禁用SPI中断；使能发送；主模式,使能超时中断
    //SpiaRegs.SPISTS.all=0;//各种标志位被置0
    //SpiaRegs.SPIBRR.all = 31;//设置波特率，即LSPCK/32,32分频
    //
    //SpiaRegs.SPICCR.bit.SPISWRESET = 1;//重新使能SPI
//}

void spi_xmit(Uint16 a)
{
    while(SpiaRegs.SPISTS.bit.BUFFULL_FLAG);  //问题1 标志位 源自[参考译文] TMS320F2808：不同的晶振会导致 SPI 发送的数据出现异常。
    //Uint16 a1 = (Uint16)a << 8;
    SpiaRegs.SPITXBUF=a;    // SPI Serial Output Buffer Register
    //while(SpiaRegs.SPISTS.bit.INT_FLAG != 1);//
}

void spi_fifo_init()
{
 //Initialize SPI FIFO registers
  SpiaRegs.SPIFFTX.all=0xE040;
  SpiaRegs.SPIFFRX.all=0x2044;
  SpiaRegs.SPIFFCT.all=0x0;
}

//Ready信号接收引脚设置为GPIO10
void Ready_Config()
{
     EALLOW;
     GpioCtrlRegs.GPAMUX1.bit.GPIO10 = 0; //i/o
    // GpioCtrlRegs.GPAPUD.bit.GPIO10 = 0; //内部上拉
     GpioCtrlRegs.GPADIR.bit.GPIO10 = 0; //input
     EDIS;
}


//接收缓冲区数据函数
void SPI_RXbuff(unsigned char *buff,unsigned int len)  //uint8_t uint32_t
{
    unsigned int i = 0;
    if(len==0)  return;
    while(GpioDataRegs.GPADAT.bit.GPIO10 == 0);//等待从机就绪
    GpioDataRegs.GPACLEAR.bit.GPIO11 = 1; //拉低片选信号
    DELAY_US(10);
    for(i=0;i<len;i++)
    {
         buff[i] = (SpiaRegs.SPIRXBUF>>8);
         //delay_loop();
         DELAY_US(10);
     }
    GpioDataRegs.GPASET.bit.GPIO11 = 1;//拉高片选信号
}

//发送缓冲区数据函数
void SPI_TXbuff(unsigned char *buff,unsigned int len)  //uint8_t uint32_t
{
    unsigned int i = 0;
    if(len==0)  return;
    while(GpioDataRegs.GPADAT.bit.GPIO10 == 0);//等待从机就绪
    GpioDataRegs.GPACLEAR.bit.GPIO11 = 1; //拉低片选信号
    DELAY_US(10);
    for(i=0;i<len;i++)
    {
        spi_xmit((Uint16)buff[i]<<8);  //左移8位，适应MSB的要求
        //delay_loop();
        DELAY_US(10);  //延时问题
     }
    GpioDataRegs.GPASET.bit.GPIO11 = 1;//拉高片选信号
}

//CRC32校验函数
/***
               描述：
        CRC32_ MPEG_2校验和计算软件实现
                参数：
        data: [输入]，计算 CRC32 的数据缓存地址指针
        length: [输入]，用于计算CRC32的数据长度
        r_buf: [输出]，按字节输出的CRC32校验和计算结果
                返回结果：
                按int型输出的CRC32校验和结果
***/
int CRC32_MPEG_2(const unsigned short int *data,int length,unsigned short int r_buf[])  //原const unsigned char *data,int length,unsigned char r_buf[]
{
    unsigned char i;
    int CRC32 = 0xFFFFFFFF, j = 0;
    while ((length--) != 0)
    {
       CRC32 ^= (unsigned int)data[j] << 24;  //uint32_t
       j++;
       for (i = 0; i < 8; ++i)
       {
          if ((CRC32 & 0x80000000) != 0)
          CRC32 = (CRC32 << 1) ^ 0x04C11DB7;
          else
          CRC32 <<= 1;
        }
     }
     for(i=0; i<4; i++)
     {
        r_buf[3-i] = (CRC32>>(8*i))&0xFF;
      }
     return CRC32;
}
//#include "F28x_Project.h"

//
// Function Prototypes
//
//void delay_loop(void);
//void spi_xmit(Uint16 a);
//void spi_fifo_init(void);
//void spi_init(void);
//void error(void);


//void main(void)
//{
   //Uint16 sdata;  // send data
  // Uint16 rdata;  // received data

//
// Step 1. Initialize System Control:
// PLL, WatchDog, enable Peripheral Clocks
// This example function is found in the F2837xD_SysCtrl.c file.
//
  // InitSysCtrl();

//
// Step 2. Initialize GPIO:
// This example function is found in the F2837xD_Gpio.c file and
// illustrates how to set the GPIO to it's default state.
// Setup only the GP I/O only for SPI-A functionality
// This function is found in F2837xD_Spi.c
//
  // InitSpiaGpio();

//
// Step 3. Clear all interrupts:
//
 //  DINT;

//
// Initialize PIE control registers to their default state.
// The default state is all PIE __interrupts disabled and flags
// are cleared.
// This function is found in the F2837xD_PieCtrl.c file.
//
  // InitPieCtrl();

//
// Disable CPU __interrupts and clear all CPU __interrupt flags:
//
  // IER = 0x0000;
   //IFR = 0x0000;

//
// Initialize the PIE vector table with pointers to the shell Interrupt
// Service Routines (ISR).
// This will populate the entire table, even if the __interrupt
// is not used in this example.  This is useful for debug purposes.
// The shell ISR routines are found in F2837xD_DefaultIsr.c.
// This function is found in F2837xD_PieVect.c.
//
  // InitPieVectTable();

//
// Step 4. Initialize the Device Peripherals:
//
//   spi_fifo_init();     // Initialize the SPI FIFO
  // InitSpi();
//
// Step 5. User specific code:
//
// sdata = 0x0100;
   
//   for(;;)
//   {
        //
        // Transmit data
        //
//        spi_xmit(sdata);

        //
        // Wait until data is received
        //
        //while(SpiaRegs.SPIFFRX.bit.RXFFST !=1) { }

        //
        // Check against sent data
        //
//        rdata = SpiaRegs.SPIRXBUF;
//        if(rdata != sdata)
 //       {
//            error();
  //      }
  //      sdata++;
  // }
//}

//
// delay_loop - Loop for a brief delay
//
//void delay_loop()
//{
 //   long i;
 //   for (i = 0; i < 1000000; i++) {}
//}

//
// error - Error function that halts the debugger
//
//void error(void)
//{
   // asm("     ESTOP0");     // Test failed!! Stop!
    //for (;;);
//}

//
// spi_xmit - Transmit value via SPI
//
//void spi_xmit(Uint16 a)
//{
   // SpiaRegs.SPITXBUF = a;
//}

//
// spi_fifo_init - Initialize SPIA FIFO
//
//void spi_fifo_init()
//{
    //
    // Initialize SPI FIFO registers
    //
   // SpiaRegs.SPIFFTX.all = 0xE040;
  //  SpiaRegs.SPIFFRX.all = 0x2044;
   // SpiaRegs.SPIFFCT.all = 0x0;

    //
    // Initialize core SPI registers
    //
  //  InitSpi();
//}

//
// End of file
//
