I have read alot of issues with serial port reading and writing. None so far have helped me figure out what my code is missing. The msdn example for c++ has undefined variables and missing brackets so although i can add brackets it still does not function. Here's what I've got at this point. It appears I can open the port and do the configuration but I cannot read a byte/char of data. I really just want a simple asyncronous serial read/write for aprogram to read from an Arduino.
class MY_SERIAL
{
HANDLE serialinstance;
DWORD dwStoredFlags;
DWORD dwRes;
DWORD dwCommEvent;
OVERLAPPED osStatus = {0};
BOOL fWaitingOnStat;
//dwStoredFlags = EV_BREAK | EV_CTS | EV_DSR | EV_ERR | EV_RING | EV_RLSD | EV_RXCHAR | EV_RXFLAG | EV_TXEMPTY ;
DCB dcb;
COMMTIMEOUTS timeouts;
COMMCONFIG serialconfig;
public:
char inBuffer[1000];
char outBuffer[100];
PDWORD noBytes;
void close_serial()
{
CloseHandle(serialinstance);
}
//----------------------------------------------------
bool open_serial(LPCSTR portNumber) // serial port name use this format "\\\\.\\COM10"
{
serialinstance = CreateFile(portNumber, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
if(serialinstance == INVALID_HANDLE_VALUE)
{
int error = GetLastError();
printf("ERROR opening serial port %s\r\n", portNumber);
if(error == 0x2){printf("ERROR_FILE_NOT_FOUND\r\n");}
if(error == 0x5){printf("ERROR_ACCESS_DENIED\r\n");}
if(error == 0xC){printf("ERROR_INVALID_ACCESS\r\n");}
if(error == 0x6){printf("ERROR_INVALID_HANDLE\r\n");}
printf("error code %d\r\n", error);
return false;
}
if(GetCommState(serialinstance, &dcb)!= true)
{
printf("ERROR getting current state of COM %d \r\n", GetLastError());
return false;
}
else{printf("debug read current comstate\r\n");}
FillMemory(&dcb, sizeof(dcb), 0); //zero initialize the structure
dcb.DCBlength = sizeof(dcb); //fill in length
dcb.BaudRate = CBR_115200; // baud rate
dcb.ByteSize = 8; // data size, xmit and rcv
dcb.Parity = NOPARITY; // parity bit
dcb.StopBits = ONESTOPBIT;
if(SetCommState(serialinstance, &dcb) != true)
{
printf("ERROR setting new state of COM %d \r\n", GetLastError());
return false;
}
else{printf("debug set new comstate\r\n");}
/*
if (!BuildCommDCB("115200,n,8,1", &dcb)) //fills in basic async details
{
printf("ERROR getting port comstate\r\n");
return FALSE;
}
*/
if (!SetCommMask(serialinstance, EV_RXCHAR))
{
printf("ERROR setting new COM MASK %d \r\n", GetLastError());
return false;
}
else{printf("debug commmask set\r\n");}
timeouts.ReadIntervalTimeout = MAXDWORD;
timeouts.ReadTotalTimeoutMultiplier = 20;
timeouts.ReadTotalTimeoutConstant = 0;
timeouts.WriteTotalTimeoutMultiplier = 0;
timeouts.WriteTotalTimeoutConstant = 0;
if (!SetCommTimeouts(serialinstance, &timeouts))
{
printf("ERROR setting timeout parameters\r\n");
return false;
}
else{printf("debug timeouts set\r\n");}
osStatus.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (osStatus.hEvent == NULL)
{// error creating event; abort
printf("ERROR creating Serial EVENT\r\n");
return false;
}
else{printf("debug event created set\r\n");}
osStatus.Internal = 0;
osStatus.InternalHigh = 0;
osStatus.Offset = 0;
osStatus.OffsetHigh = 0;
assert(osStatus.hEvent);
printf("debug com port setting complete\r\n");
return true;
}
//---------------------------------------------------------
bool read_serial_simple()
{
char m[1000];
LPDWORD bytesRead;
if (WaitCommEvent(serialinstance, &dwCommEvent, &osStatus))
{
if(dwCommEvent & EV_RXCHAR)
{
ReadFile(serialinstance, &m, 1, bytesRead, &osStatus);
printf("data read = %d, number bytes read = %d \r\n", m, bytesRead);
return true;
}
else
{
int error = GetLastError();
if(error == ERROR_IO_PENDING){printf(" waiting on incomplete IO\r\n");}
else{printf("ERROR %d\r\n", error);}
return false;
}
}
return false;
}
};
So I stripped the read function down. I now get a char and it reports reading 1 byte but the value of the char is incorrect. I get a series of 48, 13, 10, and occasionally a 50 value for the byte. However the Arduino is sending a series a 0's then a 128 as verified with TerraTerm. What else do I need here?
bool read_serial_simple()
{
unsigned char m = 0;
DWORD bytesRead;
if(ReadFile(serialinstance, &m, 1, &bytesRead, &osStatus) == true)
{
printf("data read = %d, number bytes read = %d \r\n", m, bytesRead);
return true;
}
else{
int error = GetLastError();
if(error == ERROR_IO_PENDING){printf(" waiting on incomplete IO\r\n");}
else{printf("ERROR %d\r\n", error);}
return false;
}
}
So now I can read a byte of data but I cannot write a byte or more to the port. I just get ERROR_IO_PENDING. Can someone help out with this as well. Write function of my class below.
bool write(DWORD noBytesToWrite)
{
if(WriteFile(serialinstance, outBuffer, noBytesToWrite, NULL, &osStatus) == true)
{
printf("message sent\r\n");
return true;
}
else
{
int error = GetLastError();
if(error != ERROR_IO_PENDING){LastError();}
return false;
}
}
I'm calling both functions from main as follows
myserial.open_serial(COM12);
myserial.outBuffer[0] = 'H';
myserial.outBuffer[1] = 'e';
myserial.outBuffer[2] = 'L';
myserial.outBuffer[3] = 'l';
myserial.outBuffer[4] = 'O';
for(int n=0; n<5; n++){printf("%c", myserial.outBuffer[n]);}
printf("\r\n");
while(1)
{
myserial.read();
myserial.write(5);
//system("PAUSE");
}
Currently the arduino is set up to read bytes in and repeat them back to the pc. It is doing this fine on the arduino IDE serial monitor so now I just need to get this pc program to write out.
Best Answer
Your
bytesRead
variable is an uninitialized pointer. You are passing an invalid address toReadFile()
to write to.Replace
LPDWORD bytesRead
withDWORD bytesRead
, then pass it toReadFile()
using&bytesRead
.Edit: Also eliminate the
FILE_FLAG_OVERLAPPED
. You are not handling it properly, and there is no point in using it if youWaitForSingleObject()
before reading.