/// \file console.h This file demonstrates the simplicity of defining a custom console under VSOS03.
#include <vsos.h>
//#include "consoleops.h"
#include <vs1005h.h>
#include <stdio.h>
#include <vo_gpio.h>
#include <timers.h>
#include <clockspeed.h>
#include <ringbuf.h>
#include "spi1con.h"

extern VO_FILE *orig_stdout;

void SetSPI1(register u_int32 uartSpeedHz) {
  u_int16 div = (u_int16)(clockSpeed.cpuClkHz / uartSpeedHz + 1) / 2;

  if (div > 255) {
    fprintf(orig_stdout, "W: Illegal divider %d!\n", div);
    div = 255;
  }

  PERIP(SPI1_CF) = (10 << SPI_CF_DLEN_B) | SPI_CF_MASTER | SPI_CF_FSIDLE;
  PERIP(SPI1_CLKCF) = ((div-1) << 2);
  PERIP(SPI1_FSYNC) = 0xFFFF;
  GpioSetAsPeripheral(0x17); //MOSI1
  //	GpioSetAsPeripheral(0x14); //XCS1

  printf("SPI UART %ld bps\n", uartSpeedHz);
}

static u_int16 bitRev4[16] = {
  0b0000, 0b1000, 0b0100, 0b1100, 0b0010, 0b1010, 0b0110, 0b1110,
  0b0001, 0b1001, 0b0101, 0b1101, 0b0011, 0b1011, 0b0111, 0b1111
};



/* If one below a power of two, memory usage efficiency is best */
#define SPIUART_RX_BUFFER_SIZE (256-1)
/* If one below a power of two, memory usage efficiency is best */
#define SPIUART_TX_BUFFER_SIZE (256-1)
__mem_y char __align spiUartRxBuffer[SPIUART_RX_BUFFER_SIZE];
__mem_y char __align spiUartTxBuffer[SPIUART_TX_BUFFER_SIZE];

struct SpiUart spiUart = {
  0UL, spiUartTxBuffer, spiUartTxBuffer
};

void IntSpi1C(void) {
  while (!(PERIP(SPI1_STATUS) & SPI_ST_TXFULL) && spiUart.txWr != spiUart.txRd) {
    PERIP(SPI1_DATA) = *spiUart.txRd;
    spiUart.txRd = ringmodY(spiUart.txRd, MAKEMODF(SPIUART_TX_BUFFER_SIZE));
  }
}


void SpiUartPutChar(register char ch) {
  __mem_y char *nextTxWr = ringmodY(spiUart.txWr, MAKEMODF(SPIUART_TX_BUFFER_SIZE));
  char c = 0xFC01 | (bitRev4[ch&15] << 5) | (bitRev4[(ch>>4)&15] << 1);
	
  while (nextTxWr == spiUart.txRd) {
    Delay(1);
  }

  Disable();
  if (!(PERIP(SPI1_STATUS) & SPI_ST_TXFULL) && spiUart.txWr == spiUart.txRd) {
    PERIP(SPI1_DATA) = c;
  } else {
    *spiUart.txWr = c;
    spiUart.txWr = nextTxWr;
  }
  Enable();
}


u_int16 Spi1ConsoleWrite(register __i0 VO_FILE *self, void *buf, u_int16 sourceIndex, u_int16 bytes) {
#if 0
  SPI1Send(*((char*)buf)); //Send character to SPI1 software UART
#else
  SpiUartPutChar(*((u_int16 *)buf)); //Send character to raw UART port
#endif
};
