Readfile operation completes but fills data buffer with multiple messages / Serial communication - c++

I'm working on a application that reads data on a serial port. Various messages can be sent over this serial port in a short period of time, and the thread that reads incoming data must identify what type of message it reads when the ReadFile operation completes. I'm using an overlapped structure and I want messages to be read one by one.
My problem is that the ReadFile operation often fills the buffer with multiple messages and I can't find values of com timeouts that prevent this from hapening. I suspect that reading operation doesn't complete when two messages are received back to back, which is seen from the reading thread as a single message as there is still data on the serial port when the first message is complete.
I'm observing the same phenomenon using a non-overlapped structure.
I'm using a serial com, configured as followed:
DCB configPort = { 0 };
COMMTIMEOUTS timeouts;
this->hDevice = CreateFileA(
this->portReady,
GENERIC_READ | GENERIC_WRITE,
NULL,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL
);
if (this->hDevice == INVALID_HANDLE_VALUE) {
std::cout << "INVALID HANDLE" << std::endl;
return 0;
}
OvReception.Offset = 0;
OvReception.OffsetHigh = 0;
OvReception.hEvent = ::CreateEvent(NULL, FALSE, FALSE, _T(""));
configPort.DCBlength = sizeof(DCB);
configPort.BaudRate = CBR_38400;
configPort.StopBits = ONESTOPBIT;
configPort.Parity = EVENPARITY;
configPort.ByteSize = 8;
configPort.fRtsControl = RTS_CONTROL_DISABLE;
configPort.fAbortOnError = 0;
configPort.XonLim = 800;
configPort.XoffLim = 2000;
timeouts.ReadIntervalTimeout = 1;
timeouts.ReadTotalTimeoutMultiplier = 0;
timeouts.ReadTotalTimeoutConstant = 0;
timeouts.WriteTotalTimeoutMultiplier = 0;
timeouts.WriteTotalTimeoutConstant = 0;
if (!SetCommState(this->hDevice, &configPort)) {
CloseHandle(this->hDevice);
return 0;
}
if (!SetCommTimeouts(this->hDevice, &timeouts)) {
CloseHandle(this->hDevice);
return 0;
}
And I read incoming data using :
bool readState = false;
char incomingMessage[512] = {0};
DWORD bytesRead = 0;
memset(incomingMessage, 0, sizeof(incomingMessage));
while (this->threadRunning) {
readState = ReadFile(
this->comSerie.hDevice,
incomingMessage,
sizeof(incomingMessage),
NULL,
&this->comSerie.OvReception);
if (::GetLastError() == ERROR_IO_PENDING)
{
::GetOverlappedResult(this->comSerie.hDevice, &this->comSerie.OvReception, &bytesRead, TRUE);
}
//NO ERRORS OBSERVED
std::cout << "ERROR" << std::endl;
std::cout << GetLastError() << std::endl;
std::cout << "Message received" << std::endl;
std::cout << incomingMessage<< std::endl;
switch(ReceivedMessageType(incomingMessage)){
//............ DO SOMETHING
}
//Clean buffer
memset(incomingMessage, 0, sizeof(incomingMessage));
}
I configured the bwait parameter to TRUE in the GetOverlappedResult so that it doesn't return before the write operation is completed.
I do not observe any error return by GetLastError().
I've also tried using WaitForSingleObject function, the issue was the same.
Am I missing something?
Thanks for the help

Related

IO Completion Ports and WSASend

Sorry in advance, but please explain, how to use IOCP with WSASend - for example, to send a simple message to the server and receive a response from it.
I am doing this:
Create completion port
Create threads for the completion port
I create a WSASocket, with the Overlaped flag.
I establish a connection with a remote server using WSAConnect
I bind the socket to the completion port.
I send a message to the server - by calling the WSASend function.
Like this:
void My_func_for_Thread(HANDLE iocp)
{
DWORD my_DWORD;
PULONG_PTR my_CompletionKey;
WSAOVERLAPPED* my_WSAOVERLAPPED_1;
int my_GetLastError;
while (1)
{
BOOL my_BOOL_GetQueuedCompletionStatus = GetQueuedCompletionStatus(iocp, &my_DWORD, my_CompletionKey, &my_WSAOVERLAPPED_1, INFINITE);
my_GetLastError = GetLastError();
if (my_BOOL_GetQueuedCompletionStatus == FALSE)
{
std::cout << "GetQueuedCompletionStatus== FALSE" << std::endl;
}
}
}
int main()
{
//-------------------------------------------------------------------Create port IO-------------------------------------------------------------
int Number_Threads = 4;
HANDLE My_handle_IOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, Number_Threads);
//------------------------------------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------Create thread for IOCP-------------------------------------------------------
std::vector<HANDLE>my_vector_Thread;
for (int i = 0; i < Number_Threads; i++)
{
my_vector_Thread.push_back(CreateThread(0, 0, (LPTHREAD_START_ROUTINE)&My_func_for_Thread, My_handle_IOCP, 0, 0));
}
//---------------------------------------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------Initialization Winsock-----------------------------------------------------------
WORD my_version_Winsock = MAKEWORD(2, 2);
WSADATA my_wsadata_struct;
int my_WSAStartup = WSAStartup(my_version_Winsock, &my_wsadata_struct);
//------------------------------------------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------Create WSASocket-----------------------------------------------------------------
SOCKET my_WSASocketA = WSASocketA(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
//--------------------------------------------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------
std::string myString_IP = "XX.XXX.XX.XXX";
//--------------------------------------------------------------------------
sockaddr my_sockaddr;
my_sockaddr = { 0 };
my_sockaddr.sa_family = 2; // AF_INET.
inet_pton(AF_INET, myString_IP.c_str(), &my_sockaddr.sa_data[2]);
my_sockaddr.sa_data[1] = 80; //http port
//--------------------------------------------------------------------------
int status_WSAConnect = WSAConnect(my_WSASocketA, &my_sockaddr, sizeof(my_sockaddr), NULL, NULL, NULL, NULL);
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------Bind socket and port--------------------------------------------------------
My_handle_Create_IOCP = CreateIoCompletionPort((HANDLE)my_WSASocketA, My_handle_IOCP, NULL, 0);
//-------------------------------------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------Send message to serever with WSASend-----------------------------------
WSABUF my_WSABUF;
std::string request_text_string = "GET / HTTP/1.1\r\nHost: government.ru\r\nConnection: keep-alive\r\n\r\n";
my_WSABUF.buf = &request_text_string[0];
my_WSABUF.len = request_text_string.size();
WSAOVERLAPPED my_WSAOVERLAPPED;
my_WSAOVERLAPPED = { 0 };
int my_WSASend = WSASend(my_WSASocketA, &my_WSABUF, 1, NULL, 0, &my_WSAOVERLAPPED, NULL);
if (my_WSASend == SOCKET_ERROR)
{
std::cout << "WSASend == SOCKET_ERROR:" std::endl;
}
if (my_WSASend == 0)
{
std::cout << "WSASend == 0: no error" std::endl;
}
//-----------------------------------------------------------------------------------------------------------------------------------------------------------
Sleep(10000);
//---------------------------------------------------------
for (int i = 0; i < Number_Threads; i++)
{
CloseHandle(my_vector_Thread[i]);
}
//---------------------------------------------------------
}
But, GetQueuedCompletionStatus always return 998 - Invalid access to memory location.
Which memory is the disabled access to? What am I doing wrong ?
There are several problems with your code.
Your My_func_for_Thread() function has the wrong signature for use with CreateThread(). The compiler is not complaining because you are using a typecast to silence the compiler from failing.
You are passing an uninitialized pointer to the lpCompletionKey parameter of GetQueuedCompletionStatus(). It expects a pointer to a valid ULONG_PTR variable for it to write to.
The WSAOVERLAPPED needs to remain active in memory until its final status is retrieved from the IOCP queue. But your thread is sleeping much longer than your main() is running. You should allocate the WSAOVERLAPPED dynamically, and then free it when its status is received.
Try something more like this instead:
DWORD WINAPI My_func_for_Thread(LPVOID lpParameter)
{
HANDLE iocp = (HANDLE) lpParameter;
DWORD my_DWORD;
ULONG_PTR my_CompletionKey;
WSAOVERLAPPED* my_WSAOVERLAPPED_1;
DWORD my_GetLastError;
while (TRUE)
{
BOOL my_BOOL_GetQueuedCompletionStatus = GetQueuedCompletionStatus(iocp, &my_DWORD, &my_CompletionKey, (LPOVERLAPPED*) &my_WSAOVERLAPPED_1, INFINITE);
my_GetLastError = GetLastError();
if (my_BOOL_GetQueuedCompletionStatus)
{
delete my_WSAOVERLAPPED_1;
}
else
{
std::cout << "GetQueuedCompletionStatus == FALSE" << std::endl;
}
}
return 0;
}
int main()
{
...
for (int i = 0; i < Number_Threads; i++)
{
HANDLE hThread = CreateThread(NULL, 0, &My_func_for_Thread, My_handle_IOCP, 0, NULL);
if (hThread)
my_vector_Thread.push_back(hThread);
}
...
std::string request_text_string = "GET / HTTP/1.1\r\nHost: government.ru\r\nConnection: keep-alive\r\n\r\n";
WSABUF my_WSABUF;
my_WSABUF.buf = &request_text_string[0];
my_WSABUF.len = request_text_string.size();
WSAOVERLAPPED *my_WSAOVERLAPPED = new WSAOVERLAPPED;
*my_WSAOVERLAPPED = { 0 };
int my_WSASend = WSASend(my_WSASocketA, &my_WSABUF, 1, NULL, 0, my_WSAOVERLAPPED, NULL);
// wait for request to finish...
// wait for response to arrive...
// close socket...
// wait for threads to terminate...
...
for (size_t i = 0; i < my_vector_Thread.size(); i++)
{
CloseHandle(my_vector_Thread[i]);
}
return 0;
}

Port COM Handling in C++ cause Watchdog Violation

I'm writing an application for handling communication with the device by COM port.
For it I use ReadFile() from <windows.h>, as I had some problems with synchronous use, I tried overlapped implementation from http://www.egmont.com.pl/addi-data/instrukcje/standard_driver.pdf
And from what I understand for constant reading (to not lose any data sent by device), I need to call that reading func in a separate thread in infinite while() - I created some class for handling that and it's working perfectly, but after some random amount of time it's causing bluescreen DPC WATCHDOG VIOLATION unfortunately, I can't tell any specific event that may cause this :(
#edit1
I should add that's if I use some other program for COM communication, like Termite or TerraTerm it's working with no problems.
PortHandling.cpp (basically copy of that's overlapped implementation) :
#define OVERLAPPED_READ_TIMEOUT 1
PortHandling::PortHandling()
{
this->portHandle = INVALID_HANDLE_VALUE;
this->done = false;
this->portSelected = "";
this->baudRate = 0;
}
void PortHandling::ClearPort()
{
if (this->done)
{
this->done = false;
PurgeComm(this->portHandle, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
CloseHandle(this->portHandle);
std::cout << "[E] Disconnected from port " << this->portSelected << std::endl;
}
}
bool PortHandling::SetPortProp(std::string portName, int baudRate, int maxReadSize, int maxWriteSize)
{
this->portSelected = portName;
this->portHandle = CreateFileA(("\\\\.\\" + this->portSelected).c_str(), GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
if (this->portHandle == INVALID_HANDLE_VALUE)
{
std::cout << "[E] Connecting to port failed - Port occupied" << std::endl;
this->portSelected = "";
return false;
}
SetupComm(this->portHandle, maxReadSize, maxWriteSize); // The size of input buffer and output buffer
COMMTIMEOUTS timeOuts;
timeOuts.ReadIntervalTimeout = 3; //Set read timeout
timeOuts.ReadTotalTimeoutMultiplier = 1;
timeOuts.ReadTotalTimeoutConstant = 3;
timeOuts.WriteTotalTimeoutMultiplier = 0; // Set write timeout
timeOuts.WriteTotalTimeoutConstant = 0;
SetCommTimeouts(this->portHandle, &timeOuts); // Set timeout
DCB dcb;
GetCommState(this->portHandle, &dcb);
dcb.BaudRate = baudRate; /* Baudrate at which running */
dcb.fBinary = 1; /* Binary Mode (skip EOF check) */
dcb.fParity = 0; /* Enable parity checking */
dcb.fOutxCtsFlow = 0; /* CTS handshaking on output */
dcb.fOutxDsrFlow = 0; /* DSR handshaking on output */
dcb.fDtrControl = DTR_CONTROL_ENABLE; /* DTR Flow control */
dcb.fDsrSensitivity = 0; /* DSR Sensitivity */
dcb.fTXContinueOnXoff = 1; /* Continue TX when Xoff sent */
dcb.fOutX = 0; /* Enable output X-ON/X-OFF */
dcb.fInX = 0; /* Enable input X-ON/X-OFF */
dcb.fErrorChar = 1; /* Enable Err Replacement */
dcb.fNull = 1; /* Enable Null stripping */
dcb.fRtsControl = RTS_CONTROL_DISABLE; /* Rts Flow control */
dcb.ByteSize = 8; /* Number of bits/byte, 4-8 */
dcb.Parity = NOPARITY; /* 0-4 = None,Odd,Even,Mark,Space */
dcb.StopBits = ONESTOPBIT; /* 0,1,2 = 1, 1.5, 2 */
dcb.XonChar; /* Tx and Rx X-ON character */
dcb.XoffChar; /* Tx and Rx X-OFF character */
dcb.ErrorChar; /* Error replacement char */
dcb.EofChar; /* End of Input character */
dcb.EvtChar; /* Received Event character */
SetCommState(this->portHandle, &dcb);
PurgeComm(this->portHandle, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
this->done = true;
std::cout << "[I] Connecting to port " << this->portSelected << " succeeded" << std::endl;
return true;
}
//#brief
//param size - Maximal read size, may be shorter if read is waiting for longer than set timeout (10ms)
//param buffer - Buffer into witch read data is saved
//param onRead - Function that is called on succesfull read
DWORD PortHandling::ReadFromPort(int size, char *buffer, std::function<void()> onRead)
{
DWORD dwRead = 0;
DWORD dwRes = 0;
BOOL fWaitingOnRead = FALSE;
OVERLAPPED osReader = {0};
// Create the overlapped event. Must be closed before exiting to avoid a handle leak.
osReader.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (osReader.hEvent == NULL)
{
std::cout << "[E] Error in communication, overlapped construction failed" << std::endl;
return dwRead;
}
if (!fWaitingOnRead)
{
// Issue read operation.
if (!ReadFile(this->portHandle, buffer, size, &dwRead, &osReader))
{
if (GetLastError() != ERROR_IO_PENDING) // read not delayed?
{
std::cout << "[E] Error in communication (read:1)" << std::endl;
} else
{
fWaitingOnRead = TRUE;
}
} else
{
// read completed immediately
}
}
if (fWaitingOnRead)
{
dwRes = WaitForSingleObject(osReader.hEvent, OVERLAPPED_READ_TIMEOUT);
switch (dwRes)
{
// Read completed.
case WAIT_OBJECT_0:
if (!GetOverlappedResult(this->portHandle, &osReader, &dwRead, FALSE))
{
std::cout << "[E] Error in communication (read:2)" << std::endl;
} else
{
// Read completed successfully.
}
// Reset flag so that another opertion can be issued.
fWaitingOnRead = FALSE;
break;
case WAIT_TIMEOUT:
// Operation isn't complete yet. fWaitingOnRead flag isn't
// changed since I'll loop back around, and I don't want
// to issue another read until the first one finishes.
// This is a good time to do some background work.
break;
default:
// Error in the WaitForSingleObject; abort.
// This indicates a problem with the OVERLAPPED
// structure's event handle
std::cout << "[E] Error in communication, overlapped construction failed" << std::endl;
return dwRead;
}
}
if (strlen(buffer) > 0)
{
onRead();
}
return dwRead;
}
//#brief
//param size - Size of written message
//param buffer - Buffer from witch data is send
//param onWrite - Function that is called on succesfull write
bool PortHandling::WriteToPort(int size, const char *buffer, std::function<void()> onWrite)
{
OVERLAPPED osWrite = {0};
DWORD dwWritten = 0;
DWORD dwRes = 0;
BOOL fRes = FALSE;
// Create this writes OVERLAPPED structure hEvent.
osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (osWrite.hEvent == NULL)
{
std::cout << "[E] Error in communication, overlapped construction failed" << std::endl;
return FALSE;
}
// Issue write.
if (!WriteFile(this->portHandle, buffer, size, &dwWritten, &osWrite))
{
if (GetLastError() != ERROR_IO_PENDING)
{
// WriteFile failed, but it isn't delayed. Report error and abort.
std::cout << "[E] Error in communication (write:1)" << std::endl;
fRes = FALSE;
} else
{
// Write is pending.
dwRes = WaitForSingleObject(osWrite.hEvent, INFINITE);
switch (dwRes)
{
// OVERLAPPED structure's event has been signaled.
case WAIT_OBJECT_0:
if (!GetOverlappedResult(this->portHandle, &osWrite, &dwWritten, FALSE))
{
std::cout << "[E] Error in communication (write:2)" << std::endl;
fRes = FALSE;
} else
{
// Write operation completed successfully.
fRes = TRUE;
onWrite();
}
break;
default:
// An error has occurred in WaitForSingleObject.
// This usually indicates a problem with the
// OVERLAPPED structure's event handle.
std::cout << "[E] Error in communication (write:3)" << std::endl;
fRes = FALSE;
break;
}
}
} else
{
// WriteFile completed immediately.
fRes = TRUE;
onWrite();
}
CloseHandle(osWrite.hEvent);
return fRes;
}
My class for handling that,
PortOperator.cpp
bool PortOperator::Construct(std::string portName, int baudRate, int maxReadSize, int maxWriteSize)
{
this->portName = portName;
this->baudRate = baudRate;
this->maxReadSize = maxReadSize;
this->maxWriteSize = maxWriteSize;
this->cRead = new char[maxReadSize];
memset(cRead, 0, this->maxReadSize);
this->cWrite = new char[maxWriteSize];
memset(cWrite, 0, this->maxWriteSize);
if (this->PortHandler.SetPortProp(portName, baudRate, maxReadSize, maxWriteSize))
{
// if connection succesfull, start Reading in the background
this->Reading = std::thread(&PortOperator::ReadingThread, this);
} else
{
static ftor_DeltaTime reconnect_timeout = ftor_DeltaTime();
int n = 0;
while (true)
{
// try reconnecting to port each second, max 5 tries
if (reconnect_timeout(TimeUnits::SECONDS) >= 1)
{
n++;
if (this->PortHandler.SetPortProp(portName, baudRate, maxReadSize, maxWriteSize))
{
// if connection succesfull, start Reading in the background
this->Reading = std::thread(&PortOperator::ReadingThread, this);
break;
}
if (n > 5)
{
return false;
}
reconnect_timeout.Reset();
}
}
}
return true;
}
void PortOperator::ReadingThread()
{
this->notReciving = ftor_DeltaTime();
char *buffer = new char[this->maxReadSize];
while (true)
{
memset(buffer, 0, this->maxReadSize);
//make sure the thread is stopped when port disconnect
if (!this->PortHandler.done)
{
break;
}
this->PortHandler.ReadFromPort(this->maxReadSize, buffer,
[&]() {
//block executed only when there's some data read (not empty)
if (ConsolePreview)
{
std::cout << buffer;
}
mtx_cRead.lock();
strcpy(this->cRead, buffer);
mtx_cRead.unlock();
readFlag = 1;
cv.notify_all();
notReciving.Reset();
});
}
}
std::string PortOperator::Write(std::string command)
{
std::mutex mtx_cv;
std::unique_lock<std::mutex> write_lck(mtx_cv);
std::string response = "";
this->PortHandler.WriteToPort(command.length(), command.c_str(), []() {});
if (cv.wait_for(write_lck, std::chrono::milliseconds(45)) == std::cv_status::no_timeout)
{
response = cRead;
}
return response;
}
bool PortOperator::Reconnect()
{
this->Disconnect();
return this->Construct(this->portName, this->baudRate, this->maxReadSize, this->maxWriteSize);
}
bool PortOperator::Disconnect()
{
//first clear port connection to stop thread, and then join
this->PortHandler.ClearPort();
if (Reading.joinable())
{
Reading.join();
}
return true;
}
long long int PortOperator::SilenceTime(TimeUnits t)
{
return this->notReciving(t);
}
std::vector<std::string> PortOperator::GetPorts()
{
std::vector<std::string> portsCOM;
//try connecting with each port to check which are avaiable
for (int i = 0; i <= 256; i++)
{
std::string portName = "COM" + std::to_string(i);
if (this->CheckPort(portName))
{
portsCOM.push_back(portName.c_str());
}
}
//if there's no avaiable port add "-" to vector
if (portsCOM.size() == 0)
{
portsCOM.push_back(" - ");
}
return portsCOM;
}
bool PortOperator::CheckPort(std::string portName)
{
//try connecting with given port
HANDLE serialHandle;
serialHandle = CreateFileA(("\\\\.\\" + portName).c_str(), GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (serialHandle == INVALID_HANDLE_VALUE)
{
return false;
}
CloseHandle(serialHandle);
return true;
}
I'm not the best programmer, if something hurt your eyes please tell me...
Thanks for your time :D

Issue Sending text to COM Port

I have a PLC connected to one of my laptop's COM Ports and I've trying to send it a default command that returns a default response. Currently WriteFile successfully sends the 20 bit command but ReadFile doesn't read anything though there's no error.
int main(){
HANDLE hCom = CreateFile("\\\\.\\COM4",
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
0,
NULL);
if (hCom == INVALID_HANDLE_VALUE)
{
DWORD err=GetLastError();
std::cout << "Failed\n";
return 0;
}
DCB dcbConfig;
if(GetCommState(hCom, &dcbConfig))
{
dcbConfig.BaudRate = CBR_115200;
dcbConfig.ByteSize = 8;
dcbConfig.Parity = NOPARITY;
dcbConfig.StopBits = ONESTOPBIT;
dcbConfig.fBinary = TRUE;
dcbConfig.fParity = FALSE;
}
if(!SetCommState(hCom, &dcbConfig))
{
CloseHandle(hCom);
return 0;
}
COMMTIMEOUTS commTimeout;
if(GetCommTimeouts(hCom, &commTimeout))
{
commTimeout.ReadIntervalTimeout = 1;
commTimeout.ReadTotalTimeoutConstant = 1;
commTimeout.ReadTotalTimeoutMultiplier = 1;
commTimeout.WriteTotalTimeoutConstant = 1;
commTimeout.WriteTotalTimeoutMultiplier = 1;
}
if(!SetCommTimeouts(hCom, &commTimeout))
//Handle Error Condition
CloseHandle(hCom);
// Write to the COM
static char data[22]="%01#RDD0010000107**\n";
int size = strlen(data);
DWORD dwWritten, dwReading;
int j;
WriteFile(hCom,data,(DWORD)size,&dwWritten,NULL);
DWORD err=GetLastError();
std::cout << err;
char datarecv[22];
ReadFile(hCom,&datarecv,1,&dwReading,NULL);
err = GetLastError();
std::cout << err;
std::cout << datarecv << "\n";
CloseHandle(hCom);
std::cin>>j;
return 0;
}

Some problem with serial programming in vc++ mfc

When I connect my embedded device to my system, I am running my program which will write to the port my embedded is connect and it prints the reply to console.
When I connect my device and run this program it is not giving any output.
But when I connect my device and use PUTTY to send some commands first and then run my program it is working.
Maybe there is a problem in the way I am starting communication?
My source code is:
#include "stdafx.h"
#include <iostream>
//#include <windows.h>
#include <afx.h>
int main()
{
using namespace std;
int i=0;
// cout << "Hello world!" << endl;
HANDLE hSerial;
hSerial = CreateFile("COM5",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_WRITE | FILE_SHARE_READ,
0,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0);
if(hSerial==INVALID_HANDLE_VALUE)
{
if(GetLastError()==ERROR_FILE_NOT_FOUND)
{
// TRACE("serial port does not exist for reading\n");
//serial port does not exist. Inform user.
}
// TRACE("some other error,serial port does not exist for reading\n");
//some other error occurred. Inform user.
}
DCB dcbSerialParams = {0};
dcbSerialParams.DCBlength=sizeof(dcbSerialParams);
if (!GetCommState(hSerial, &dcbSerialParams))
{
// TRACE("error getting state for reading\n");
//error getting state
}
dcbSerialParams.BaudRate=9600;
dcbSerialParams.ByteSize=8;
dcbSerialParams.StopBits=ONESTOPBIT;
dcbSerialParams.Parity=NOPARITY;
if(!SetCommState(hSerial, &dcbSerialParams))
{
//TRACE("error setting state for reading\n");
//error setting serial port state
}
COMMTIMEOUTS timeouts={0};
timeouts.ReadIntervalTimeout=50;
timeouts.ReadTotalTimeoutConstant=50;
timeouts.ReadTotalTimeoutMultiplier=10;
timeouts.WriteTotalTimeoutConstant=50;
timeouts.WriteTotalTimeoutMultiplier=10;
if(!SetCommTimeouts(hSerial, &timeouts))
{
// TRACE("some error occured for reading\n");
//error occureed. Inform user
}
int n=100,n1=100;
char szBuff[100];
DWORD dwBytesRead = 0;
char szBuff1[100];
DWORD dwByteswrote = 0;
memset(szBuff1,0,100);
memcpy(szBuff1,"LIST\r",5);
if(!WriteFile(hSerial, szBuff1,5, &dwByteswrote, NULL))
{
cout << "error writing" ;
}
cout << szBuff1 << endl;
cout << dwByteswrote << endl;
while(1)
{
if(!ReadFile(hSerial, szBuff, n1, &dwBytesRead, NULL))
{
cout << "error reading";
break;
}
else
{
cout << dwBytesRead << endl;
szBuff[dwBytesRead]='\0';
if(dwBytesRead>0)
{
cout << (szBuff);
break;
}
}
}
cin >> i;
}
Try this... you will probably need to do the code for exceptions (ex: if the response is bigger than 2024)
bool SendModemATCommand(const string &strCommand, int iModemPort, string &strRetValue)
{
bool bRetValue = false;
strRetValue = "";
char cBuffer[2024];
HANDLE hCom = NULL;
char cComPort[64];
sprintf_s(cComPort,"\\\\.\\COM%d", iModemPort);
hCom = CreateFile( cComPort,
GENERIC_READ | GENERIC_WRITE,
0, // must be opened with exclusive-access
NULL, // no security attributes
OPEN_EXISTING, // must use OPEN_EXISTING
0, // not overlapped I/O
NULL // hTemplate must be NULL for comm devices
);
if (hCom != INVALID_HANDLE_VALUE)
{
COMMTIMEOUTS comTimeOuts;
comTimeOuts.ReadIntervalTimeout = MAXDWORD;
comTimeOuts.ReadTotalTimeoutMultiplier = MAXDWORD;
comTimeOuts.ReadTotalTimeoutConstant = 0;//MAXDWORD;
comTimeOuts.WriteTotalTimeoutMultiplier = 0;
comTimeOuts.WriteTotalTimeoutConstant = 0;
if(SetCommTimeouts(hCom, &comTimeOuts))
{
DCB dcb;
dcb.DCBlength = sizeof(DCB);
if(GetCommState(hCom, &dcb))
{
DWORD dwBytesWritten = 0;
DWORD dwBytesRead = 0;
DWORD dwBytesTotal = 0;
if( WriteFile(hCom, strCommand.c_str(), (int)strCommand.size(), &dwBytesWritten, NULL) )
{
if(dwBytesWritten == strCommand.size())
{
dwBytesRead = 0;
DWORD tickStart = GetTickCount();
bool bTimeOut = false;
while(true)
{
while(ReadFile(hCom, cBuffer + dwBytesTotal, 1, &dwBytesRead, NULL))
{
if(dwBytesRead == 0 && dwBytesTotal != dwBytesWritten)
break;
dwBytesTotal += dwBytesRead;
}
if ( dwBytesTotal == 0 )
{
// timeout
if ( GetTickCount() - tickStart > 10000) // 10 Seconds
{
bTimeOut = true;
break;
}
}
else
break;
}
cBuffer[dwBytesTotal] = '\0';
strRetValue = cBuffer;
if(bTimeOut)
strRetValue = "Timed out:" + strCommand;
else
bRetValue = true;
}
}
}
}
CloseHandle(hCom);
}
return bRetValue;
}
Most likely the problem is with your initialization.
I recall having this type of trouble before and Com Timeouts structure was particularly troublesome.
I suggest you get a null modem cable from COM5 to another port on the machine (if you have one), or to another computer. Then use a terminal program to open up the other port and see you can see the "List" command coming through when you run the program. If not then it's very likely to be related to the way you are initializing & opening the com port.
This link may prove useful. Just strip out the Afx stuff and look particularly at the initialization.
http://www.codeproject.com/KB/system/chaiyasit_t.aspx
One other suggestion, you only send List once. If the device is not already plugged in and ready, nothing will happen. Maybe it should keep sending the list command until it gets a
Response.
Also, do you need "List\r\n" or just "List\r"? What is the other ends expecting?

what are the functions i need use for serial communication in vc++?

I am working on an embeeded device.i connect to it using COM port.
It gives the list of all files when i send a command "LIST" to it.
so i wrote an "hello world" which will connect to the port device is connected and will send data.
When i connect my device and run my program it is writing to the port and not receiving any bytes from the port.
but when i open the COM port using PUTTY(which is used to open port and send some data) and send COMMAND it works and when i CLOSE PUTTY and NOW RUN MY PROGRAM now it is working fine,so i need to OPEN port with putty for the first time for my program to work.
may be i am not initialising some functions...:(
can anyone help me out in this,i am unable to find solution for the past day.thanks in advance...
my source code is:-
#include "stdafx.h"
#include <iostream>
#include <afx.h>
int main()
{
using namespace std;
int i=0;
// cout << "Hello world!" << endl;
HANDLE hSerial;
hSerial = CreateFile("COM5",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_WRITE | FILE_SHARE_READ,
0,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0);
if(hSerial==INVALID_HANDLE_VALUE)
{
if(GetLastError()==ERROR_FILE_NOT_FOUND)
{
// TRACE("serial port does not exist for reading\n");
//serial port does not exist. Inform user.
}
// TRACE("some other error,serial port does not exist for reading\n");
//some other error occurred. Inform user.
}
DCB dcbSerialParams = {0};
dcbSerialParams.DCBlength=sizeof(dcbSerialParams);
if (!GetCommState(hSerial, &dcbSerialParams))
{
// TRACE("error getting state for reading\n");
//error getting state
}
dcbSerialParams.BaudRate=9600;
dcbSerialParams.ByteSize=8;
dcbSerialParams.StopBits=ONESTOPBIT;
dcbSerialParams.Parity=NOPARITY;
dcbSerialParams.fOutX=TRUE;
dcbSerialParams.fInX=TRUE;
if(!SetCommState(hSerial, &dcbSerialParams))
{
//TRACE("error setting state for reading\n");
//error setting serial port state
}
COMMTIMEOUTS timeouts={0};
timeouts.ReadIntervalTimeout=50;
timeouts.ReadTotalTimeoutConstant=50;
timeouts.ReadTotalTimeoutMultiplier=10;
timeouts.WriteTotalTimeoutConstant=50;
timeouts.WriteTotalTimeoutMultiplier=10;
if(!SetCommTimeouts(hSerial, &timeouts))
{
// TRACE("some error occured for reading\n");
//error occureed. Inform user
}
int n=100,n1=100;
char szBuff[100];
DWORD dwBytesRead = 0;
char szBuff1[100];
DWORD dwByteswrote = 0;
memset(szBuff1,0,100);
memcpy(szBuff1,"LIST\r",5);
FlushFileBuffers(hSerial);
LPDWORD uf=0;
GetCommModemStatus(hSerial,uf);
TRACE("%d\n",uf);
if(!WriteFile(hSerial, szBuff1,5, &dwByteswrote, NULL))
{
cout << "error writing" ;
}
cout << szBuff1 << endl;
cout << dwByteswrote << endl;
dwByteswrote=0;
while(1)
{
if(!ReadFile(hSerial, szBuff, n1, &dwBytesRead, NULL))
{
cout << "error reading";
break;
}
else
{
cout << dwBytesRead << endl;
szBuff[dwBytesRead]='\0';
if(dwBytesRead>0)
{
cout << (szBuff);
break;
}
else
{
}
}
}
cin >> i;
}
You might try setting all the DCB options and clearing port errors
// Common settings
dcbSerialParams.DCBlength = sizeof( dcbSerialParams );
dcbSerialParams.ByteSize = 8;
dcbSerialParams.BaudRate = CBR_9600;
dcbSerialParams.fParity = FALSE;
dcbSerialParams.Parity = NOPARITY;
dcbSerialParams.StopBits = ONESTOPBIT;
dcbSerialParams.fDtrControl = 0;
dcbSerialParams.fRtsControl = 0;
// If you say so
dcbSerialParams.fOutX = TRUE;
dcbSerialParams.fInX = TRUE;
// Not so common settings
dcbSerialParams.fBinary = FALSE;
dcbSerialParams.fParity = FALSE;
dcbSerialParams.fOutxCtsFlow = FALSE;
dcbSerialParams.fOutxDsrFlow = FALSE;
dcbSerialParams.fDsrSensitivity = FALSE;
dcbSerialParams.fErrorChar = FALSE;
dcbSerialParams.fNull = FALSE;
dcbSerialParams.fAbortOnError = FALSE;
// Clear errors
unsigned long ulCommErr = 0;
ClearCommBreak( hSerial );
ClearCommError( hSerial, &ulCommErr, NULL );
Probably unrelated, but I noticed I at some point added a security descriptor to CreateFile() in my serial code, I believe some configuration of Windows Server required it.
// Allow access
SECURITY_ATTRIBUTES sa, *pSa = NULL;
sa.nLength = sizeof( SECURITY_ATTRIBUTES );
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = (SECURITY_DESCRIPTOR*)LocalAlloc(LPTR,SECURITY_DESCRIPTOR_MIN_LENGTH);
if ( sa.lpSecurityDescriptor
&& InitializeSecurityDescriptor( (SECURITY_DESCRIPTOR*)sa.lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION )
&& SetSecurityDescriptorDacl( (SECURITY_DESCRIPTOR*)sa.lpSecurityDescriptor, TRUE, (PACL)NULL, FALSE ) )
pSa = &sa;
// Open the port
hSerial = CreateFile( x_pPort,
GENERIC_READ | GENERIC_WRITE,
0,
pSa,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL );
if ( pSa )
LocalFree( pSa->lpSecurityDescriptor );
MSDN documentation of CreateFile demands using 0 as dwShareMode for Communications Resources like COM ports (you use FILE_SHARE_WRITE|FILE_SHARE_READ). Try this first. Even if it won't help it is better to follow the official documentation anyway.
If (1) doesn't work then try using CREATE_ALWAYS instead of OPEN_EXISTING. Actually OPEN_EXISTING is demanded by the documentation but one community message (on the same page after the official documentation) suggests using CREATE_ALWAYS for LPT ports (may be it is different though).