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
Related
Im trying to understand how serial communication works through windows API. Im using an Wemos board to send the message and reading in a C++ program. Both of these functions im using work. The HANDLE is a class variable. This is non overlapped and its a "listener":
void Serial::ReadSerialPort(int length)
{
char* message = new char[length];
DWORD nBytesRead;
DWORD dwEvtMask;
DWORD errors;
BOOL bResult;
COMSTAT status;
ClearCommError(hCOM, &errors, &status);
SetCommMask(hCOM, EV_RXCHAR | EV_ERR); //receive character event
while (WaitCommEvent(hCOM, &dwEvtMask, 0)) { //wait for character
if (dwEvtMask & EV_RXCHAR)
bResult = ReadFile(hCOM, message, length, &nBytesRead, 0);
else if (dwEvtMask & EV_ERR)
std::cout << "error: " << dwEvtMask << std::endl;
if (bResult && nBytesRead == 0)
{
std::cout << "end of file\n"; // this never happens anyway
}
//printing
for (int i = 0; i < length; i++)
std::cout << message[i];
}
}
This is overlapped:
LPCSTR Serial::ReadSerialPortOverlapped(int length) {
OVERLAPPED osReader = { 0 };
BOOL fWaitingOnRead = FALSE;
BOOL bResult;
char* message = new char[length];
DWORD dwBytesTransferred;
DWORD dwError;
SetCommMask(hCOM, EV_RXCHAR | EV_ERR); //receive character event
// Create the overlapped event. Must be closed before exiting
// to avoid a handle leak.
osReader.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
// Error creating overlapped event; abort.
if (osReader.hEvent == NULL) {
std::cout << "error";
}
if (!fWaitingOnRead) {
// Issue read operation.
bResult = ReadFile(hCOM, message, length, &dwBytesTransferred, &osReader);
if (!bResult) {
if (GetLastError() != ERROR_IO_PENDING)
std::cout << "error\n" << std::endl;
else {
fWaitingOnRead = TRUE;
while (fWaitingOnRead)
{
fWaitingOnRead = FALSE;
//pending
bResult = GetOverlappedResult(hCOM,
&osReader,
&dwBytesTransferred,
FALSE);
if (!bResult)
{
switch (dwError = GetLastError())
{
case ERROR_HANDLE_EOF:
{
// Handle an end of file
printf("GetOverlappedResult found EOF\n");
break;
}
case ERROR_IO_INCOMPLETE:
{
// still incomplete
fWaitingOnRead = TRUE;
break;
}
}
}
else
{
// completed
// Manual-reset event should be reset since it is now signaled.
ResetEvent(osReader.hEvent);
}
}
}
}
else {
// read completed immediately
}
return message;
}
}
What i dont understand is that both of them will only work if i know beforehand the length of the message. If i provide a bigger buffer, let say for example, my message is "test", and my buffer is 10 in size, it will read the message but will keep waiting for more. But what if there isnt more, and i dont know the length beforehand? If i set a smaller buffer, for example, 1, and the message is bigger, it will only read the first character and skip the rest. This is a little weird to me because i was used to the recv() function where you can use a bigger buffer and it will stop reading when it finds that the stream is over. In arduino, Serial.read() with Serial.available() seems to be able to recognize the end of the stream.
Im accepting any tip on good ways to do this. Thanks!
I am reading continuous serial data which is being sent as 29 byte array
with the first byte which is the header as a value of oxD1.
How can pick the data in the buffer starting from the Header.
This is my code.
int SerialPort::readSerialPortFreedPacket(BYTE *buffer, unsigned int
buf_size)
{
DWORD bytesRead;
int timeout = 500;
OVERLAPPED ovread = { 0 };
ovread.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (ovread.hEvent == NULL) {
// Error creating overlapped event; abort.
return FALSE;
}
if (!ReadFile( this->handler , (void*)buffer, 29, &bytesRead, &ovread)) {
if (GetLastError() != ERROR_IO_PENDING) {
// Handle error in communications
std::cout << "Error reading data " << std::endl;
}
else {
DWORD ret = WaitForSingleObject(ovread.hEvent, timeout);
switch (ret) {
case WAIT_OBJECT_0:
// HandleASuccessfulRead(buf, bytesRead);
std::cout << buffer << std::endl;
break;
case WAIT_TIMEOUT:
// Handle timeout
break;
case WAIT_FAILED:
// Handle failure
break;
default:
// what else to handle?
break;
}
}
}
else {
// read completed immediately
//HandleASuccessfulRead(buf,bytesRead);
}
return 0;
}
I am trying jni interfacing for serial port programming, using Microsoft Visual Studio 11 with .NET 4.0.
I get he following error when I try to read from the comm port:
time out happened in PortRead()
The read time out value is set to 5sec.
The following is a part of the code:
Also, since my laptop is 64 bit I'm using a bafo ie a 64 to 32 bit converter, and then attach the rs232 wire.
JNIEXPORT jint JNICALL Java_JavaSerial_Read(JNIEnv *env, jobject obj)
{
jint idata = 0;
char cdata[8];
ERR_CODE rc = OK;
CommPortClass* commClass;
commClass = new CommPortClass;
commClass->iMaxChars = 1;
rc = PortRead(commClass);
if (rc != OK)
Msg("ERROR in PortRead()! ");
sprintf_s(cdata, "%d", commClass->pcBuffer[0]);
idata = atoi(cdata);
delete commClass;
return idata;
}
//Port read function
ERR_CODE PortRead(CommPortClass *hCommPort)
{
HANDLE hThread; // handler for port read thread
DWORD IDThread;
DWORD Ret, ExitCode;
DWORD dTimeout = 5000; // define time out value: 5 sec.
ERR_CODE ecStatus = OK;
if (!(hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) ThreadFunc, (LPVOID)hCommPort, CREATE_SUSPENDED, &IDThread) ) )
// no security attributes, use default stack size, parameter to thread function, creation flag - suspended, returns thread ID
{
Msg("Create Read Thread failed");
return EC_CREATE_THREAD;
}
ResumeThread(hThread); // start thread now
Ret = WaitForSingleObject(hThread, dTimeout);
if (Ret == WAIT_OBJECT_0)
{
// Data received & process it... need to do nothing because the data is stored in the
// hCommPort in the Thread Function. The only thing is to close thread handle
CloseHandle(hThread);
}
else if (Ret == WAIT_TIMEOUT) // Time out happened
{
// Warning & kill thread
Ret = GetExitCodeThread(hThread, &ExitCode);
Msg("Time out happened in PortRead() ");
if (ExitCode == STILL_ACTIVE)
{
TerminateThread(hThread, ExitCode);
CloseHandle(hThread);
return EC_RECV_TIMEOUT;
}
else
{
CloseHandle(hThread);
Msg("ERROR in GetExitCodeThread: != STILL_ACTIVE ");
ecStatus = EC_EXIT_CODE;
}
}
else
{
Msg("ERROR in WaitFor SingleObject ");
ecStatus = EC_WAIT_SINGLEOBJ;
}
return ecStatus;
}
//Thread() function
void WINAPI ThreadFunc(void* hCommPorts)
{
char Byte;
BOOL bResult, fDone;
int nTotRead = 0;
DWORD dwCommModemStatus, dwBytesTransferred;
CommPortClass* CommPorts;
ERR_CODE ecStatus = OK;
CommPorts = (CommPortClass* )hCommPorts;
// Specify a set of events to be monitored for the port.
SetCommMask(hPort, EV_RXCHAR | EV_CTS | EV_DSR | EV_RLSD | EV_RING);
fDone = FALSE;
while (!fDone)
{
// Wait for an event to occur for the port.
WaitCommEvent(hPort, &dwCommModemStatus, 0);
// Re-specify the set of events to be monitored for the port.
SetCommMask(hPort, EV_RXCHAR | EV_CTS | EV_DSR |EV_RLSD| EV_RING);
if (dwCommModemStatus & EV_RXCHAR||dwCommModemStatus & EV_RLSD)
{
// received the char_event & loop to wait for the data.
do
{
// Read the data from the serial port.
bResult = ReadFile(hPort, &Byte, 1, &dwBytesTransferred, 0);
if (!bResult)
{
Msg("ERROR in ReadFile !");
fDone = TRUE;
break;
}
else
{
// Display the data read.
if (dwBytesTransferred == 1)
{
CommPorts->pcBuffer[nTotRead] = Byte;
nTotRead++;
if (nTotRead == CommPorts->iMaxChars)
{
fDone = TRUE;
break;
}
}
else
{
if (Byte == 0x0D ||Byte == 0x0A) // null char or CR
{
Msg("Received null character ");
fDone = TRUE;
break;
}
}
}
} while (dwBytesTransferred == 1); //while (nTotRead < pRecv->iMaxChars);
} // if
} // while
return;
}
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?
I'm trying to make a modem call in one end, and in the other end the program answers the call. It doesn't seem to detect the carrier. Am I doing anything wrong? Am I missing something?
int main(int argc, char** argv)
{
ParseArgs(argc,argv);
SerialPort* port = SerialPort::New();
if(!port)
Error(ErrorNoMemory,"Can't create port");
int error = port->Open(PortNum, SendFlag);
if(error)
Error(error,"Can't open port");
error = port->Initialise(PortBaud);
if(error)
Error(error,"Can't initialise port");
if(ReceiveFlag)
{
port->Listen();
Receive(port); //after the call is stablished I send a file
}
else
{
port->Dial(PhoneNumber);
Send(port);
}
port->Close();
delete port;
return 0;
}
The part of opening the port:
int Open(unsigned port, bool SendFlag)
{
// make name for port...
char name[] = "\\\\.\\com???.???";
char* nameNumber = name+sizeof(name)-8;
char* nameEnd = nameNumber;
if(port>999){
return ErrorInvalidPort;
}
if(port>99)
{
*nameEnd++ = '0'+port/100;
port %= 100;
}
if(port>9)
{
*nameEnd++ = '0'+port/10;
port %= 10;
}
*nameEnd++ = '0'+port;
*nameEnd = 0;
// open port...
hSerial = CreateFile(name, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if(hSerial==INVALID_HANDLE_VALUE)
{
switch(GetLastError())
{
case ERROR_FILE_NOT_FOUND:
return ErrorInvalidPort;
case ERROR_ACCESS_DENIED:
return ErrorPortInUse;
default:
return Error();
}
}
SetupComm( hSerial, 1024, 1024 );
if (!SendFlag)
{
if (!SetCommMask(hSerial, EV_RING |EV_RLSD))
// Error setting communications mask
printf("error mascara");
}
else
{
if (!SetCommMask(hSerial, EV_RLSD))
{
// Error setting communications mask
printf("error mascara");
}
}
return 0;
}
The initialise part:
int Initialise(unsigned baud)
{
// flush port...
if(!FlushFileBuffers(hSerial))
return Error();
if(!PurgeComm(hSerial, PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR))
return Error();
// configure port...
DCB dcb ;
if(!GetCommState(hSerial, &dcb))
return Error();
dcb.BaudRate = CBR_115200;
dcb.ByteSize = 8;
dcb.StopBits = ONESTOPBIT;
dcb.Parity = NOPARITY;
if(!SetCommState(hSerial, &dcb))
{
if(GetLastError()==ERROR_INVALID_PARAMETER)
return ErrorInvalidSettings;
return Error();
}
// set timeouts to zero so read/writes return immediately...
COMMTIMEOUTS timeouts = {0};
timeouts.ReadIntervalTimeout = MAXDWORD;
timeouts.ReadTotalTimeoutConstant = 0;
timeouts.ReadTotalTimeoutMultiplier = 0;
timeouts.WriteTotalTimeoutConstant = 0;
timeouts.WriteTotalTimeoutMultiplier= 0;
if(!SetCommTimeouts(hSerial, &timeouts))
return Error();
// flush port again...
if(!PurgeComm(hSerial, PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR))
return Error();
return 0;
}
The dial part:
int Dial(char *telefono)
{
unsigned long int n = 0;
DWORD dwCommEvent;
DWORD bytes;
DWORD dwRead;
char cadena[15];
char chRead;
sprintf(cadena, "ATDT%s\r", telefono);
if (!WriteFile( hSerial, "ATH1\r", strlen("ATH1\r"), (&(n)), 0 ))
{
printf("error");
}
FlushFileBuffers( hSerial );
Sleep(1000);
if (!WriteFile( hSerial, cadena, strlen(cadena), (&(n)), 0))
{
printf("error");
}
FlushFileBuffers( hSerial );
Sleep(10000);
printf("Marcamos");
do
{
printf("Espero eventos");
if(WaitCommEvent(hSerial, &dwCommEvent, NULL))
{
if(dwCommEvent & EV_RLSD)
{
printf("rlsd");
break;
}
else
{
printf("otro");
}
}
printf("fin del bucle");
} while(true);
return 0;
}
The listening part:
int Listen()
{
DWORD dwCommEvent;
unsigned long int n = 0;
do
{
printf("ESpero eventos");
if(WaitCommEvent(hSerial, &dwCommEvent, NULL))
{
if(dwCommEvent & EV_RING)
{
printf("RING");
if (!WriteFile( hSerial, "ATA\r", strlen("ATA\r"), (&(n)), 0 ))
{
printf("error");
}
FlushFileBuffers( hSerial );
break;
}
else if (dwCommEvent & EV_RLSD )
{
break;
}
}
printf("fin del bucle");
} while(true);
return 0;
}
You might have an easier time of it using Microsoft's Telephony API (TAPI) rather than trying to talk to the modem directly.
You may want to try issuing an ATS0=1 on the receiving side and let the modem autoanswer (substitute the number of rings you want instead of 1 if you wish).
You may discover that smart modems don't always pass through the ring (EV_RING) signal.
EDIT: Don't forget to 'ATS0=0' when you don't want the modem to auto-answer any more.
Maybe you need to apply the A0 and / or S0=1 Hayes command on the answering side.