#include "f38x_spi.h"

u8 spi_ckr(u8 new_value){
  u8 old_value = SPI0CKR;
  SPI0CKR = new_value;
  return old_value;
}

/**
 * Configure SPI0 for 8-bit, 400KHz SCK, Master mode, polled operation, data
 * sampled on 1st SCK rising edge.
 * 
 */
void spi_init(){
  /*
   * data sampled on rising edge, clk active low,
   * 8-bit data words, master mode;
   */
  SPI0CFG = 0x70;
  
  // 4-wire mode; SPI enabled; flags cleared
  SPI0CN = 0x0F;
  
  // SPI clock = 400K
  spi_clock(400);
}

#if !defined(SPI_DEBUG_BIT_BANG)
/**
 * Function sends one byte to spi and reads ony byte from spi
 * it will be written with SYSCLK as clk
 * 
 * @param byte value to write
 * @return SPI byte
 */
unsigned char spi_write_read_byte(unsigned char byte){
  SPI0DAT = byte;
  while(!SPIF);
  SPIF = 0;
  return SPI0DAT;
}

void spi_read(unsigned char * pchar, unsigned int length){
  while(length--){
    SPI0DAT = 0xFF;
    while(!SPIF);
    SPIF = 0;
    *(pchar++) = SPI0DAT;
  }
}

void spi_write(unsigned char * pchar, unsigned int length){
  while(length--){
    SPI0DAT = *(pchar++);
    while(!SPIF);
    SPIF = 0;
  }
}

#else

#ifdef USE_ASM_FOR_SFR_MANIP
#define clk_up()      {__asm orl _P0,SHARP  0x01 __endasm; }
#define clk_down()    {__asm anl _P0,SHARP ~0x01 __endasm; }
#define out_up()      {__asm orl _P0,SHARP  0x04 __endasm; }
#define out_down()    {__asm anl _P0,SHARP ~0x04 __endasm; }
#else
#define clk_up()      (P0 |=  0x01)
#define clk_down()    (P0 &= ~0x01)
#define out_up()      (P0 |=  0x04)
#define out_down()    (P0 &= ~0x04)
#endif
#define is_in_up()    (P0 & 0x02)
#define clk_wait()

unsigned char spi_write_read_byte(unsigned char byte){
  u8 temp = 0;
  u8 mask = 0x80;
  do{
    clk_down();
    if(byte & mask){out_up();}else{out_down();}
    clk_wait();
    clk_up();
    if(is_in_up()) temp |= mask;
    clk_wait();
  }while(mask >>= 1);
  return temp;
}

void spi_read(unsigned char *buf, unsigned int size){
  for(; size--; buf++){
    u8 temp = 0;
    u8 mask = 0x80;
    do{
      clk_down();
      clk_wait();
      clk_up();
      if(is_in_up()) temp |= mask;
      clk_wait();
    }while(mask >>= 1);
    *buf = temp;
  }
}

void spi_write(unsigned char *buf, unsigned int size){
  for(; size--; buf++){
    u8 mask = 0x80;
    do{
      clk_down();
      if((*buf) & mask){out_up();}else{out_down();}
      clk_wait();
      clk_up();
      clk_wait();
    }while(mask >>= 1);
  }
}

#endif