// Rs232Thread.cpp : implementation file
//

#include "stdafx.h"
#include "Rs232Thread.h"

#include "resource.h"

#include "Commport.h"
#include "Global.h"

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

HANDLE CRs232Thread::m_hEventThreadKilled;
HANDLE CRs232Thread::m_hEventThreadCreated;
HANDLE CRs232Thread::m_hEventProtocol;

/////////////////////////////////////////////////////////////////////////////
// CRs232Thread

IMPLEMENT_DYNCREATE(CRs232Thread, CWinThread)

CRs232Thread::CRs232Thread()
{
}

CRs232Thread::~CRs232Thread()
{
}

void CRs232Thread::operator delete(void* p)
{
	// The exiting main application thread waits for this event before completely
	// terminating in order to avoid a false memory leak detection. 

	CWinThread::operator delete(p);
	SetEvent(m_hEventThreadKilled);
}

BOOL CRs232Thread::InitInstance()
{
	if (m_wndRs232.Create() == FALSE)
		return FALSE;

	// It is important to set CWinThread::m_pMainWnd to the user interface
	// window.  This is required so that when the m_pMainWnd is destroyed,
	// the CWinThread is also automatically destroyed.  For insight into
	// how the CWinThread is automatically destroyed when the m_pMainWnd
	// window is destroyed, see the implementation of CWnd::OnNcDestroy
	// in wincore.cpp of the MFC sources.

	m_pMainWnd = &m_wndRs232;
	SetEvent(m_hEventThreadCreated);
	return TRUE;
}

int CRs232Thread::ExitInstance()
{
	// TODO:  perform any per-thread cleanup here
	return CWinThread::ExitInstance();
}

void CRs232Thread::PrepareEvent()
{
	m_hEventThreadKilled = CreateEvent(NULL, FALSE, FALSE, NULL); 
	m_hEventThreadCreated = CreateEvent(NULL, FALSE, FALSE, NULL); 
	m_hEventProtocol = CreateEvent(NULL, FALSE, FALSE, NULL); 
}

void CRs232Thread::UnprepareEvent()
{
	CloseHandle(m_hEventThreadKilled);
	CloseHandle(m_hEventThreadCreated);
	CloseHandle(m_hEventProtocol);
}


BEGIN_MESSAGE_MAP(CRs232Thread, CWinThread)
	//{{AFX_MSG_MAP(CRs232Thread)
		// NOTE - the ClassWizard will add and remove mapping macros here.
	//}}AFX_MSG_MAP
#if _MSC_VER >= 1300
	ON_THREAD_MESSAGE(WM_RS232_DISCONNECT, OnDisconnect)
	ON_THREAD_MESSAGE(WM_RS232_SAVING_FILE, OnSavingFile)
	ON_THREAD_MESSAGE(WM_RS232_START_DEBUG, OnStartDebug)
#else
	ON_MESSAGE(WM_RS232_DISCONNECT, OnDisconnect)
	ON_MESSAGE(WM_RS232_SAVING_FILE, OnSavingFile)
	ON_MESSAGE(WM_RS232_START_DEBUG, OnStartDebug)
#endif
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CRs232Thread message handlers

void CRs232Thread::OnDisconnect(WPARAM, LPARAM)
{
	m_wndRs232.DestroyWindow();
}

void CRs232Thread::OnSavingFile(WPARAM wParam, LPARAM lParam)
{
	BOOL bBegin = (BOOL)wParam;
	char * p = (char *)lParam;
	if (bBegin)
	{
		m_wndRs232.BeginSavingFile(p);
	}
	else
	{
		m_wndRs232.EndSavingFile();
	}
}

void CRs232Thread::OnStartDebug(WPARAM, LPARAM)
{
	m_wndRs232.StartDebug();
}

/////////////////////////////////////////////////////////////////////////////
// CRs232Wnd

CRs232Wnd::CRs232Wnd()
{
	m_bDebug = FALSE;
	m_bSavingFile = FALSE;
	m_iCountFile = 0;
	m_iCountH55 = m_iCountHaa = m_iCountHff = m_iCountH00 = 0;
	m_pEdit = NULL;
}

CRs232Wnd::~CRs232Wnd()
{
}

BOOL CRs232Wnd::Create()
{
	DWORD dwStyle = WS_POPUPWINDOW|WS_CAPTION|WS_MINIMIZEBOX; //|WS_VISIBLE 

	// Register a custom WndClass and create a window.
	// This must be done because CRs232Wnd has a custom cursor, and no icon.
	LPCTSTR lpszRs232WndClass = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW,
													LoadCursor(NULL, IDC_ARROW),
													(HBRUSH)(COLOR_WINDOW+1), NULL);

	return CWnd::CreateEx(0, lpszRs232WndClass, _T("Rs232 Output"), dwStyle,
							0, 0, 0, 0, NULL, 0);
}

void CRs232Wnd::BeginSavingFile(char * p)
{
	m_bSavingFile = TRUE;
	m_iCountFile = 0;
	m_iTotalFile = 0;
	m_pFileBuf = p;
}

void CRs232Wnd::EndSavingFile()
{
	m_bSavingFile = FALSE;
}

void CRs232Wnd::StartDebug()
{	
	HWND hWnd = GetSafeHwnd();
	LONG style = GetWindowLong(hWnd, GWL_STYLE);

	m_bDebug = TRUE;	

	style |= WS_VISIBLE;
	SetWindowLong(hWnd, GWL_STYLE, style);
	SetWindowPos(&CWnd::wndTop, 0, 0, 600, 400, SWP_SHOWWINDOW);

	m_pEdit = new CEdit();
	m_pEdit->Create(/*WS_DISABLED|*/WS_VISIBLE|WS_CHILD|WS_BORDER|WS_HSCROLL|WS_VSCROLL|ES_MULTILINE|ES_WANTRETURN,
		CRect(0, 0, 594, 375), this, IDC_RS232_EDIT);
//	m_pEdit->SetFont(GetFont());

	RedrawWindow(NULL, NULL, RDW_FRAME|RDW_INVALIDATE|RDW_ERASE|RDW_UPDATENOW);
	SetForegroundWindow();
}

BEGIN_MESSAGE_MAP(CRs232Wnd, CWnd)
	//{{AFX_MSG_MAP(CRs232Wnd)
	ON_WM_CLOSE()
	//}}AFX_MSG_MAP
	ON_MESSAGE(WM_COMMPORT_COM1_DATA, OnData)
	ON_MESSAGE(WM_COMMPORT_ERROR, OnError)
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// CRs232Wnd message handlers
#if _MSC_VER >= 1300
LRESULT CRs232Wnd::OnData(WPARAM wParam, LPARAM lParam)
#else
void CRs232Wnd::OnData(WPARAM wParam, LPARAM lParam)
#endif
{
	int i, iLength = (int)wParam;
	BYTE * p = (BYTE *)lParam;
	int iVal;

	if (m_bDebug)
	{
		char * pDisplay = (char *)p;
		int iDisplayLength, iTotalLength;

		pDisplay[iLength] = 0;
		iTotalLength = 0;
		do
		{
//			OutputDebugString(pDisplay);
			m_pEdit->ReplaceSel(pDisplay);
			iDisplayLength = lstrlen(pDisplay);
			iDisplayLength ++;
			pDisplay += iDisplayLength;
			iTotalLength += iDisplayLength;
		} while (iTotalLength < iLength);
	}
	else if (m_bSavingFile)
	{
		memcpy(m_pFileBuf + m_iTotalFile, p, iLength);
		m_iTotalFile += iLength;
		m_iCountFile += iLength;
		if (m_iCountFile >= 8)
		{
			m_iCountFile -= 8;
			SetEvent(CRs232Thread::m_hEventProtocol);
		}
	}
	else
	{
		for (i = 0; i < iLength; i ++)
		{
			iVal = p[i];
			CheckProtocol(iVal - 0x55, m_iCountH55);
//			CheckProtocol(iVal - 0xaa, m_iCountHaa);
			CheckProtocol(iVal - 0xff, m_iCountHff);
			CheckProtocol(iVal - 0x00, m_iCountH00);
		}
	}

//	OutputDebugBinary(p, iLength);
	free(p);
#if _MSC_VER >= 1300
	return 0;
#endif

}
#if _MSC_VER >= 1300
LRESULT CRs232Wnd::OnError(WPARAM wParam, LPARAM lParam)
#else
void CRs232Wnd::OnError(WPARAM wParam, LPARAM lParam)
#endif
{
#if _MSC_VER >= 1300
	return 0;
#endif
}


/////////////////////////////////////////////////////////////////////////////
// CRs232Wnd helper functions

void CRs232Wnd::CheckProtocol(int iVal, int & iCountHxx)
{
	if (iVal == 0)
	{
		iCountHxx ++;
		if (iCountHxx == 8)
		{
			SetEvent(CRs232Thread::m_hEventProtocol);
			iCountHxx = 0;
		}
	}
	else
	{
		iCountHxx = 0;
	}
}


BOOL CRs232Wnd::DestroyWindow() 
{
	if (m_pEdit != NULL)
	{
		m_pEdit->DestroyWindow();
		delete m_pEdit;
	}
	
	return CWnd::DestroyWindow();
}

void CRs232Wnd::OnClose() 
{
	ShowWindow(SW_MINIMIZE);
//	CWnd::OnClose();
}
