/*
  シリアルデバイス制御
  Satofumi KAMIMURA
  $Id: sci_init.c 286 2008-10-20 09:40:22Z satofumi $
*/

#include "sh7045lib.h"
#include "cpu_spec.h"
#include "ringBuffer.h"


#define SCI_BIT_WAIT (int)(1.0 * CPU_CLOCK / 38400.0 / 7.0)

static int Initialized = 0;
static ringBuffer_t SendRing[2];
static char SendBuf[2][SCI_BUFFER_SIZE];
static ringBuffer_t RecvRing[2];
static char RecvBuf[2][SCI_BUFFER_SIZE];


static void init_sciBuffer(void) {
  Initialized = 1;

  // 送信用のリングバッファを初期化
  initRingBuffer(&SendRing[0], &SendBuf[0][0], SCI_BUFFER_SIZE_SHIFT);
  initRingBuffer(&SendRing[1], &SendBuf[1][0], SCI_BUFFER_SIZE_SHIFT);

  // 受信用のリングバッファを初期化
  initRingBuffer(&RecvRing[0], &RecvBuf[0][0], SCI_BUFFER_SIZE_SHIFT);
  initRingBuffer(&RecvRing[1], &RecvBuf[1][0], SCI_BUFFER_SIZE_SHIFT);
}


/* シリアルデバイスの初期化 */
void init_sci(int port, int level) {
  volatile int i;

  if (!Initialized) {
    init_sciBuffer();
  }

  if (port == SCI_0) {
    /* SCI0 の初期化 */
    SCI0.SCR.BYTE = 0x00;	/* TE=0, RE=0 */
    SCI0.SMR.BYTE = 0; /* 8bit, 1stop bit, no parity, 1/1clk, TE=0, RE=0 */
    //SCI0.BRR = 22;		/* 38400 bps */
    SCI0.BRR = 7;		/* 115200 bps */
    PFC.PACRL2.WORD |= 0x0005;	/* use TXD0, RXD0 function */

  } else if (port == SCI_1) {
    /* SCI1 の初期化 */
    SCI1.SCR.BYTE = 0x00;	/* TE=0, RE=0 */
    SCI1.SMR.BYTE = 0; /* 8bit, 1stop bit, no parity, 1/1clk, TE=0, RE=0 */
    //SCI1.BRR = 22;		/* 38400 bps */
    SCI1.BRR = 7;		/* 115200 bps */
    PFC.PACRL2.WORD |= 0x0140;	/* use TXD1, RXD1 function */
  }

  for (i = 0; i < SCI_BIT_WAIT; ++i)
    ;

  if (port == SCI_0) {
    SCI0.SCR.BYTE = 0x30;
    SCI0.SSR.BYTE &= ~0x40;
    INTC.IPRF.WORD &= ~0x00f0;
    INTC.IPRF.WORD |= level << 4;
    SCI0.SCR.BYTE |= 0x40;

  } else if (port == SCI_1) {
    SCI1.SCR.BYTE = 0x30;
    SCI1.SSR.BYTE &= ~0x40;
    INTC.IPRF.WORD &= ~0x000f;
    INTC.IPRF.WORD |= level;
    SCI1.SCR.BYTE |= 0x40;
  }
}


static int getMaskLevel(int port) {
  return ((port == SCI_0) ?
	  (INTC.IPRF.WORD & 0x00f0) >> 4 : INTC.IPRF.WORD & 0x000f);
}


void stop_sci(int port) {
  unsigned int mask = get_imask();
  unsigned int level = getMaskLevel(port);

  set_imask(level);
  if (port == SCI_0) {
    INTC.IPRF.WORD &= ~0x00f0;
    SCI0.SCR.BYTE &= ~0x40;

  } else if (port == SCI_1) {
    INTC.IPRF.WORD &= ~0x000f;
    SCI1.SCR.BYTE &= ~0x40;
  }
  set_imask(mask);
}


int sci_sending(int port) {
  unsigned int mask = get_imask();
  unsigned int level = getMaskLevel(port);
  int n;

  set_imask(level);
  n = getRingFillSize(&SendRing[port]);
  set_imask(mask);

  return n;
}


/* シリアル送信 */
int sci_write(int port, const unsigned char *data, int size) {
  unsigned int mask = get_imask();
  unsigned int level = getMaskLevel(port);
  int i;

  // 送信バッファにデータを配置
  for (i = 0; i < size; ++i) {
    int ret;
    set_imask(level);
    ret = putRingBuffer(&SendRing[port], data[i]);
    set_imask(mask);
    if (ret < 0) {
      break;
    }
  }

  // 送信割り込みの許可
  set_imask(level);
  if (port == SCI_0) {
    SCI0.SCR.BYTE |= 0x80;
  } else if (port == SCI_1) {
    SCI1.SCR.BYTE |= 0x80;
  }
  set_imask(mask);

  return i;
}


/* シリアル受信 */
int sci_read(int port, unsigned char *data, int size) {
  unsigned int imask = get_imask();
  unsigned int level = getMaskLevel(port);
  int filled = 0;
  char ch;

  while (filled < size) {
    set_imask(level);
    if (getRingBuffer(&RecvRing[port], &ch) >= 0) {
      data[filled++] = ch;
    }
    set_imask(imask);
  }
  return size;
}


int sci_copy(int port, unsigned char *data, int size) {
  unsigned int imask = get_imask();
  unsigned int level = getMaskLevel(port);
  int readable_num;
  int n;

  set_imask(level);
  readable_num = get_sciReadable(port);
  n = (readable_num < size) ? readable_num : size;
  getRingBufferCopy(data, &RecvRing[port], n);
  set_imask(imask);

  return n;
}


int get_sciReadable(int port) {
  unsigned int imask = get_imask();
  unsigned int level = getMaskLevel(port);
  int fill_size;

  set_imask(level);
  fill_size = getRingFillSize(&RecvRing[port]);
  set_imask(imask);

  return fill_size;
}


void flush_sciRecv(int port) {
  unsigned int imask = get_imask();
  unsigned int level = getMaskLevel(port);

  set_imask(level);
  clearRingBuffer(&RecvRing[port]);
  set_imask(imask);
}


#pragma interrupt
void txi0(void) {
  char ch;

  if (getRingBuffer(&SendRing[0], &ch) < 0) {
    SCI0.SCR.BYTE &= ~0x80;     /* 送信終了。以後の送信割り込みを禁止 */
  } else {
    SCI0.TDR = ch;
    SCI0.SSR.BYTE &= ~0x80;     /* 割り込みフラグをクリア */
  }
}


#pragma interrupt
void txi1(void) {
  char ch;

  if (getRingBuffer(&SendRing[1], &ch) < 0) {
    SCI1.SCR.BYTE &= ~0x80;     /* 送信終了。以後の送信割り込みを禁止 */
  } else {
    SCI1.TDR = ch;
    SCI1.SSR.BYTE &= ~0x80;     /* 割り込みフラグをクリア */
  }
}


#pragma interrupt
void tei0(void) {
}

#pragma interrupt
void tei1(void) {
}


#pragma interrupt
void rxi0(void) {
  putRingBuffer(&RecvRing[0], SCI0.RDR);
  SCI0.SSR.BYTE &= ~0x40;	/* 割り込みフラグのクリア */
}

#pragma interrupt
void rxi1(void) {
  putRingBuffer(&RecvRing[1], SCI1.RDR);
  SCI1.SSR.BYTE &= ~0x40;	/* 割り込みフラグのクリア */
}


#pragma interrupt
void eri0(void) {
}

#pragma interrupt
void eri1(void) {
}
