Using this guide/class (http://playground.arduino.cc/Interfacing/CPPWindows) I wrote a little application to send data on the serial port to an Arduino. (This will be added on a larger project later on)
int _tmain(int argc, _TCHAR* argv[]) {
Serial* SP = new Serial(argv[1]);
char outcomingData[256];
int dataLength = 255;
int sendData;
while (SP->IsConnected()) {
strcpy_s(outcomingData, argv[2]);
sendData = SP->WriteData(outcomingData, dataLength);
printf("%s", outcomingData);
}
return 0;
}
The problem is that the data is sent only when I close the application or delete SP through the destructor. How can I fix this? Is there a workaround or another method that I can add to the class?
It's likely that your data is being cached such that it isn't actually written to your serial device until CloseHandle is called in ~Serial. You can avoid this caching behavior by specifying FILE_FLAG_WRITE_THROUGH in your call to CreateFile, so that the file creation would look something like:
//Try to connect to the given port throuh CreateFile
this->hSerial = CreateFile(portName,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
NULL);
If that doesn't work, there's also FILE_FLAG_NO_BUFFERING, but that may impose limitations on the alignment of the data you write to the device.
If you would like to retain the normal buffering behavior, you could add a Serial::Flush method that calls FlushFileBuffers to force Windows to write any data it has cached out to the device:
void Serial::Flush()
{
FileFlushBuffers(this->hSerial);
}
You would then call SP->Flush() after SP->WriteData(...) to ensure that Windows' buffers are flushed to the device. This would allow you to make multiple small writes without having to flush each one, possibly improving performance.
As a side note, I would question your use of new here. It doesn't seem like it's really needed, and SP could just be constructed locally:
Serial SP(argv[1]);
Related
In my code I open a FIFO (created with mkfifo) and then I proceed to use a QSocketNotifier to receive notifications of incoming data, to read it while it arrives.
// create the FIFO
if(!mkfifo(SERIAL_FIFO, 0600)) {
// nonblocking open (even open itself would block until a first write)
in_fifo = ::open(SERIAL_FIFO, O_RDONLY | O_NONBLOCK);
if(in_fifo >= 0) {
// create notifier
in_fifo_notifier = new QSocketNotifier(in_fifo, QSocketNotifier::Read, this);
connect(&*in_fifo_notifier, &QSocketNotifier::activated,
this, [this](QSocketDescriptor /*socket*/, QSocketNotifier::Type /*type*/){
// copy all the available data
char buf[4096];
for(;;) {
ssize_t rl = ::read(in_fifo, buf, sizeof(buf));
if(rl <= 0) break;
::write(out_fd, buf, rl);
}
});
}
The problem is that, whenever someone writes on the other end of the pipe, the signal keeps getting activated (with associated 100% CPU usage), even though every time I read all the data. Where's the problem?
Ultimately, this is just a variation over the problem described here, as Qt under the hood uses select/epoll machinery to implement QSocketNotifier. Opening the FIFO as O_RDWR fixes the problem.
I'm new to serial programming, and am trying to make a program that sends bytes via the serial port to an Arduino, to control an LED array. For efficiency, I want to do this in C++ using the Windows API, with a high baud rate. Here's my minimal example which just sends a '1':
#include <windows.h>
DCB serialParams;
byte data[1];
DWORD bytessent;
int main(int argc, char* argv[])
{
data[0] = 1;
HANDLE arduino = CreateFile("/COM5", GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
serialParams.BaudRate = CBR_19200;
serialParams.ByteSize = 8;
serialParams.StopBits = ONESTOPBIT;
serialParams.Parity = NOPARITY;
SetCommState(arduino, &serialParams);
WriteFile(arduino, &data, 1, &bytessent, 0);
return 0;
}
This works well, except that calling the SetCommState function seems to send a whole load of random data to the port, which is a headache to try to sort from the actual data coming through. Is there a way in Windows API to close the port temporarily while making the changes? This should be possible as it can be done pretty easily in Python with pySerial:
from serial import Serial
s = Serial("/COM5")
s.close()
s.baudrate = 18400
s.open()
s.write([1])
SetCommState shouldn't send any data to port.
But, if you try to change/set some values of DCB, you should get data from port (use GetCommState), change desired values, and set new dcb.
More info here: https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-setcommstate
See "Remarks" section.
As per subject I'm trying to develop a simple piped parent/child program.
Main purpose of this program is to keep the child process alive and use std::cin and std::cout to communicate between parent/child processes.
On Linux all of this works quite well.
On Windows I've been following the example here and there's one peculiar difference with Linux: one has to invoke
CloseHandle(g_hChildStd_IN_Wr)
To write to the child pipe and flush it. This has the side effect to close the pipe, thus terminating my in-connection to the child process.
I've also tried to use FlushFileBuffers but it doesn't work.
Any idea how can I flush the buffer without having to close the anonymous pipe?
Below sources of both Parent and Child processes.
If the code of the parent process is basically the one in the example above:
// IN_Wr_ is initialized as below with bInheritHandle=TRUE
::CreatePipe(&IN_Rd_, &IN_Wr_, &saAttr, 0);
// and
::SetHandleInformation(IN_Wr_, HANDLE_FLAG_INHERIT, 0)
// When I spawn the child process I do
STARTUPINFO siStartInfo = {0};
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.hStdError = INVALID_HANDLE_VALUE;
siStartInfo.hStdOutput = OUT_Wr_;
siStartInfo.hStdInput = IN_Rd_;
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
...
// then in order to write to std::cin
const DWORD reqSz = static_cast<DWORD>(std::strlen(request));
DWORD written = 0;
while(true) {
DWORD curWritten = 0;
if(!WriteFile(IN_Wr_, request + written, reqSz-written, &curWritten, NULL))
throw std::runtime_error("Error on WriteFile");
written += curWritten;
if(written == reqSz) {
// all written, done
break;
}
}
::FlushFileBuffers(IN_Wr_);
// only when I do this CloseHandle then the child process
// is able to read data
::CloseHandle(IN_Wr_);
this child code is a simple echo server, along the lines of:
buif[2048+1];
while(std::cin) {
std::cin.read(buf, 2048);
const auto rb = std::cin.gcount();
buf[rb] = '\0';
std::cout << buf << std::endl; // this does flush
}
Here's your problem:
std::cin.read(buf, 2048);
It's doing exactly what you've asked it to: waiting until it has read 2048 characters or reaches the end of file. You're not sending 2048 characters, so nothing happens until the server closes the pipe, which counts as the end of file in this context.
Instead, you should be using something like getline(s, 2048, '\0') which will stop reading when it sees a null character. (And, of course, you will need to modify the sender so that it writes that null character at the end of the string.)
Alternatively, you could use the native API: ReadFile has the semantics you seem to be wanting. Ideally you would use a message-mode pipe, which is designed precisely for this sort of use.
The article here might be helpful: https://support.microsoft.com/en-us/kb/190351. It has a section on flushing problems when printf is used to send data to the redirected pipe, which seems to be done in your case. The suggested solution is to use fflush(NULL) to flush the C run-time IO buffers.
It looks like the issue is a MSFT implementation of std::cin::read (and even fread(..., ..., ..., stdin)).
If instead of relying on:
// C++ API
while(std::cin) {
std::cin.read(buf, 2048);
...
// or also "C" API
int rb = 0;
while(0 < (rb = fread(buf, 2048, 1, stdin))) {
...
I do
// Low level Win32 "C" API
while(::ReadFile(hStdin, buf, 2048, &rb, 0)) {
...
// or also low level unix-like "C" API
int rb = 0;
while(0 < (rb = _read(0, buf, 2048))) {
...
The above example just works fine (funnily enough, the call to FlushFileBuffers is not even needed).
I'm communicating between two processes on different machines via a pipe, using IO completion routines.
Occasionally, when the completion routine for WriteFileEx gets called, the completion routine parameter dwErrorCode is 0 (i.e. no error), GetOverlappedResult returns true (i.e. no error), but dwNumberOfBytesTransfered does not match nNumberOfBytesToWrite in the call to WriteFileEx. I only see this on the client end of the pipe however.
If the number of bytes transferred does not match the number of bytes that was requested to transfer, how can this be deemed a success?
This is how the client's handle to the pipe is created:
mHPipe = CreateFile(pipeName, // pipe name
GENERIC_READ | // read and write access
GENERIC_WRITE,
0, // no sharing
NULL, // default security attributes
OPEN_EXISTING, // opens existing pipe
FILE_FLAG_OVERLAPPED | // overlapped
FILE_FLAG_WRITE_THROUGH, // write through mode
NULL); // no template file
// do some checking...
// The pipe connected; change to message-read mode.
DWORD dwMode = PIPE_READMODE_MESSAGE;
BOOL fSuccess = SetNamedPipeHandleState(mHPipe, // pipe handle
&dwMode, // new pipe mode
NULL, // don't set maximum bytes
NULL); // don't set maximum time
Can anyone see why this would happen?
Thanks
EDIT:
The relevant WriteFileEx code is as follows:
void WINAPI CompletedWriteRoutine(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverLap)
{
BOOL fWrite = FALSE;
LPPIPEINST lpPipeInst = (LPPIPEINST)lpOverLap;
//
// ! 99.9% of the time, dwNumberOfBytesTransfered == lpPipeInst->cbDataSize
// but 0.1% of the time, they do not match
//
// Some stuff
// Copy next message to send
memcpy_s(lpPipeInst->chData, sizeof(lpPipeInst->chData), pMsg->msg, pMsg->size);
lpPipeInst->cbDataSize = pMsg->size;
// Some other stuff
fWrite = WriteFileEx(lpPipeInst->hPipeInst,
lpPipeInst->chData,
lpPipeInst->cbDataSize,
(LPOVERLAPPED) lpPipeInst,
(LPOVERLAPPED_COMPLETION_ROUTINE)CompletedWriteRoutine);
// Some other, other stuff
}
Where LPPIPEINST is declared as:
typedef struct
{
OVERLAPPED oOverlap; // must remain first item
HANDLE hPipeInst;
TCHAR chData[BUFSIZE];
DWORD cbDataSize;
} PIPEINST, *LPPIPEINST;
And the initial call to CompletedWriteRoutine is given the lpOverlap parameter declared thusly:
PIPEINST pipeInstWrite = {0};
pipeInstWrite.hPipeInst = client.getPipeHandle();
pipeInstWrite.oOverlap.hEvent = hEvent[eventWriteComplete];
EDIT:
After trying re-initializing the overlapped structure as Harry suggested, I noticed something peculiar.
I memset the OVERLAPPED structure to zero before each WriteFileEx, and roughly 1/5000 completion routine callbacks, the cbWritten parameter and the OVERLAPPED structure's InternalHigh member was now set to the size of the previous message, instead of the most recent message. I added some logging to file on both the client and server ends of the pipe inside the completion routines, and the data sent and received at both ends was an exact match (and the correct, expected data). This then unveiled that in the time taken to write the data to a file, the InternalHigh member in the OVERLAPPED structure had changed to now reflect the size of the message I was expecting (cbWritten remains the old message size). I removed the file logging, and am now able to reproduce the issue like clockwork with this code:
void WINAPI CompletedWriteRoutine(DWORD dwErr, DWORD cbWritten, LPOVERLAPPED lpOverLap)
{
LPPIPEINST lpPipeInst = (LPPIPEINST)lpOverLap;
// Completion routine says it wrote the amount of data from the previous callback
if (cbWritten != lpPipeInst->cbDataSize)
{
// Roughly 1 in 5000 callbacks ends up in here
OVERLAPPED ovl1 = lpPipeInst->oOverlap; // Contains size of previous message, i.e. cbWritten
Sleep(100);
OVERLAPPED ovl2 = lpPipeInst->oOverlap; // Contains size of most recent message, i.e lpPipeInst->cbDataSize
}
...
}
It seems that sometimes, the completion routine is being called before the OVERLAPPED structure and the completion routine input parameter is updated. I'm using MsgWaitForMultipleObjectsEx(eventLast, hEvent, INFINITE, QS_POSTMESSAGE, MWMO_ALERTABLE); for the completion routines to be called on Windows 7 64 bit.
This MSDN page says:
"The system does not use the OVERLAPPED structure after the completion routine is called, so the completion routine can deallocate the memory used by the overlapped structure."
...so apparently, what this code can reproduce should never happen?
Is this a WINAPI bug?
Added FILE_FLAG_NO_BUFFERING to the CreateFile call - haven't seen the problem since. Thanks everyone who commented for your time.
I want to programmaticaly check for the available serial ports which are not connected with any device.
i tried the following code and able to get the available com ports but dont know whether it is used. how to determine that?
TCHAR szComPort[8];
HANDLE hCom = NULL;
for (int i = 1; i <= 10; ++i)
{
if (i < 10)
wsprintf(szComPort, _T("COM%d"), i);
else
wsprintf(szComPort, _T("\\\\.\\COM%d"), i);
hCom = CreateFile(szComPort,
GENERIC_READ|GENERIC_WRITE, // desired access should be read&write
0, // COM port must be opened in non-sharing mode
NULL, // don't care about the security
OPEN_EXISTING, // IMPORTANT: must use OPEN_EXISTING for a COM port
0, // usually overlapped but non-overlapped for existance test
NULL); // always NULL for a general purpose COM port
}
Unlike USB, there's no reliable method to check whether a serial (RS232) port is connected. It's quite common to use just TD, RD and ground (transmit/receive). Even when other pins are connected, their use isn't well standardized.