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;
}
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!
First time using IO Completion Ports. I'm having an issue where the GetQueuedCompletionStatus returns a Null for the Completion Key, which I am using to pass a data struct with handles for other portions of the code.
The GetQueuedCompletionStatus seems to be triggering off messages received just fine otherwise.
I tried to include just the code involving the IO Completion ports:
The Data Structs:
typedef struct _THREAD_MESSAGE
{
mutex cmd_mtx;
string command;
} THREAD_MESSAGE, * LPTHREAD_MESSAGE;
typedef struct _LISTEN_SOCKET_DATA
{
SOCKET Socket;
int Port;
HANDLE hAcceptEvent;
HANDLE IOCP;
VOID* MessageProcessor;
ConfigHandler* CfgHandle;
// Other information useful to be associated with the handle
} LISTEN_SOCKET_DATA, * LPLISTEN_SOCKET_DATA;
typedef struct _CONNECTED_SOCKET_DATA
{
SOCKET Socket;
int Port;
HANDLE IOCP;
VOID* MessageProcessor;
ConfigHandler* CfgHandle;
} CONNECTED_SOCKET_DATA, * LPCONNECTED_SOCKET_DATA;
#define OPERATION_TYPE_UNKNOWN 0
#define OPERATION_TYPE_SEND 1
#define OPERATION_TYPE_RECV 2
typedef struct
{
OVERLAPPED* Overlapped;
CHAR Buffer[DATA_BUFSIZE];
int BufferLen;
int OperationType;
string PacketName;
} PER_IO_OPERATION_DATA, * LPPER_IO_OPERATION_DATA;
The completion port was initialized with:
m_CompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
The Listener:
//Thread for handling Listener sockets and Accepting connections
DWORD ListenThread(LPVOID lpParam)
{
LPLISTEN_SOCKET_DATA pSocketData = (LPLISTEN_SOCKET_DATA)(lpParam);
WSANETWORKEVENTS NetworkEvents;
DWORD dwRet;
SOCKADDR_IN NewSockAddr;
SOCKET NewSocket;
int nLen;
while (true) //run forever
{
//Wait for event
dwRet = WSAWaitForMultipleEvents(1,
&(pSocketData->hAcceptEvent),
false,
100,
false);
//Nothing happened, back to top
if (dwRet == WSA_WAIT_TIMEOUT)
continue;
//We got a event, find out which one.
int nRet = WSAEnumNetworkEvents(pSocketData->Socket,
pSocketData->hAcceptEvent,
&NetworkEvents);
if (nRet == SOCKET_ERROR)
{
wprintf(L"WSAEnumNetworkEvents error %ld\n", WSAGetLastError());
break;
}
//We got a Accept event
if (NetworkEvents.lNetworkEvents & FD_ACCEPT)
{
//Check for errors
if (NetworkEvents.iErrorCode[FD_ACCEPT_BIT] == 0)
{
// Accept new connection
nLen = sizeof(SOCKADDR_IN);
NewSocket = accept(pSocketData->Socket,
(LPSOCKADDR)&NewSockAddr,
&nLen);
if (NewSocket == SOCKET_ERROR)
{
wprintf(L"accept() error %ld\n", WSAGetLastError());
break;
}
wprintf(L"Accepted Connection %ld", NewSockAddr.sin_addr.S_un.S_addr);
//Set new connection as TCP connection, No Delay
const char chOpt = 1;
int nErr = setsockopt(NewSocket, IPPROTO_TCP, TCP_NODELAY, &chOpt, sizeof(char));
if (nErr == -1)
{
wprintf(L"setsockopt() error %ld\n", WSAGetLastError());
break;
}
LPCONNECTED_SOCKET_DATA ConnectedSocketData = new CONNECTED_SOCKET_DATA;
ZeroMemory(ConnectedSocketData, sizeof(CONNECTED_SOCKET_DATA));
ConnectedSocketData->Socket = NewSocket;
ConnectedSocketData->Port = pSocketData->Port;
ConnectedSocketData->IOCP = pSocketData->IOCP;
ConnectedSocketData->CfgHandle = pSocketData->CfgHandle;
ConnectedSocketData->MessageProcessor = pSocketData->MessageProcessor;
//Add the new socket to the completion port, message from the socker will be queued up for proccessing by worker threads.
if (CreateIoCompletionPort((HANDLE)NewSocket, pSocketData->IOCP, (DWORD)ConnectedSocketData, 0) == NULL)
{
wprintf(L"CreateIOCompletionPort error %ld\n", WSAGetLastError());
delete ConnectedSocketData;
ConnectedSocketData = NULL;
closesocket(NewSocket);
break;
}
//Set the PerIOData, will be used at completion time
LPPER_IO_OPERATION_DATA PerIOOperationData = new PER_IO_OPERATION_DATA;
PerIOOperationData->BufferLen = 0;
PerIOOperationData->OperationType = OPERATION_TYPE_RECV;
DWORD RecvBytes = 0;
DWORD Flags = 0;
WSABUF DataBuf;
DataBuf.len = DATA_BUFSIZE;
DataBuf.buf = PerIOOperationData->Buffer;
PerIOOperationData->Overlapped = new OVERLAPPED;
ZeroMemory(PerIOOperationData->Overlapped, sizeof(OVERLAPPED));
//Kick off the first Recv request for the Socket, will be handled by the completion Queue.
if (WSARecv(NewSocket, &DataBuf, 1, &RecvBytes, &Flags, (PerIOOperationData->Overlapped), NULL) == SOCKET_ERROR)
{
wprintf(L"WSARecv error %ld\n", WSAGetLastError());
return 0;
}
}
else
{
wprintf(L"Unknown network event error %ld\n", WSAGetLastError());
break;
}
}
}
}
The Worker Thread, it crashes when it tries to use ConnectedSocketData due to the struct being null:
// Worker thread, processes IOCP messages.
DWORD ServerWorkerThread(LPVOID lpParam)
{
HANDLE CompletionPort = (HANDLE)lpParam;
DWORD BytesTransferred = 0;
OVERLAPPED* lpOverlapped = NULL;
LPCONNECTED_SOCKET_DATA ConnectedSocketData = NULL;
LPPER_IO_OPERATION_DATA PerIoData = NULL;
DWORD Flags = 0;
WSABUF DataBuf;
DWORD RecvBytes = 0;
int DestinationAddress = 0;
while (TRUE)//run forever
{
//Check for new message
if (GetQueuedCompletionStatus(CompletionPort, &BytesTransferred, (PULONG_PTR)&ConnectedSocketData, (LPOVERLAPPED*)&lpOverlapped, INFINITE) == 0)
{
DWORD Err = GetLastError();
if (Err != WAIT_TIMEOUT)
{
printf("GetQueuedCompletionStatus() failed with error %d\n", Err);
if (closesocket(ConnectedSocketData->Socket) == SOCKET_ERROR)
{
printf("closesocket() failed with error %d\n", WSAGetLastError());
return 0;
}
GlobalFree(ConnectedSocketData);
}
continue;
}
// retrieve IO data
PerIoData = CONTAINING_RECORD(lpOverlapped, PER_IO_OPERATION_DATA, Overlapped);
vector<SiteData>::iterator SiteDataIterator;
vector<InstrumentData>::iterator InstrumentDataIterator;
for (SiteDataIterator = ConnectedSocketData->CfgHandle->SiteConnections.begin();
SiteDataIterator != ConnectedSocketData->CfgHandle->SiteConnections.end();
SiteDataIterator++)
{
if (SiteDataIterator->Port == ConnectedSocketData->Port)
{
break;
}
}
Any Ideas why the IOCP is not passing the Completion Key?
Any Ideas why the IOCP is not passing the Completion Key?
of course it passing back exactly what you pass to CreateIoCompletionPort and I/O in place pointer to OVERLAPPED
but at first
CreateIoCompletionPort((HANDLE)NewSocket, pSocketData->IOCP, (DWORD)ConnectedSocketData, 0)
is wrong - only low 32 bit of ConnectedSocketData is used here, must be
CreateIoCompletionPort((HANDLE)NewSocket, pSocketData->IOCP, (DWORD_PTR)ConnectedSocketData, 0)
then, your definition of PER_IO_OPERATION_DATA
typedef struct
{
OVERLAPPED* Overlapped;
CHAR Buffer[DATA_BUFSIZE];
int BufferLen;
int OperationType;
string PacketName;
} PER_IO_OPERATION_DATA, * LPPER_IO_OPERATION_DATA;
is always and critical error. must be
typedef struct
{
OVERLAPPED Overlapped;
CHAR Buffer[DATA_BUFSIZE];
int BufferLen;
int OperationType;
string PacketName;
} PER_IO_OPERATION_DATA, * LPPER_IO_OPERATION_DATA;
by Overlapped (when it defined as OVERLAPPED* Overlapped ) impossible take back address of PER_IO_OPERATION_DATA. but from &Overlapped (when it defined as OVERLAPPED Overlapped ) already possible.
i be better do next definition
struct PER_IO_OPERATION_DATA : public OVERLAPPED
{
CHAR Buffer[DATA_BUFSIZE];
int BufferLen;
int OperationType;
string PacketName;
};
and use
WSARecv(NewSocket, &DataBuf, 1, &RecvBytes, &Flags, PerIOOperationData, NULL)
and
PerIoData = static_cast<PER_IO_OPERATION_DATA*>(lpOverlapped);
you wrong handle case when GetQueuedCompletionStatus return false - you leak PerIoData it this case.
this is only top errors in your code, related to your direct question
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
I have a project which you can create named pipes in c# or c++ and this program will work as a middle man and simply pass the data on. Used to maintain integrity. Though in one of my while loops when I debug it I step on the while loop then it will cancel the steps and not process the while loop. It reaches line 107 of this code. If you need more of my files I will be happy to post them if needed.
//Information\\
//----------------------------------------\\
//File Name: NamedPipes.cpp
//Date Of Creation: 03/12/2019
//Purpose
/*
This file is to handle the interprocess communication
between the pipes.
*/
//----------------------------------------\\
//Internal Includes\\
//----------------------------------------\\
#include "NamedPipes.h"
#include "MiddleMan.h"
//----------------------------------------\\
//Global Variables\\
//----------------------------------------\\
struct Connection NamedPipes::Server;
struct Connection NamedPipes::Client;
//----------------------------------------\\
//Functions\\
//----------------------------------------\\
int NamedPipes::CreateServer()
{
try
{
LPTSTR lpszPipename = (LPTSTR)"\\\\.\\pipe\\Omni3";
LPTSTR lpszPipename2 = (LPTSTR)"\\\\.\\pipe\\Omni4";
while (1) {
Server.Write = CreateNamedPipe(lpszPipename, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 1024 * 16, 1024 * 16, NMPWAIT_USE_DEFAULT_WAIT, NULL);
Server.Read = CreateNamedPipe(lpszPipename2, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 1024 * 16, 1024 * 16, NMPWAIT_USE_DEFAULT_WAIT, NULL);
if (Server.Write == INVALID_HANDLE_VALUE)
{
return -1;
}
if (ConnectNamedPipe(Server.Write, NULL) != FALSE) // wait for someone to connect to the pipe
{
Server.Connected = true;
DWORD dwThreadId = 0;
HANDLE hThread = CreateThread(
NULL, // no security attribute
0, // default stack size
(LPTHREAD_START_ROUTINE)MiddleMan::Pass, // thread proc
(LPVOID)&Server, // thread parameter
0, // not suspended
&dwThreadId); // returns thread ID
}
}
return 1;
}
catch (exception ex)
{
}
return 0;
}
int NamedPipes::CreateClient()
{
try
{
DWORD last_error;
unsigned int elapsed_seconds = 0;
const unsigned int timeout_seconds = 5;
LPTSTR lpszPipename = (LPTSTR)"\\\\.\\pipe\\Omni1";
LPTSTR lpszPipename2 = (LPTSTR)"\\\\.\\pipe\\Omni2";
Client.Read = CreateFile(lpszPipename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
Client.Write = CreateFile(lpszPipename2, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
while (INVALID_HANDLE_VALUE == Client.Read &&
elapsed_seconds < timeout_seconds)
{
last_error = GetLastError();
if (last_error != ERROR_PIPE_BUSY)
{
break;
}
Sleep(1000);
elapsed_seconds++;
Client.Read = CreateFile(lpszPipename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
Client.Write = CreateFile(lpszPipename2, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
}
if (INVALID_HANDLE_VALUE == Client.Read)
{
std::cerr << "Failed to connect to pipe " << lpszPipename <<
": last_error=" << last_error << "\n";
return 0;
}
else
{
std::cout << "Connected to pipe " << lpszPipename << "\n";
}
DWORD dwThreadId = 0;
Client.Connected = true;
HANDLE hThread = CreateThread(
NULL, // no security attribute
0, // default stack size
(LPTHREAD_START_ROUTINE)MiddleMan::Pass, // thread proc
(LPVOID)&Client, // thread parameter
0, // not suspended
&dwThreadId); // returns thread ID
return 1;
}
catch (exception ex)
{
}
return 0;
}
/*
This function will loop until it recieves a transmission from the external UI.
*/
string NamedPipes::RecieveInformation(HANDLE Pipe)
{
BOOL fSuccess;
char chBuf[2048];
DWORD cbRead;
int i;
try
{
while (true)
{
if (Pipe) {
fSuccess = ReadFile(Pipe, chBuf, 2048, &cbRead, NULL);
if (cbRead != NULL && fSuccess)
{
string s(chBuf);
s.resize(cbRead);
printf("Pipe Recieved: %s\n", s.c_str());
return s;
}
printf("Error: Couldn't Read Pipe\n");
Sleep(500);
}
else
{
printf("Error: Invalid Pipe\n");
}
}
return "";
}
catch (exception ex)
{
printf("Error: %s\n", ex.what());
}
catch (...)
{
printf("Error Unknown\n");
}
}
int NamedPipes::SendInformation(HANDLE Pipe, string Information)
{
char buf[2048];
DWORD cbWritten;
try
{
strcpy(buf, Information.c_str());
if (!WriteFile(Pipe, buf, (DWORD)strlen(buf), &cbWritten, NULL))
{
printf("Message Sending Failed. Error: %d\n", GetLastError());
}
}
catch (exception ex)
{
}
return 1;
}
//----------------------------------------\\
EDIT: If it helps this is MiddleMan::Pass
void MiddleMan::Pass(LPVOID Pipe2)
{
Connection Pipe = *(Connection *)Pipe2;
while (1)
{
string Information = NamedPipes::RecieveInformation(Pipe.Read);
if (Information != "") {
if (Pipe.Read == NamedPipes::Server.Read)
{
if (NamedPipes::Client.Connected) {
NamedPipes::SendInformation(NamedPipes::Client.Write, Information);
}
}
else if (Pipe.Read == NamedPipes::Client.Read)
{
if (NamedPipes::Server.Connected) {
NamedPipes::SendInformation(NamedPipes::Server.Write, Information);
}
}
}
}
}
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.