//------------------------------------------------------------------------------
//  TOPPERS/ASP Windows Debug Environment
//  Copyright (C) 2010-2013 Cores Co., Ltd. Japan
//------------------------------------------------------------------------------
// $Id: UnitSim.cs 115 2013-02-11 02:13:05Z nagasima $
#include "StdAfx.h"
#include "WinKernel.h"
#include "SifUARTC.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

extern CKernel *g_Kernel;

//------------------------------------------------------------------------------
// CSifUARTC
//	概要：
//	引数：
//	pKernel
//	戻り値：
//------------------------------------------------------------------------------
CSifUARTC::CSifUARTC(TUartCPort *reg, int txIntNo, int rxIntNo, int devNo)
{
	m_Reg = reg;
	m_TxIntNo = txIntNo;
	m_RxIntNo = rxIntNo;
	m_DevNo = devNo;
	m_Term = uctIdle;
	m_Timer = -1;
	m_Send = 0;
	//memset(m_SendBuf, 0, sizeof(m_SendBuf));
	m_SendBufPos = 0;
	m_RecvBuf = NULL;
	m_RecvBufPos = 0;

	InitializeCriticalSection(&m_Lock);
}

//------------------------------------------------------------------------------
//	概要：
//	引数：
//	戻り値：
//------------------------------------------------------------------------------
CSifUARTC::~CSifUARTC()
{
	TUARTCDataNode *Node;

	while(!m_RecvQueue.empty()){
		// 割り込み禁止
		Lock();

		// キューから次のメッセージを取得
		Node = m_RecvQueue.front();
		m_RecvQueue.pop_front();
		delete (unsigned char *)Node;

		// 割り込み許可
		Unlock();
	}

	DeleteCriticalSection(&m_Lock);
}

unsigned char CSifUARTC::GetByte2(intptr_t Index)
{
	unsigned char *Reg = (unsigned char *)m_Reg;

	// 受信バッファが読み込まれたら
	if(Index == (uintptr_t)&((TUartCPort *)0)->RX){
		if(m_RecvBuf != NULL)
		{
			Lock();
			Reg[Index] = m_RecvBuf->Data[m_RecvBufPos++];
			if(m_RecvBufPos >= m_RecvBuf->Size){
				delete (unsigned char *)m_RecvBuf;
				// キューから次のメッセージを取得
				if(m_RecvQueue.empty()){
					m_RecvBuf = NULL;
				}
				else{
					m_RecvBuf = m_RecvQueue.front();
					m_RecvQueue.pop_front();
				}
				m_RecvBufPos = 0;
			}
			Unlock();

			if(m_RecvBuf != NULL)
				g_Kernel->Interrupt(m_RxIntNo);
		}
	}
	else if(Index == (intptr_t)&((TUartCPort *)0)->STR){
		::SwitchToThread();
	}

	return Reg[Index];
}

void CSifUARTC::SetByte2(intptr_t Index, unsigned char Value)
{
	unsigned char *Reg = (unsigned char *)m_Reg;

	//Reg[Index] = Value;

	// 送信バッファに書き込まれたら
	if(Index == (intptr_t)&((TUartCPort *)0)->TX){
		m_Reg->STR.TSF = 1;
		InterlockedIncrement(&m_Send);
		g_Kernel->OnSetEvent();
	}
}

__int64 CSifUARTC::GetTimer()
{
	return m_Timer;
}

void CSifUARTC::Progress(__int64 Timer)
{
	if(m_Timer == -1)
		return;

	m_Timer -= Timer;
	if(m_Timer < 0){
		m_Timer = 0;
	}
}

void CSifUARTC::CallTimeOut(__int64 Frequency)
{
	if(((m_Term == uctIdle) || (m_Term == uctFlush)) && (m_Send != 0)){
		m_Timer = 0;
		m_Term = uctIdle;
	}

	if(m_Timer != 0)
		return;

	Lock();

	switch(m_Term){
	case uctIdle:
		m_SendBuf[m_SendBufPos++] = m_Reg->TX;
		if(m_SendBufPos == (sizeof(m_SendBuf) / sizeof(m_SendBuf[0]))){
			g_Kernel->Output(m_DevNo, m_SendBuf, sizeof(m_SendBuf));
			//memset(m_SendBuf, 0, sizeof(m_SendBuf));
			m_SendBufPos = 0;
		}
		m_Reg->STR.TSF = 0;
		m_Term = uctSending;
		m_Timer = CalcTimer(Frequency);
		break;
	case uctSending:
		if(g_Kernel->KernelFlag())
			g_Kernel->Interrupt(m_TxIntNo);
		m_Timer = 0;
		m_Term = uctWait;
		break;
	case uctWait:
		// 割り込み処理が終了するまでスレッドスイッチ
		if((g_Kernel->InterruptEnabled(m_TxIntNo) || g_Kernel->InProcIntr(m_TxIntNo)) && g_Kernel->KernelFlag()){
			m_Timer = 0;
			m_Term = uctWait;
			break;
		}
		// 送信データがなければ
		if(InterlockedDecrement(&m_Send) == 0){
			// 少し待って送信
			m_Timer = 2 * CalcTimer(Frequency);
			m_Term = uctFlush;
		}
		else{
			m_Timer = -1;
			m_Term = uctIdle;
		}
		break;
	case uctFlush:
		g_Kernel->Output(m_DevNo, m_SendBuf, m_SendBufPos);
		//memset(m_SendBuf, 0, sizeof(m_SendBuf));
		m_SendBufPos = 0;

		m_Timer = -1;
		m_Term = uctIdle;
		break;
	}

	Unlock();
}

__int64 CSifUARTC::CalcTimer(__int64 Frequency)
{
/*	__int64 bits;
	TUartCCTL0 *CTL0 = &m_Reg->CTL0;

	// データビット数
	if(CTL0->CL == 0)
		bits = 7;
	else
		bits = 8;

	// パリティありの場合
	if(CTL0->PS != 0)
		// 1bit追加
		bits += 1;

	// ストップビット数加算
	if(CTL0->SL == 0)
		bits += 1;
	else
		bits += 2;

	return (Frequency * bits * (__int64)(2 << m_Reg->CTL1.CKS) * m_Reg->CTL2.BRS) / g_Kernel->Frequency;*/
	return 1;
}

void CSifUARTC::Receive(const void *Data, int Size)
{
	TUARTCDataNode *Node = (TUARTCDataNode *)new unsigned char[sizeof(TUARTCDataNode) + Size];

	Node->Size = Size;
	memcpy(Node->Data, Data, Size);

	// 割り込み禁止
	Lock();

	if(m_RecvBuf == NULL){
		m_RecvBuf = Node;
		m_RecvBufPos = 0;

		g_Kernel->Interrupt(m_RxIntNo);
	}
	else{
		// メッセージをキューイング
		m_RecvQueue.push_back(Node);
	}

	// 割り込み許可
	Unlock();
}
