#include <cstdio>
#include <windows.h>
#include "c232comm.h"
#include "CRIO.h"


static int RIOLengths[] = {
	0,		// 0.CheckRequest
	0,		// 1.VersionRequest
	0,		// 2.AnalogRequest
	1,		// 3.ResetRequest
	2,		// 4.LampRequest
	2,		// 5.CheckReply
	2,		// 6.VersionReply
	10,		// 7.AnalogReply
	1,		// 8.ButtonPressed
	1,		// 9.ButtonReleased
	2,		// 10.KeyPressed
	2,		// 11.KeyReleased
	1		// 12.TestModeChange
};

static const char* RIOPackets[] = {
	"CheckRequest",
	"VersionRequest",
	"AnalogRequest",
	"ResetRequest",
	"LampRequest",
	"CheckReply",
	"VersionReply",
	"AnalogReply",
	"ButtonPressed",
	"ButtonReleased",
	"KeyPressed",
	"KeyReleased",
	"TestModeChange",
};

void CRIO::Init ()
{
	m_pStart		= &m_ba[0];
	m_pEnd			= &m_ba[sizeof (m_ba)];
	m_nCount		= 0;
	m_dwFlags		= 0;
	m_nState		= 0;
	m_nRead			= 0;
	m_nLeft			= 0;
	m_bCheck		= 0;
    m_nReplies		= 0;
	TestModeActive	= 0;
	m_dwAnalogRequest = 0;
}

void CRIO::RIOBordState (BYTE ID)
{
	switch (ID)
	{
	case BoardMissing:
		break;
	case BoardBad:
		break;
	case LampBad:
		break;
	case RestartCount:
		break;
	case AbandonCount:
		break;
	case FullBufferCount:
		break;
	}	
}

void CRIO::DoEventLoop()
{
    CString		str, temp;
	BYTE		baBuffer[256];
	int			nRet = -1;

    if (IsValid()) {
		memset (baBuffer, 0, sizeof(baBuffer));		
        nRet = rxCom (&baBuffer[0], sizeof(baBuffer));

        if (nRet > 0) {
			EventLoop (baBuffer, nRet);
        } else {
        }
		CheckAnalogRequest();
    } else {
    }
    while(m_ListBox.GetCount() > 40) {
        m_ListBox.DeleteString(0);
    }
}

void CRIO::EventLoop(const BYTE *buf, int nLen)
{
	int		nNewLen;
	BYTE	*pIndex;

	CString strText;

	nNewLen = m_nCount + nLen;
	pIndex	= &m_pStart[nNewLen];

	if (pIndex > m_pEnd) {
		if (m_nCount > 0) {
			memcpy (&m_ba[0], m_pStart, m_nCount);
		}
		m_pStart = &m_ba[0];
	}

	memcpy (&m_pStart[m_nCount], &buf[0], nLen);
	m_nCount += nNewLen;

	while (m_nCount > 0)
	{
		BYTE bCmd = m_pStart[0];

		switch (bCmd)
		{
		case IDLE_CHAR:
			m_ListBox.AddString("IDLE");
			break;

		case ACK_CHAR:
			m_dwFlags |= RX_ACK_BIT;
			m_ListBox.AddString("ACK");
			break;

		case NAK_CHAR:
			m_dwFlags |= RX_NAK_BIT;			
			m_ListBox.AddString("NAK");
			break;

		default:
			if (m_nState) {
				if (bCmd & 0x80) {
					m_nState = 0;
					if (bCmd == RESTART_CHAR) {
						// discard...
						m_ListBox.AddString("DISCARD");
					} else {
						// error.
						AddReply (NAK_CHAR);
					}
				} else {
					if (m_nLeft > 0) {
						m_baRead[m_nRead++] = bCmd;
						m_bCheck += bCmd;
						m_nLeft--;
					} else {
						MSBOFF (m_bCheck);						
						m_nState = 0;
						if (bCmd == m_bCheck) {
							// chechsum OK.
							AddReply (ACK_CHAR);
#ifdef TEST_RIO
	                        switch(m_baRead[0]) {
		                    case rio_CheckReply:
								strText.Format("CheckReply(%x)", m_baRead[1]);
								RIOBordState (m_baRead[1]);
			                    break;
		                    case rio_VersionReply:
								strText = "VersionReply";
			                    break;
		                    case rio_AnalogReply:
								strText = "AnalogReply";
								m_dwAnalogRequest = 0;
			                    break;
		                    case rio_ButtonPressed:
								strText.Format("[%d] 버튼눌림", m_baRead[1]);
			                    break;
		                    case rio_ButtonReleased:
								strText.Format("[%d] 버튼띰", m_baRead[1]);
			                    break;
		                    case rio_KeyPressed:
								strText = "KeyPressed";
			                    break;
		                    case rio_TestModeChange:
			                    TestModeActive = 1;
			                    if (m_baRead[1] != 0) {
			                    }
			                    else {
				                    TestModeActive = 0;
			                    }
								strText = "TestModeChange";
			                    break;
		                    default:
								strText = "Default";
			                    break;
	                        }
							m_ListBox.AddString(strText);
#else //
							//extern void RioButtonManager (BYTE *byData);
							//RioButtonManager(m_baRead);
#endif //
						} else {
							// error.
						    AddReply(NAK_CHAR);
						}
					}
				}
			} else {
				if (bCmd & 0x80) {
					if (bCmd == RESTART_CHAR) {
						// restart...
						m_ListBox.AddString("Restart");
					} else {						
						MSBOFF (bCmd);
						if (MAXLENGTH) {
							// valid command...
							m_bCheck = bCmd;
							m_baRead[0] = bCmd | 0x80;
							m_nRead = 1;
							m_nLeft = RIOLengths[bCmd];
							m_nState = 1;
						} else {
							// unknown command...
						}
					}
				} else {
					// error...
				}
			}
			break;
		}
		m_pStart++;
		m_nCount--;
	}
    CheckReplies();
}

void CRIO::AddReply (BYTE bReply)
{
//    ASSERT ((bReply == ACK_CHAR) || (bReply == NAK_CHAR));
    if (m_nReplies < (sizeof (m_baReplies) / sizeof (m_baReplies[0]))) {
        m_baReplies[m_nReplies++] = bReply;
    } else {
        // reply buffer full...
    }
}

void CRIO::CheckReplies ()
{
    if (m_nReplies > 0) {		
        int nRet = txCom (&m_baReplies, m_nReplies);
        if (nRet > 0) {
			CString str;
			str.Format(">>ACK or NAK - %d", nRet);
			m_ListBox.AddString(str);
            m_nReplies -= nRet;
            if (m_nReplies > 0) {
                memcpy (&m_baReplies[0], &m_baReplies[nRet], m_nReplies);
            } else {
//                ASSERT (m_nReplies == 0);
                m_nReplies = 0;
            }
        }
    }
}

void CRIO::CheckAnalogRequest()
{
	static BOOL s_b1st = TRUE;
	if (s_b1st) {
		s_b1st = FALSE;
	} else {
		if (m_dwAnalogRequest == 0) {
update:
			RequestAnalogUpdate();
			m_dwAnalogRequest = GetTickCount();
		} else {
			if ((m_dwAnalogRequest + 1000) < GetTickCount()) {
				goto update;
			}
		}
	}
}

void CRIO::SendCommand (const BYTE* pbPacket)
{
    BYTE ba[256];

    BYTE bCmd = *pbPacket++;

    if (bCmd & 0x80) {
		MSBOFF (bCmd);
		if (bCmd < MAXLENGTH) {
			CString str;
			str.Format(">>%s", RIOPackets[bCmd]);

            int nLeft = RIOLengths[bCmd];
            BYTE* p = &ba[0];
            BYTE bCheck = bCmd;
			MSBON (bCmd);
            *p++ = bCmd;
			
            while (nLeft > 0) {
                BYTE b = *pbPacket++;
				MSBOFF (b);
                bCheck += b;
                *p++ = b;
                nLeft--;
            }
			            
			MSBOFF (bCheck);
            *p++ = bCheck;
            SendPacket (&ba[0], p - &ba[0]);

			m_ListBox.AddString(str);
        } else {
			m_ListBox.AddString("unknown command");
		}
    } else {
        m_ListBox.AddString("error");
    }
}

void CRIO::SendPacket (const BYTE* pbPacket, int nLen)
{
    CheckReplies();
    txComLoop(pbPacket, nLen);
}

void CRIO::SetLamp(int lampNumber, int state)
{
	static BYTE	request_lamp_string[] = { rio_LampRequest, 0, 0 };

	request_lamp_string[1] = (BYTE) (lampNumber & 0x7F);
	request_lamp_string[2] = (BYTE) (state & 0x7F);	

	SendCommand (request_lamp_string);
}

void CRIO::GeneralReset()
{	
	static BYTE	request_reset_string[] = { rio_ResetRequest, 0 };
	SendCommand (request_reset_string);
}

void CRIO::ResetThrottle()
{
	static BYTE	request_throttle_string[] = { rio_ResetRequest, 1 };
	SendCommand (request_throttle_string);	
}

void CRIO::RequestCheck()
{
	static BYTE	request_check_string[] = { rio_CheckRequest };
	SendCommand (request_check_string);
}

void CRIO::RequestVersion()
{	
	static BYTE	request_version_string[] = { rio_VersionRequest };
	SendCommand (request_version_string);
}

void CRIO::RequestAnalogUpdate()
{
	static BYTE	request_analog_string[] = { rio_AnalogRequest };
	SendCommand (request_analog_string);
}