/******************************************************************************
文 件 名：SPI_Master.c
功能描述：SPI 主机模式驱动库文件
作    者：张暄
版    本：V1.0
日    期：2017.04.02
******************************************************************************/

#include "SPI_Master.h"

SPIDataBlockStruct      SPIDataBlock;

/******************************************************************************
函数名：SPI_Master_Start
功  能：初始化并启动SPI主机模式
参  数：Mode：SPI工作模式：         SPI_MODE_0
                                    SPI_MODE_1
                                    SPI_MODE_2
                                    SPI_MODE_3

        FirstBit：首先发送的数据位：SPI_MSB_FIRST
                                    SPI_LSB_FIRST
返回值：无
******************************************************************************/
void SPI_Master_Start(uint8_t Mode, uint8_t FirstBit)
{
  SPICR1  = 0x00;

  PTSRR  &= 0xCF;
  PTSRR  |= SPI_GPIO_SELECT;

  SPIBR   = 0x32;                 //Baud Rate = BUSCLK / ((3 + 1) * 2 ^ (2 + 1)) = 1000000

  SPICR2 &= 0x40;

  SPICR1  = 0x50 | Mode | FirstBit;
}

/******************************************************************************
函数名：SPI_Master_Stop
功  能：关闭SPI功能
参  数：无
返回值：无
******************************************************************************/
void SPI_Master_Stop(void)
{
  SPICR1 &= 0x1D;                 //关闭SPI
}

/******************************************************************************
函数名：SPI_Master_Get_Write_Status
功  能：获取当前写入状态
参  数：无
返回值：SPI_WRITE_COMPLETE    ：数据写入完成
        SPI_WRITE_NOT_COMPLETE：数据写入未完成
******************************************************************************/
uint8_t SPI_Master_Get_Write_Status(void)
{
  if (SPIDataBlock.Status != SPI_DATA_BLOCK_IDLE)
    return SPI_WRITE_NOT_COMPLETE;

  if (SPISR_SPIF)
    return SPI_WRITE_COMPLETE;

  return SPI_WRITE_NOT_COMPLETE;
}

/******************************************************************************
函数名：SPI_Master_Byte_Write
功  能：向SPI总线上写一字节
参  数：Data:要写入的数据
返回值：SPI_WRITE_COMPLETE：数据成功写入
        SPI_UNWRITABLE    ：当前不可写入
******************************************************************************/
uint8_t SPI_Master_Byte_Write(uint8_t Data)
{
  if (SPIDataBlock.Status != SPI_DATA_BLOCK_IDLE)
    return SPI_UNWRITABLE;

  if (SPISR_SPTEF)                //数据寄存器为空时方可写入
  {
    SPICR2 &= 0xBF;               //启动8位传输
    SPIDRL = Data;
    return SPI_WRITE_COMPLETE;
  }

  return SPI_UNWRITABLE;
}

/******************************************************************************
函数名：SPI_Master_Byte_Read_Req
功  能：请求在SPI总线上读取一字节数据
参  数：无
返回值：SPI_READ_REQ_COMPLETE：读取请求成功
        SPI_READ_NOT_COMPLETE：读取失败
******************************************************************************/
uint8_t SPI_Master_Byte_Read_Req(void)
{
  uint8_t Data;

  if (SPIDataBlock.Status != SPI_DATA_BLOCK_IDLE)
    return SPI_READ_NOT_COMPLETE;

  if (SPISR_SPIF)
    Data = SPIDRL;                //接收寄存器不为空则清空接收寄存器

  if (SPISR_SPTEF)                //数据寄存器为空时方可写入
  {
    SPICR2 &= 0xBF;               //启动8位传输
    SPIDRL = SPI_DUMMY_BYTE;
    return SPI_READ_REQ_COMPLETE;
  }

  return SPI_READ_NOT_COMPLETE;
}

/******************************************************************************
函数名：SPI_Master_Get_Read_Byte
功  能：获取在SPI总线上读出的一字节数据
参  数：pData：用于存储读出数据的变量
返回值：SPI_READ_COMPLETE    ：读取成功
        SPI_READ_NOT_COMPLETE：读取失败
******************************************************************************/
uint8_t SPI_Master_Get_Read_Byte(uint8_t *pData)
{
  if (SPIDataBlock.Status != SPI_DATA_BLOCK_IDLE)
    return SPI_READ_NOT_COMPLETE;

  if (SPISR_SPIF)
  {
    *pData = SPIDRL;
    return SPI_READ_COMPLETE;
  }

  return SPI_READ_NOT_COMPLETE;
}

/******************************************************************************
函数名：SPI_Master_Word_Write
功  能：向SPI总线上写一个字(16bit)
参  数：Data:要写入的数据
返回值：SPI_WRITE_COMPLETE：数据成功写入
        SPI_UNWRITABLE    ：当前不可写入
******************************************************************************/
uint8_t SPI_Master_Word_Write(uint16_t Data)
{
  if (SPIDataBlock.Status != SPI_DATA_BLOCK_IDLE)
    return SPI_UNWRITABLE;

  if (SPISR_SPTEF)                //数据寄存器为空时方可写入
  {
    SPICR2 |= 0x40;               //启动16位传输
    SPIDR = Data;
    return SPI_WRITE_COMPLETE;
  }

  return SPI_UNWRITABLE;
}

/******************************************************************************
函数名：SPI_Master_Word_Read_Req
功  能：请求在SPI总线上读取一个字(16bit)的数据
参  数：无
返回值：SPI_READ_REQ_COMPLETE：读取请求成功
        SPI_READ_NOT_COMPLETE：读取失败
******************************************************************************/
uint8_t SPI_Master_Word_Read_Req(void)
{
  uint16_t Data;

  if (SPIDataBlock.Status != SPI_DATA_BLOCK_IDLE)
    return SPI_READ_NOT_COMPLETE;

  if (SPISR_SPIF)
    Data = SPIDR;                 //接收寄存器不为空则清空接收寄存器

  if (SPISR_SPTEF)                //数据寄存器为空时方可写入
  {
    SPICR2 |= 0x40;               //启动16位传输
    SPIDR = SPI_DUMMY_WORD;
    return SPI_READ_REQ_COMPLETE;
  }

  return SPI_READ_NOT_COMPLETE;
}

/******************************************************************************
函数名：SPI_Master_Get_Read_Word
功  能：获取在SPI总线上读出的一个字(16bit)的数据
参  数：pData：用于存储读出数据的变量
返回值：SPI_READ_COMPLETE    ：读取成功
        SPI_READ_NOT_COMPLETE：读取失败
******************************************************************************/
uint8_t SPI_Master_Get_Read_Word(uint16_t *pData)
{
  if (SPIDataBlock.Status != SPI_DATA_BLOCK_IDLE)
    return SPI_READ_NOT_COMPLETE;

  if (SPISR_SPIF)
  {
    *pData = SPIDR;
    return SPI_READ_COMPLETE;
  }

  return SPI_READ_NOT_COMPLETE;
}

/******************************************************************************
函数名：SPI_Master_Block_Write
功  能：向SPI总线上写一个数据块
参  数：pData：要写入的数据块
        Len  ：数据块长度
返回值：SPI_WRITE_COMPLETE：数据成功写入
        SPI_UNWRITABLE    ：当前不可写入
******************************************************************************/
uint8_t SPI_Master_Block_Write(uint8_t *pData, uint8_t Len)
{
  uint8_t i;

  if (SPIDataBlock.Status != SPI_DATA_BLOCK_IDLE)
    return SPI_UNWRITABLE;        //如果有读写正在进行则中止写入

  if ((Len == 0) || (Len > SPI_DATA_BUFFER_SIZE))
    return SPI_UNWRITABLE;

  SPIDataBlock.Ptr = 0;
  SPIDataBlock.ReadComplete = 0;  //数据被覆盖,清零标志
  SPIDataBlock.Len = Len;
  for (i = 0; i < Len; i++)
    SPIDataBlock.Data[i] = pData[i];

  if (SPISR_SPTEF == 0)           //存储器非空状态不可写入
    return SPI_UNWRITABLE;

  SPIDataBlock.Status = SPI_DATA_BLOCK_WRITE;

  SPICR1 |= 0x20;                 //开启发送中断
  SPICR2 &= 0xBF;                 //启动8位传输
  SPIDRL = SPIDataBlock.Data[SPIDataBlock.Ptr];

  return SPI_WRITE_COMPLETE;
}

/******************************************************************************
函数名：SPI_Master_Block_Read_Req
功  能：请求在SPI总线上读取一个数据块
参  数：Len：数据块的长度
返回值：SPI_READ_REQ_COMPLETE：读取请求成功
        SPI_READ_NOT_COMPLETE：读取失败
******************************************************************************/
uint8_t SPI_Master_Block_Read_Req(uint8_t Len)
{
  uint8_t Data;

  if (SPIDataBlock.Status != SPI_DATA_BLOCK_IDLE)
    return SPI_READ_NOT_COMPLETE; //如果有读写正在进行则中止读取

  if ((Len == 0) || (Len > SPI_DATA_BUFFER_SIZE))
    return SPI_READ_NOT_COMPLETE;

  if (SPISR_SPTEF == 0)           //存储器非空状态不可写入
    return SPI_READ_NOT_COMPLETE;

  if (SPISR_SPIF)
    Data = SPIDRL;                //接收寄存器不为空则清空接收寄存器

  SPIDataBlock.Status = SPI_DATA_BLOCK_READ;
  SPIDataBlock.Ptr = 0;
  SPIDataBlock.ReadComplete = 0;
  SPIDataBlock.Len = Len;

  SPICR1 |= 0x80;                 //开启接收中断
  SPICR2 &= 0xBF;                 //启动8位传输
  SPIDRL = SPI_DUMMY_BYTE;

  return SPI_READ_REQ_COMPLETE;
}

/******************************************************************************
函数名：SPI_Master_Get_Read_Block
功  能：获取在SPI总线上读出的数据块
参  数：pData：读出的数据块存储地址
        Len：数据块长度
返回值：SPI_READ_COMPLETE    ：读取成功
        SPI_READ_NOT_COMPLETE：读取失败
******************************************************************************/
uint8_t SPI_Master_Get_Read_Block(uint8_t *pData, uint8_t Len)
{
  uint8_t i;

  if (SPIDataBlock.Status != SPI_DATA_BLOCK_IDLE)
    return SPI_READ_NOT_COMPLETE;

  if (SPIDataBlock.ReadComplete)
  {
    SPIDataBlock.ReadComplete = 0;
    for (i = 0; i < Len; i++)
      pData[i] = SPIDataBlock.Data[i];

    return SPI_READ_COMPLETE;
  }

  return SPI_READ_NOT_COMPLETE;
}

/******************************************************************************
函数名：SPI_Master_Block_Transmit_ISR
功  能：数据块传输完成中断函数,于整个数据块传输完成后由中断调用
参  数：无
返回值：无
******************************************************************************/
#if SPI_CALL_DATA_BLOCK_TX_ISR
void SPI_Master_Block_Transmit_ISR(void)
{

}
#endif

#pragma CODE_SEG __NEAR_SEG NON_BANKED   	//置所有中断函数放在FLASH的非分页区

/******************************************************************************
函数名：SPI_ISR
功  能：SPI中断服务函数,用于收发数据
参  数：无
返回值：无
******************************************************************************/
void interrupt SPI_ISR(void)
{
  if (SPIDataBlock.Status == SPI_DATA_BLOCK_WRITE)
  {
    if (SPISR_SPTEF)
    {
      SPIDataBlock.Ptr++;
      if (SPIDataBlock.Ptr < SPIDataBlock.Len)
        SPIDRL = SPIDataBlock.Data[SPIDataBlock.Ptr];
      else
      {
        SPICR1 &= 0xDF;                 //关闭发送中断
        SPIDataBlock.Status = SPI_DATA_BLOCK_IDLE;
#if SPI_CALL_DATA_BLOCK_TX_ISR
        SPI_Master_Block_Transmit_ISR();
#endif
      }
    }
  }
  else if (SPIDataBlock.Status == SPI_DATA_BLOCK_READ)
  {
    if (SPISR_SPIF)
    {
      SPIDataBlock.Data[SPIDataBlock.Ptr] = SPIDRL;
      SPIDataBlock.Ptr++;
      if (SPIDataBlock.Ptr < SPIDataBlock.Len)
        SPIDRL = SPI_DUMMY_BYTE;
      else
      {
        SPICR1 &= 0x7F;                 //关闭接收中断
        SPIDataBlock.Status = SPI_DATA_BLOCK_IDLE;
        SPIDataBlock.ReadComplete = 1;  //置接收完成标志
      }
    }
  }
  else
  {
    if (SPISR_MODF)
      SPICR1 &= 0x7F;                   //关闭SPI中断
  }
}

#pragma CODE_SEG DEFAULT
