Last active
August 29, 2015 14:14
-
-
Save jasin/932cba512f912661e13d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "stdafx.h" | |
#include "serial.h" | |
Serial::Serial(const TCHAR *pchPort, HWND &hwnd) // Constructor | |
{ | |
SetOnEventHandle(hwnd); | |
SetPort(pchPort); | |
m_bIsConnected = false; | |
} | |
Serial::~Serial() // Destructor | |
{ | |
delete[] m_pchPort; | |
CloseHandle(m_hSerial); | |
} | |
int Serial::UnInit() | |
{ | |
/* Kill the worker thread, clean up */ | |
SignalObjectAndWait(m_hThreadTerminator, m_hThread, INFINITE, FALSE); | |
return 0; | |
} | |
int Serial::Init() | |
{ | |
m_hSerial = CreateFile(m_pchPort, | |
GENERIC_READ | GENERIC_WRITE, | |
0, | |
0, | |
OPEN_EXISTING, | |
FILE_FLAG_OVERLAPPED, | |
0); | |
if (m_hSerial == INVALID_HANDLE_VALUE) | |
{ | |
if (GetLastError() == ERROR_FILE_NOT_FOUND) | |
{ | |
// Serial port does not exist. | |
return -1; | |
} | |
// Error occurred | |
return -1; | |
} | |
else | |
{ | |
DCB dcbSerialParams = {0}; | |
dcbSerialParams.DCBlength = sizeof(dcbSerialParams); | |
if (!GetCommState(m_hSerial, &dcbSerialParams)) | |
{ | |
// error getting the connection, report to user | |
return -1; | |
} | |
dcbSerialParams.BaudRate = CBR_115200; | |
dcbSerialParams.ByteSize = 8; | |
dcbSerialParams.StopBits = ONESTOPBIT; | |
dcbSerialParams.Parity = NOPARITY; | |
if(!SetCommState(m_hSerial, &dcbSerialParams)) | |
{ | |
// error setting state of COM port, report to user | |
return -1; | |
} | |
// Not sure if the below code needs to be included or not with checking the status of the COM queue | |
COMMTIMEOUTS timeouts = {0}; | |
timeouts.ReadIntervalTimeout=MAXDWORD; | |
timeouts.ReadTotalTimeoutConstant=0; | |
timeouts.ReadTotalTimeoutMultiplier=0; | |
timeouts.WriteTotalTimeoutConstant=0; | |
timeouts.WriteTotalTimeoutMultiplier=0; | |
if(!SetCommTimeouts(m_hSerial, &timeouts)){ | |
//error inform the user | |
return -1; | |
} | |
if (!SetCommMask(m_hSerial, EV_RXCHAR | EV_TXEMPTY)) | |
{ | |
//error occurred inform the user | |
return -1; | |
} | |
// Create thread terminator | |
m_hThreadTerminator = CreateEvent(0, 0, 0, 0); | |
// Create an event that will be signaled w/(SetEvent()) in the worker thread. | |
m_hThreadRunning = CreateEvent(0, 0, 0, 0); | |
// Begin worker thread | |
m_hThread = (HANDLE)_beginthreadex(0, 0, &WorkThread, (void*) this, 0, 0); | |
// Wait for event, see that the thread is running. Clean up a possible handle leak. | |
DWORD dwWait = WaitForSingleObject(m_hThreadRunning, INFINITE); | |
assert(dwWait == WAIT_OBJECT_0); | |
m_bIsConnected = true; | |
CloseHandle(m_hThreadRunning); | |
return 0; | |
} | |
} | |
unsigned int __stdcall Serial::WorkThread(void* pvParam) | |
{ | |
// This is a pointer to the 'this' serial class. | |
// Needed to be able to set members of the class in a static class function | |
Serial * cThis = (Serial*) pvParam; | |
// Set up the overlapped event | |
OVERLAPPED ov; | |
memset(&ov, 0, sizeof(ov)); | |
ov.hEvent = CreateEvent(0, true, false, 0); | |
DWORD dwEventMask = 0; | |
DWORD dwWait; | |
HANDLE aHandles[2]; | |
aHandles[0] = cThis->m_hThreadTerminator; | |
aHandles[1] = ov.hEvent; | |
SetEvent(cThis->m_hThreadRunning); | |
while (true) | |
{ | |
if (!WaitCommEvent(cThis->m_hSerial, &dwEventMask, &ov)) | |
{ | |
assert(GetLastError() == ERROR_IO_PENDING); | |
} | |
dwWait = WaitForMultipleObjects(2, aHandles, FALSE, INFINITE); | |
switch(dwWait) | |
{ | |
case WAIT_OBJECT_0: | |
{ | |
_endthreadex(1); | |
} | |
case WAIT_OBJECT_0 + 1: | |
{ | |
if (dwEventMask & EV_TXEMPTY) | |
{ | |
ResetEvent(ov.hEvent); | |
} | |
else if (dwEventMask & EV_RXCHAR) | |
{ | |
// read data here | |
DWORD dwBytesRead = 0; | |
DWORD dwErrors; | |
COMSTAT cStat; | |
OVERLAPPED ovRead = { 0 }; | |
ovRead.hEvent = CreateEvent(0, true, false, 0); | |
// Get the Bytes in queue | |
string str; | |
do | |
{ | |
TCHAR szBuf[2]; | |
memset(szBuf, 0x00, sizeof(szBuf)); | |
if (ReadFile(cThis->m_hSerial, &szBuf, 1, NULL, &ovRead)) | |
{ | |
GetOverlappedResult(cThis->m_hSerial, &ovRead, &dwBytesRead, FALSE); | |
str.append(szBuf); | |
} | |
else | |
{ | |
DWORD err = GetLastError(); | |
} | |
} while (dwBytesRead > 0); | |
// Send msg to the window and have the window process it | |
SendMessage(cThis->m_hHwnd, WM_SERIAL, 0, LPARAM(str.c_str())); | |
CloseHandle(ovRead.hEvent); // clean up!!! | |
} | |
// Reset the overlapped event | |
ResetEvent(ov.hEvent); | |
} | |
break; | |
}//switch | |
} | |
return 0; | |
} | |
bool Serial::WriteData(char *pchBuffer) | |
{ | |
//TODO: Write data to the serial port from the buffer. | |
OVERLAPPED ov = { 0 }; | |
ov.hEvent = CreateEvent(0, true, false, 0); | |
DWORD dwBytesWritten = 0; | |
DWORD dwSize = _tcslen(pchBuffer); | |
if (!WriteFile(m_hSerial, pchBuffer, dwSize, &dwBytesWritten, &ov)) | |
if (GetLastError() == ERROR_IO_PENDING) | |
WaitForSingleObject(ov.hEvent, INFINITE); | |
CloseHandle(ov.hEvent); | |
return 0; | |
} | |
bool Serial::IsConnected() | |
{ | |
return m_bIsConnected; | |
} | |
wchar_t Serial::GetPort() | |
{ | |
return * m_pchPort; | |
} | |
void Serial::SetPort(const TCHAR *pchPort) | |
{ | |
m_nLength = _tcslen(pchPort)+1; // Get the length of the string | |
m_pchPort = new TCHAR[m_nLength]; // Allocate memory | |
_tcscpy_s(m_pchPort, m_nLength, pchPort); // Copy to internal buffer | |
} | |
void Serial::SetOnEventHandle(HWND hwnd) | |
{ | |
m_hHwnd = hwnd; | |
} | |
HANDLE Serial::GetSerialHandle() | |
{ | |
return m_hSerial; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment