Re: Strange serial port error
And here MySerial.cpp:
// MySerial.cpp : implementation file
//
#include "stdafx.h"
#include "uart3.h"
#include "MySerial.h"
#include <vector>
#define MAX_BUFFER_SIZE_MYSERIAL 64
#define READING 0
#define WRITING 1
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// MySerial
IMPLEMENT_DYNCREATE(MySerial, CWinThread)
//! Constructor
MySerial::MySerial()
{
opened= FALSE;
init = FALSE;
}
//! Destructor
MySerial::~MySerial()
{
//CloseHandle(ShutdownEvent);
//CloseHandle(ReadEvent);
//CloseHandle(WriteEvent);
// Wait for the thread to exit before deleting
//WaitForSingleObject( this->m_hThread, INFINITE );
}
/*! \brief Inits member's class.
Due the use of threads, initialisation of vars must be done here.
*/
BOOL MySerial::InitInstance()
{
m_bAutoDelete = FALSE;
init = TRUE;
return TRUE;
}
//! At close thread
int MySerial::ExitInstance()
{
//TRACE("Close thread.\n");
return CWinThread::ExitInstance();
}
BEGIN_MESSAGE_MAP(MySerial, CWinThread)
//{{AFX_MSG_MAP(MySerial)
// NOTE - the ClassWizard will add and remove mapping macros here.
ON_THREAD_MESSAGE( WM_MYSERIAL_WRITE, OnWriteData )
ON_THREAD_MESSAGE( WM_MYSERIAL_CLOSE, closePort )
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// MySerial message handlers
BOOL MySerial::OnIdle(LONG lCount)
{
// TRACE("Nothing to do.\n");
return CWinThread::OnIdle(lCount);
}
int MySerial::Run()
{
//TRACE("Running.");
return CWinThread::Run();
}
// Message Handler that sends data
// wParam: std::vector<unsigned char>
/*! \brief Writes data into serial comm
\param wParam: must be a std::vector<unsigned char> with every byte
to send.
\param lParam: Not used, but must be in definition.
*/
void MySerial::OnWriteData( WPARAM wParam, LPARAM lParam )
{
//TRACE("Write Exec\n");
DWORD bytesWritten;
unsigned char* buffer = (unsigned char*)wParam;
BOOL ok = ::WriteFile( hComm, buffer, lParam, &bytesWritten,
&ovWriter );
if( !ok )
{
//Fail
DWORD err = ::GetLastError();
if( err!=ERROR_IO_PENDING ) //Error grave
{
//Tell GUI that an error occourred
err = ::GetLastError();
TRACE("Error WriteFile::%d.\n",err);
delete buffer;
PostQuitMessage(0);
return;
}
//ERROR_IO_PENDING
HANDLE waiters[2];
waiters[0] = ShutdownEvent;
waiters[1] = WriteEvent;
DWORD what = ::WaitForMultipleObjects( 2, waiters, FALSE,
INFINITE );
switch( what )
{
case WAIT_OBJECT_0: //Shutdown event
//Tell GUI that the thread has stopped
err = ::GetLastError();
TRACE("Error Wait4Multiple Objects:%d\n",err );
delete buffer;
PostQuitMessage(0);
return;
case WAIT_OBJECT_0 + 1: //Write completed
ok = ::GetOverlappedResult( hComm, &ovWriter, &bytesWritten,
TRUE );
if( !ok )
{ //Fail!
//Tell GUI fail occourred
TRACE("Fail GeTOverlapped.\n");
delete buffer;
PostQuitMessage(0);
return;
}
else
{
//Write complete
//Tell GUI that all writed ok
//TRACE("Writed with delay.\n");
notificador->PostMessage(UWM_MYSERIAL_DATA_WRITTED );
}
break;
default:
DWORD err = ::GetLastError();
ASSERT( FALSE );
TRACE("Fail default.\n");
delete buffer;
PostQuitMessage(0);
return;
}
}
else
{
SetEvent( WriterStoped );
notificador->PostMessage(UWM_MYSERIAL_DATA_WRITTED );
ResetEvent( WriterStoped );
}
delete buffer; //Kill buffer
}
//LRESULT MySerial::ReaderThread(LPVOID cT )
/*! \brief Reads from serial comm port
This is a thread that continuosly is reading from serial comm
port.<br>
At every bunch of bytes received, posts a message to main GUI thread
sending the values found.
*/
UINT ReaderThread( LPVOID cT )
{
MySerial* SerialHandler = (MySerial*)cT;
BOOL reading = TRUE;
DWORD bytesRead;
DWORD shutdown;
HANDLE waiters[2];
waiters[0] = SerialHandler->ShutdownEvent;
waiters[1] = SerialHandler->ovReader.hEvent;
while( reading )
{
unsigned char buffer[MAX_BUFFER_SIZE_MYSERIAL];
BOOL ok = ::ReadFile( SerialHandler->hComm, buffer,
MAX_BUFFER_SIZE_MYSERIAL, &bytesRead, &SerialHandler->ovReader );
if( !ok )
{
DWORD error = ::GetLastError();
if( error!= ERROR_IO_PENDING )
{
TRACE("ERROR READING.\n");
shutdown = error; //Store the error
reading = FALSE; //Stop reading
continue;
}
//ERROR_IO_PENDING
DWORD result = ::WaitForMultipleObjects( 2, waiters, FALSE,
INFINITE );
switch( result )
{
case WAIT_OBJECT_0: //Event shutdown
shutdown = 0;
reading = FALSE; //Stop the reading
continue;
case WAIT_OBJECT_0 + 1:
ok = ::GetOverlappedResult( SerialHandler->hComm, &SerialHandler-
ovReader, &bytesRead, TRUE ); //Get results
if( !ok )
{ //GetOverlappedResult has failed
shutdown = ::GetLastError();
reading = FALSE; //Stop the reading
TRACE("ERROR READING\n");
continue;
}
else
{
//TRACE("READED OK\n");
}
break;
default:
TRACE("ASSERT\n");
shutdown = ::GetLastError();
ASSERT(FALSE); //Fallo
reading = FALSE;
continue;
}
}
if( bytesRead>0 )
{
unsigned char* buffer2 = new unsigned
char[MAX_BUFFER_SIZE_MYSERIAL];
for( int i=(bytesRead-1); i>=0; i-- )
buffer2[i] = buffer[i];
SerialHandler->notificador->PostMessage( UWM_MYSERIAL_DATA_READ,
(WPARAM)buffer2, (LPARAM)bytesRead );
}
else
{
//TRACE("None byte received\n");
}
}
if( shutdown!=0 )
{ SerialHandler->notificador-
PostMessage( UWM_MYSERIAL_ERROR,shutdown, READING );
}
SetEvent( SerialHandler->ReaderStoped );
return 0;
}
//! \return MySerial::opened
BOOL MySerial::isOpen()
{
return opened;
}
//! \return MySerial::init
BOOL MySerial::isInit()
{
return init;
}
//! Stores a pointer to CWnd object in order to be able to send
messages to it.
void MySerial::configure( CWnd* w )
{
this->notificador = w;
}
/*! \brief Opens port
Configures MySerial:dcb object and opens port.
*/
BOOL MySerial::openPort( int port )
{
opened = TRUE;
WriteEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
ReadEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
ReaderStoped = CreateEvent( NULL, TRUE, FALSE, NULL );
WriterStoped = CreateEvent( NULL, TRUE, FALSE, NULL );
ShutdownEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
memset( &ovReader, 0, sizeof( OVERLAPPED ) );
memset( &ovWriter, 0, sizeof( OVERLAPPED ) );
ovReader.hEvent = ReadEvent;
ovWriter.hEvent = WriteEvent;
CString Sport;
Sport.Format( "\\\\.\\COM%d",port );
hComm = CreateFile( Sport, GENERIC_READ | GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL );
if( hComm == INVALID_HANDLE_VALUE )
{
TRACE("Could not open the port.\n");
opened = FALSE;
return FALSE;
}
BOOL fSucces = GetCommState( hComm, &dcb );
if( !fSucces )
{
TRACE("Error checking port configuration.\n");
opened = FALSE;
return FALSE;
}
dcb.DCBlength = sizeof(dcb);
dcb.BaudRate = CBR_57600;
dcb.fBinary = TRUE;
dcb.fParity = FALSE;
dcb.fOutxCtsFlow = FALSE;
dcb.fOutxDsrFlow = FALSE;
dcb.fDtrControl = DTR_CONTROL_ENABLE;
dcb.fDsrSensitivity = FALSE;
dcb.fTXContinueOnXoff = FALSE;
dcb.fOutX = FALSE;
dcb.fInX = FALSE;
dcb.fErrorChar = 0;
dcb.fNull = FALSE;
dcb.fRtsControl = RTS_CONTROL_ENABLE;
dcb.fAbortOnError = FALSE;
dcb.XonLim = 2048;
dcb.XoffLim = 512;
dcb.ByteSize = 8;
dcb.Parity = NOPARITY;
dcb.StopBits = 0; //ONESTOPBIT;
dcb.XonChar = 17;
dcb.XoffChar = 19;
dcb.ErrorChar = 0;
dcb.EofChar = 0;
dcb.EvtChar = 0;
fSucces = SetCommState( hComm, &dcb );
if( !fSucces )
{
TRACE("Error configuring port\n");
opened = FALSE;
return FALSE;
}
fSucces = PurgeComm( hComm, PURGE_RXABORT|PURGE_RXCLEAR );
if( !fSucces )
{
TRACE("Fail purging port.\n");
opened = FALSE;
return FALSE;
}
COMMTIMEOUTS timeouts;
GetCommTimeouts( hComm, &timeouts );
timeouts.ReadIntervalTimeout = 10;
timeouts.ReadTotalTimeoutMultiplier = 1;
timeouts.ReadTotalTimeoutConstant = 10;
timeouts.WriteTotalTimeoutMultiplier = 0;
timeouts.WriteTotalTimeoutConstant = 0;
SetCommTimeouts( hComm, &timeouts );
//Start the reading
pReaderThread = AfxBeginThread( ReaderThread, this,
THREAD_PRIORITY_ABOVE_NORMAL );
return TRUE;
}
/*! \brief Closes port.
Closes the port opened and Reader thread too.
*/
void MySerial::closePort( WPARAM wparam, LPARAM lparam)
{
if( opened )
{
SetEvent( ShutdownEvent );
WaitForSingleObject( pReaderThread->m_hThread, INFINITE );
BOOL ok = PurgeComm( hComm, PURGE_RXABORT|PURGE_RXCLEAR );
::CloseHandle( WriteEvent );
::CloseHandle( ShutdownEvent );
::CloseHandle( ReadEvent );
::CloseHandle( hComm );
PostQuitMessage(0);
opened = FALSE;
}
else
{
PostQuitMessage(0);
}
}
void MySerial::Kill()
{
opened = FALSE;
init = FALSE;
}