I am writing a serial communication code in c++ on Visual Studio 2010. For this I try this example, which is working fine. Now, I try to send a string and read it back by shorting Rx and Tx pins of my hardware. Here is my code for sending string:-
char *buffer ="hello";
DWORD bytesSend;
DWORD errors;
COMSTAT status;
DWORD numWritten;
WriteFile(hCom, buffer, strlen(buffer), &numWritten, NULL);
printf("send succesfully\n");
and here is my receiving code:-
DWORD numRead;
BOOL ret = ReadFile(hCom, buffer, 5, &numRead, NULL);
if(!ret)
{
printf("Read Fail\n");
}
else
{
printf("%s\n",buffer);
}
On running my code, receive is getting failed. So, please tell me where is the problem. here is my complete code.
#include "stdafx.h"
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
void PrintCommState(DCB dcb)
{
// Print some of the DCB structure values
_tprintf( TEXT("\nBaudRate = %d, ByteSize = %d, Parity = %d, StopBits = %d\n"),
dcb.BaudRate,
dcb.ByteSize,
dcb.Parity,
dcb.StopBits );
}
int _tmain( )
{
DCB dcb;
HANDLE hCom;
BOOL fSuccess;
TCHAR *pcCommPort = TEXT("COM1"); // Most systems have a COM1 port
// Open a handle to the specified com port.
hCom = CreateFile( pcCommPort,
GENERIC_READ | GENERIC_WRITE,
0, // must be opened with exclusive-access
NULL, // default 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)
{
// Handle the error.
printf ("CreateFile failed with error %d.\n", GetLastError());
return (1);
}
// Initialize the DCB structure.
SecureZeroMemory(&dcb, sizeof(DCB));
dcb.DCBlength = sizeof(DCB);
// Build on the current configuration by first retrieving all current
// settings.
fSuccess = GetCommState(hCom, &dcb);
if (!fSuccess)
{
// Handle the error.
printf ("GetCommState failed with error %d.\n", GetLastError());
return (2);
}
PrintCommState(dcb); // Output to console
// Fill in some DCB values and set the com state:
// 57,600 bps, 8 data bits, no parity, and 1 stop bit.
dcb.BaudRate = CBR_57600; // baud rate
dcb.ByteSize = 8; // data size, xmit and rcv
dcb.Parity = NOPARITY; // parity bit
dcb.StopBits = ONESTOPBIT; // stop bit
fSuccess = SetCommState(hCom, &dcb);
if (!fSuccess)
{
// Handle the error.
printf ("SetCommState failed with error %d.\n", GetLastError());
return (3);
}
// Get the comm config again.
fSuccess = GetCommState(hCom, &dcb);
if (!fSuccess)
{
// Handle the error.
printf ("GetCommState failed with error %d.\n", GetLastError());
return (2);
}
PrintCommState(dcb); // Output to console
_tprintf (TEXT("Serial port %s successfully reconfigured.\n"), pcCommPort);
char *buffer ="hello";
DWORD bytesSend;
DWORD errors;
COMSTAT status;
DWORD numWritten;
WriteFile(hCom, buffer, strlen(buffer), &numWritten, NULL);
printf("send succesfully\n");
DWORD numRead;
BOOL ret = ReadFile(hCom, buffer, 5, &numRead, NULL);
if(!ret)
{
printf("Read Fail\n");
}
else
{
printf("%s",buffer);
}
return (0);
}
Here is my output:-
Try flushing the file buffer after write.
https://msdn.microsoft.com/en-us/library/windows/desktop/aa364439%28v=vs.85%29.aspx
Related
I am writing a little serial bus (RS485) monitor in c++. It should read small data packages up to 32 bytes from the serialport an occasionally writes such a databus to the serial port when the user requests it.
Reading works perfectly. I set up a thread for reading using the SetCommMask(hComm, EV_RXCHAR); during initialization and later ReadFile(hComm, RS485PacketBuffer, sizeof(T_PACKET), &nBytes, NULL) to receive the package using timeouts for getting the inter package gaps.
In the main program I use a simple WriteFile(hComm, packet, packet->length + 5, &nBytes, NULL) to write the package.
This WriteFile seems to hang until there are some bytes received from the bus. Only then the package is sent and the bus devices recognize it and answer properly. Why does WriteFile wait for character receiving?
This is my init and thread code
HANDLE uart_init(char *portname, int baudrate)
{
HANDLE hComm;
BOOL Write_Status, Read_Status;
DCB dcbSerialParams;
COMMTIMEOUTS timeouts = { 0 };
hComm = CreateFile(L"com8", //port name
GENERIC_READ | GENERIC_WRITE, //Read/Write
0, // No Sharing
NULL, // No Security
OPEN_EXISTING, // Open existing port only
0, // Non Overlapped I/O
NULL); // Null for Comm Devices
if (hComm == INVALID_HANDLE_VALUE)
printf("Error in opening serial port\n");
else
printf("opening serial port successful\n");
Write_Status = GetCommState(hComm, &dcbSerialParams); //retreives the current settings
if (Write_Status == FALSE)
{
printf(" Error in GetCommState()\n");
CloseHandle(hComm);
return NULL;
}
dcbSerialParams.BaudRate = baudrate; // Setting BaudRate = 1200
dcbSerialParams.ByteSize = 8; // Setting ByteSize = 8
dcbSerialParams.StopBits = ONESTOPBIT; // Setting StopBits = 1
dcbSerialParams.Parity = NOPARITY; // Setting Parity = None
Write_Status = SetCommState(hComm, &dcbSerialParams); //Configuring the port according to settings in DCB
if (Write_Status == FALSE)
{
printf(" Error! in Setting DCB Structure\n");
CloseHandle(hComm);
return NULL;
}
else
{
printf(" Setting DCB Structure Successful\n");
printf(" Baudrate = %d\n", dcbSerialParams.BaudRate);
printf(" ByteSize = %d\n", dcbSerialParams.ByteSize);
printf(" StopBits = %d\n", dcbSerialParams.StopBits);
printf(" Parity = %d\n\n", dcbSerialParams.Parity);
}
// Set COM port timeout settings
timeouts.ReadIntervalTimeout = 50;
timeouts.ReadTotalTimeoutConstant = 0;
timeouts.ReadTotalTimeoutMultiplier = 0;
timeouts.WriteTotalTimeoutConstant = 0;
timeouts.WriteTotalTimeoutMultiplier = 0;
if (SetCommTimeouts(hComm, &timeouts) == 0)
{
printf("Error setting timeouts\n");
CloseHandle(hComm);
return NULL;
}
Read_Status = SetCommMask(hComm, EV_RXCHAR); //Configure Windows to Monitor the serial device for Character Reception
if (Read_Status == FALSE)
printf(" Error! in Setting CommMask\n\n");
else
printf(" Setting CommMask successfull\n\n");
return hComm;
}
unsigned int __stdcall RS485Receiver(void* data)
{
BOOL status = 0;
DWORD dwEventMask = 0;
DWORD nBytes; // Bytes read by ReadFile()
puts("Serial Thread started");
if (hComm = uart_init("COM8", 1200))
{
printf("Waiting for Data Reception...\n");
status = WaitCommEvent(hComm, &dwEventMask, NULL); //Wait for the character to be received
if (status == FALSE)
{
printf("Error! in Setting WaitCommEvent()\n");
}
else //If WaitCommEvent()==True Read the RXed data using ReadFile();
{
_putch('.'); fflush(stdout);
do
{
//Read_Status = ReadFile(hComm, &TempChar, sizeof(TempChar), &NoBytesRead, NULL);
if ((!ReadFile(hComm, RS485PacketBuffer, sizeof(T_PACKET), &nBytes, NULL)))
{
printf("wrong character");
}
else if (nBytes)
{
RS485PrintPacket(RS485PacketBuffer, RS485PacketBuffer->length + 4, stdout);
}
} while (1);
}
CloseHandle(hComm);//Closing the Serial Port
}
puts("Serial Thread stopped");
return 0;
}
#endif
And this is the write function, which hangs until character receiving:
uint8_t sendPacket(T_PACKET* packet)
{
DWORD nBytes;
//calculate checksum
packet->d[packet->length] = crc8((uint8_t*)packet, packet->length + 4);
// PORTB &= ~(1 << TRANSENABLE); // ToDo: How do I enable transmitter on PC
Sleep(10); // short pause to stabilize bus transceiver
printf("Sende Paket, length = %u\n", packet->length+5);
if (!WriteFile(hComm, packet, packet->length + 5, &nBytes, NULL))
{
printf("Error writing text to RS485 port\n");
return 6;
}
printf("gesendet\n"); fflush(stdout);
if (nBytes != packet->length + 5) return 7;
printf("kein Fehler\n");
// PORTB |= (1 << TRANSENABLE); // ToDo: How do I disable transmitter on PC
return 0;`
}
I already tried several timout settings. These seems to have no effect to the problem. Maybe it is an issue with the USB/RS485 converter. I think as the RS485 is a bus, the serial port will probably see it's own send bytes. Maybe that causes the problem.
Or maybe the blocking receiver thread which is waiting for characters blocks the whole serial port.
As #Codo mentioned, I tried now to use overlapped IO. I have a complete solution now. See the answer below.
thanks for all the hints. #Codo's first remark was the solution. I have to use overlapping because Windows blocks also the sender when the receiver is waiting. Stupid, but true.
Since overlapping IO is a bit complicated I post my solution her for reference. Now I have to try the same in C#. :-)
HANDLE uart_init(char *portname, int baudrate)
{
HANDLE hComm;
BOOL Result;
DCB dcbSerialParams;
COMMTIMEOUTS timeouts = { 0 };
wchar_t wstr[50];
MultiByteToWideChar(CP_UTF8, 0, portname, -1, wstr, 50);
hComm = CreateFile(wstr, //port name
GENERIC_READ | GENERIC_WRITE, //Read/Write
0, // No Sharing
NULL, // No Security
OPEN_EXISTING, // Open existing port only
FILE_FLAG_OVERLAPPED, // Non Overlapped I/O
NULL); // Null for Comm Devices
if (hComm == INVALID_HANDLE_VALUE)
printf("Error in opening serial port\n");
else
printf("opening serial port successful\n");
Result = GetCommState(hComm, &dcbSerialParams); //retreives the current settings
if (Result == FALSE)
{
printf(" Error in GetCommState()\n");
CloseHandle(hComm);
return NULL;
}
dcbSerialParams.BaudRate = baudrate; // Setting BaudRate = 1200
dcbSerialParams.ByteSize = 8; // Setting ByteSize = 8
dcbSerialParams.StopBits = ONESTOPBIT; // Setting StopBits = 1
dcbSerialParams.Parity = NOPARITY; // Setting Parity = None
dcbSerialParams.fBinary = TRUE; // has to be TRUE in Windows
dcbSerialParams.fParity = FALSE; // No parity
dcbSerialParams.fOutxCtsFlow = FALSE; // No CTS flow control
dcbSerialParams.fOutxDsrFlow = FALSE; // No DSR flow control
dcbSerialParams.fDtrControl = FALSE; // No DTR low control
dcbSerialParams.fDsrSensitivity = FALSE; // Ignore DSR
dcbSerialParams.fOutX = FALSE; // No XON/XOFF flow control
dcbSerialParams.fInX = FALSE; // No XON/XOFF flow control
dcbSerialParams.fErrorChar = FALSE; // do not replace errors
dcbSerialParams.fNull = FALSE; // allow NULL bytes
dcbSerialParams.fRtsControl = RTS_CONTROL_ENABLE; // Enable RTS pin
dcbSerialParams.fAbortOnError = FALSE; // do not stop on error
Result = SetCommState(hComm, &dcbSerialParams); //Configuring the port according to settings in DCB
if (Result == FALSE)
{
printf(" Error! in Setting DCB Structure\n");
CloseHandle(hComm);
return NULL;
}
else
{
printf(" Setting DCB Structure Successful\n");
printf(" Baudrate = %d\n", dcbSerialParams.BaudRate);
printf(" ByteSize = %d\n", dcbSerialParams.ByteSize);
printf(" StopBits = %d\n", dcbSerialParams.StopBits);
printf(" Parity = %d\n\n", dcbSerialParams.Parity);
}
// Set COM port timeout settings
timeouts.ReadIntervalTimeout = 50;
timeouts.ReadTotalTimeoutConstant = 0;
timeouts.ReadTotalTimeoutMultiplier = 0;
timeouts.WriteTotalTimeoutConstant = 0;
timeouts.WriteTotalTimeoutMultiplier = 0;
if (SetCommTimeouts(hComm, &timeouts) == 0)
{
printf("Error setting timeouts\n");
CloseHandle(hComm);
return NULL;
}
Result = SetCommMask(hComm, EV_RXCHAR); //Configure Windows to Monitor the serial device for Character Reception
if (Result == FALSE)
printf(" Error in Setting CommMask\n\n");
else
printf(" Setting CommMask successfull\n\n");
return hComm;
}
unsigned int __stdcall RS485Receiver(void* data)
{
BOOL status = 0;
DWORD dwEventMask = 0;
DWORD nBytes; // Bytes read by ReadFile()
DWORD dwRes;
DWORD dwRead;
BOOL fWaitingOnRead = FALSE;
OVERLAPPED osRead = { 0 };
puts("Serial Thread started");
if (hComm = uart_init((char *)data, 1200))
{
printf("Waiting for Data Reception...\n");
// Create the overlapped event. Must be closed before exiting
// to avoid a handle leak.
osRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (osRead.hEvent == NULL)
{
CloseHandle(hComm);//Closing the Serial Port
puts("Serial Thread stopped");
return 0;
}
while (1)
{
if (!fWaitingOnRead)
{
// Issue read operation.
if (!ReadFile(hComm, RS485PacketBuffer, sizeof(T_PACKET), &dwRead, &osRead))
{
if (GetLastError() != ERROR_IO_PENDING) // read not delayed?
printf("wrong character");
else
fWaitingOnRead = TRUE;
}
else {
// read completed immediately
RS485PrintPacket(RS485PacketBuffer, RS485PacketBuffer->length + 4, stdout);
}
}
if (fWaitingOnRead)
{
dwRes = WaitForSingleObject(osRead.hEvent, INFINITE);
switch (dwRes)
{
// Read completed.
case WAIT_OBJECT_0:
if (!GetOverlappedResult(hComm, &osRead, &dwRead, FALSE))
printf("wrong character");
else
// Read completed successfully.
RS485PrintPacket(RS485PacketBuffer, RS485PacketBuffer->length + 4, stdout);
// 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.
break;
}
}
}
CloseHandle(hComm); //Closing the Serial Port
}
puts("Serial Thread stopped");
return 0;
}
/*
* Send a data packet
* use this only for Windows
*/
uint8_t sendPacket(T_PACKET* packet)
{
DWORD nBytes;
uint8_t fRes = 0;
OVERLAPPED osWrite = { 0 };
//calculate checksum
packet->d[packet->length] = crc8((uint8_t*)packet, packet->length + 4);
// PORTB &= ~(1 << TRANSENABLE); // ToDo: How do I enable transmitter on PC
Sleep(10); // short pause to stabilize bus transceiver
osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (osWrite.hEvent == NULL)
// error creating overlapped event handle
return ERR_COMM_WR;
if (!WriteFile(hComm, packet, packet->length + 5, &nBytes, &osWrite))
{
if (GetLastError() != ERROR_IO_PENDING) // read not delayed?
{
fRes = ERR_COMM_WR;
}
else
{
if (!GetOverlappedResult(hComm, &osWrite, &nBytes, TRUE))
{
fRes = ERR_COMM_WR;
}
else
{
// Read completed successfully.
RS485PrintPacket(packet, packet->length + 4, stdout);
}
}
}
CloseHandle(osWrite.hEvent);
// PORTB |= (1 << TRANSENABLE); // ToDo: How do I disable transmitter on PC
return fRes;
}
I am using a DLL injection on to start the client end of a file pipe, which talks to a server that logs the messages. The problem is that the server only receives a buffer filled with question mark ('?') characters.
Client / Injectable DLL:
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <strsafe.h>
#define BUFSIZE 1024*1024
HANDLE hPipe;
BOOL fSuccess = FALSE;
DWORD cbToWrite, cbWritten, dwMode;
const wchar_t* lpszPipename = TEXT("\\\\.\\pipe\\listen");
char write_buffer[BUFSIZE];
void init()
{
hPipe = CreateFile(
lpszPipename, // pipe name
GENERIC_READ | // read and write access
GENERIC_WRITE,
0, // no sharing
NULL, // default security attributes
OPEN_EXISTING, // opens existing pipe
0, // default attributes
NULL); // no template file
// The pipe connected; change to message-read mode.
dwMode = PIPE_READMODE_MESSAGE;
fSuccess = SetNamedPipeHandleState(
hPipe, // pipe handle
&dwMode, // new pipe mode
NULL, // don't set maximum bytes
NULL); // don't set maximum time
}
#pragma warning(disable:4996)
void report(const char* frmt, ...)
{
va_list args;
va_start(args, frmt);
vsnprintf(write_buffer, BUFSIZE, frmt, args);
va_end(args);
// Send a message to the pipe server.
fSuccess = WriteFile(
hPipe, // pipe handle
write_buffer, // message
strlen(write_buffer), // message length
&cbWritten, // bytes written
NULL); // not overlapped
return;
}
Server:
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <strsafe.h>
#define BUFSIZE 1024*1024
BOOL fConnected = FALSE;
DWORD dwThreadId = 0;
HANDLE hPipe = INVALID_HANDLE_VALUE, hThread = NULL;
const wchar_t* lpszPipename = TEXT("\\\\.\\pipe\\listen");
// The main loop creates an instance of the named pipe and
// then waits for a client to connect to it. When the client
// connects, a thread is created to handle communications
// with that client, and this loop is free to wait for the
// next client connect request. It is an infinite loop.
for (;;)
{
_tprintf(TEXT("\nPipe Server: Main thread awaiting client connection on %s\n"), lpszPipename);
hPipe = CreateNamedPipe(
lpszPipename, // pipe name
PIPE_ACCESS_DUPLEX, // read/write access
PIPE_TYPE_MESSAGE | // message type pipe
PIPE_READMODE_MESSAGE | // message-read mode
PIPE_WAIT, // blocking mode
PIPE_UNLIMITED_INSTANCES, // max. instances
BUFSIZE, // output buffer size
BUFSIZE, // input buffer size
0, // client time-out
NULL); // default security attribute
if (hPipe == INVALID_HANDLE_VALUE)
{
_tprintf(TEXT("CreateNamedPipe failed, GLE=%d.\n"), GetLastError());
return -1;
}
// Wait for the client to connect; if it succeeds,
// the function returns a nonzero value. If the function
// returns zero, GetLastError returns ERROR_PIPE_CONNECTED.
fConnected = ConnectNamedPipe(hPipe, NULL) ?
TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
if (fConnected)
{
printf("Client connected, creating a processing thread.\n");
// Create a thread for this client.
hThread = CreateThread(
NULL, // no security attribute
0, // default stack size
InstanceThread, // thread proc
(LPVOID)hPipe, // thread parameter
0, // not suspended
&dwThreadId); // returns thread ID
if (hThread == NULL)
{
_tprintf(TEXT("CreateThread failed, GLE=%d.\n"), GetLastError());
return -1;
}
else CloseHandle(hThread);
}
else
// The client could not connect, so close the pipe.
CloseHandle(hPipe);
}
DWORD WINAPI InstanceThread(LPVOID lpvParam)
// This routine is a thread processing function to read from and reply to a client
// via the open pipe connection passed from the main loop. Note this allows
// the main loop to continue executing, potentially creating more threads of
// of this procedure to run concurrently, depending on the number of incoming
// client connections.
{
HANDLE hHeap = GetProcessHeap();
TCHAR* pchRequest = (TCHAR*)HeapAlloc(hHeap, 0, BUFSIZE * sizeof(TCHAR));
TCHAR* pchReply = (TCHAR*)HeapAlloc(hHeap, 0, BUFSIZE * sizeof(TCHAR));
DWORD cbBytesRead = 0, cbReplyBytes = 0, cbWritten = 0;
BOOL fSuccess = FALSE;
HANDLE hPipe = NULL;
// Print verbose messages. In production code, this should be for debugging only.
printf("InstanceThread created, receiving and processing messages.\n");
// The thread's parameter is a handle to a pipe object instance.
hPipe = (HANDLE)lpvParam;
// Loop until done reading
while (1)
{
// Read client requests from the pipe. This simplistic code only allows messages
// up to BUFSIZE characters in length.
fSuccess = ReadFile(
hPipe, // handle to pipe
pchRequest, // buffer to receive data
BUFSIZE, // size of buffer
&cbBytesRead, // number of bytes read
NULL); // not overlapped I/O
// Process the incoming message.
_tprintf(TEXT("Client Request String:\"%s\"\n"), pchRequest);
}
FlushFileBuffers(hPipe);
DisconnectNamedPipe(hPipe);
CloseHandle(hPipe);
HeapFree(hHeap, 0, pchRequest);
HeapFree(hHeap, 0, pchReply);
printf("InstanceThread exitting.\n");
return 1;
}
P.S. If is some how possible to use a debugger with a injectable DLL please let me know!
There are a few problems with this code, which I will come to at the end. First, some code that works. Please note that I have simplified things slightly by making it all into a single application (so that I could easily test it) and by getting rid of the thread, but none of that matters in the context of your question.
#define _CRT_SECURE_NO_WARNINGS
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <strsafe.h>
#define BUFSIZE 1024*1024
const TCHAR* lpszPipename = TEXT("\\\\.\\pipe\\listen");
char write_buffer [BUFSIZE];
HANDLE init()
{
HANDLE hPipe = CreateFile(
lpszPipename, // pipe name
GENERIC_READ | // read and write access
GENERIC_WRITE,
0, // no sharing
NULL, // default security attributes
OPEN_EXISTING, // opens existing pipe
0, // default attributes
NULL); // no template file
if (hPipe == INVALID_HANDLE_VALUE)
{
printf ("CreateFile returned error %d\n", GetLastError ());
return INVALID_HANDLE_VALUE;
}
// The pipe connected; change to message-read mode.
DWORD dwMode = PIPE_READMODE_MESSAGE;
BOOL fSuccess = SetNamedPipeHandleState(
hPipe, // pipe handle
&dwMode, // new pipe mode
NULL, // don't set maximum bytes
NULL); // don't set maximum time
if (!fSuccess)
{
printf ("SetNamedPipeHandleState returned error %d\n", GetLastError ());
CloseHandle (hPipe);
return INVALID_HANDLE_VALUE;
}
return hPipe;
}
void report(HANDLE hPipe, const char *frmt, ...)
{
va_list args;
va_start(args, frmt);
_vsnprintf(write_buffer, BUFSIZE, frmt, args);
va_end(args);
// Send a message to the pipe server.
DWORD cbWritten;
BOOL fSuccess = WriteFile(
hPipe, // pipe handle
write_buffer, // message
(DWORD) strlen (write_buffer) + 1, // message length, including EOS
&cbWritten, // bytes written
NULL); // not overlapped
if (!fSuccess)
printf ("WriteFile returned error %d\n", GetLastError ());
}
int _tmain (int argc, TCHAR **argv)
{
if (argc > 1 && _tcscmp (argv [1], __T ("send")) == 0)
{
// send
HANDLE hPipe = init ();
if (hPipe != INVALID_HANDLE_VALUE)
{
report (hPipe, "A message to you, Rudi");
CloseHandle (hPipe);
}
return 0;
}
// receive
for (;;)
{
_tprintf(TEXT("\nPipe Server: Main thread awaiting client connection on %s\n"), lpszPipename);
HANDLE hPipe = CreateNamedPipe(
lpszPipename, // pipe name
PIPE_ACCESS_DUPLEX, // read/write access
PIPE_TYPE_MESSAGE | // message type pipe
PIPE_READMODE_MESSAGE | // message-read mode
PIPE_WAIT, // blocking mode
PIPE_UNLIMITED_INSTANCES, // max. instances
BUFSIZE, // output buffer size
BUFSIZE, // input buffer size
0, // client time-out
NULL); // default security attribute
if (hPipe == INVALID_HANDLE_VALUE)
{
printf ("CreateNamedPipe failed, GLE=%d.\n", GetLastError());
return -1;
}
// Wait for the client to connect; if it succeeds,
// the function returns a nonzero value. If the function
// returns zero, GetLastError returns ERROR_PIPE_CONNECTED.
BOOL fConnected = ConnectNamedPipe(hPipe, NULL) ?
TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
if (!fConnected)
{
printf ("Error %d connecting named pipe\n", GetLastError());
return 255;
}
printf ("Client connected\n");
HANDLE hHeap = GetProcessHeap();
char* pchRequest = (char*) HeapAlloc(hHeap, 0, BUFSIZE);
// Loop until done reading
while (1)
{
// Read client requests from the pipe. This simplistic code only allows messages
// up to BUFSIZE characters in length.
DWORD cbBytesRead = 0;
BOOL fSuccess = ReadFile(
hPipe, // handle to pipe
pchRequest, // buffer to receive data
BUFSIZE, // size of buffer
&cbBytesRead, // number of bytes read
NULL); // not overlapped I/O
if (!fSuccess)
break;
// Process the incoming message.
printf("Client Request String:\"%s\"\n", pchRequest);
}
FlushFileBuffers(hPipe);
DisconnectNamedPipe(hPipe);
CloseHandle(hPipe);
HeapFree(hHeap, 0, pchRequest);
}
return 0;
}
To run this in "send" mode, specify send on the command line. Otherwise it runs as a server. My server runs for ever. Kill it with Ctrl+C.
So what was wrong with your code? Well, mostly, it was a bit of a mishmash of ANSI and UNICODE strings. You need to be much more careful with this kind of thing and you also need to calculate buffer sizes appropriately. This is all fixed in the above code, which is why I posted it. Also, in terms of good programming practise:
You should check for errors much more thoroughly.
As written, the server assumes that the string sent to it is NUL-terminated but the client doesn't send it that way (so I fixed the client).
The server needs to break out of its receive loop when the sender closes its end of the pipe.
Declare local variables locally! (And pass them around as parameters, when appropriate.) Don't use unnecessary globals.
Using #define _CRT_SECURE_NO_WARNINGS is better than explicitly disabling the warning that you get if you don't.
My code fixes all of these issues. HTH.
Ok so below I have the code for named pipe server/client. I have the server placed on my Windows 8 computer and it creates a pipe and then waits for the client to connect. Then I start the client on my Windows 7 but it returns error 5 (Access denied, I think??) Can someone explain to me why it is giving me error 5 please?
Thnx in advance for all the answers
Server Code
#include "stdafx.h"
#include "windows.h"
#include <iostream>
using namespace std;
#define g_szPipeName "\\\\.\\pipe\\pipename" //Name given to the pipe
#define BUFFER_SIZE 1024 //1k
#define ACK_MESG_RECV "Message received successfully"
#define _CRT_SECURE_NO_WARNINGS
HANDLE hPipe;
int repeate() {
char szBuffer[BUFFER_SIZE];
DWORD cbBytes;
//We are connected to the client.
//To communicate with the client we will use ReadFile()/WriteFile()
//on the pipe handle - hPipe
//Read client message
BOOL bResult = ReadFile(
hPipe, // handle to pipe
szBuffer, // buffer to receive data
sizeof(szBuffer), // size of buffer
&cbBytes, // number of bytes read
NULL); // not overlapped I/O
if ((!bResult) || (0 == cbBytes))
{
printf("\nError occurred while reading from the client: %d", GetLastError());
CloseHandle(hPipe);
system("Pause");
return 1; //Error
}
else
{
printf("\nReadFile() was successful.");
}
printf("\nClient sent the following message: %s", szBuffer);
strcpy(szBuffer, ACK_MESG_RECV);
//Reply to client
bResult = WriteFile(
hPipe, // handle to pipe
szBuffer, // buffer to write from
strlen(szBuffer) + 1, // number of bytes to write, include the NULL
&cbBytes, // number of bytes written
NULL); // not overlapped I/O
if ((!bResult) || (strlen(szBuffer) + 1 != cbBytes))
{
printf("\nError occurred while writing to the client: %d", GetLastError());
CloseHandle(hPipe);
system("Pause");
return 1; //Error
}
else
{
printf("\nWriteFile() was successful.");
}
repeate();
}
int main(int argc, char* argv[])
{
SECURITY_DESCRIPTOR sd;
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = &sd;
hPipe = CreateNamedPipe(
g_szPipeName, // pipe name
PIPE_ACCESS_DUPLEX, // read/write access
PIPE_TYPE_MESSAGE | // message type pipe
PIPE_READMODE_MESSAGE | // message-read mode
PIPE_WAIT, // blocking mode
PIPE_UNLIMITED_INSTANCES, // max. instances
BUFFER_SIZE, // output buffer size
BUFFER_SIZE, // input buffer size
NMPWAIT_USE_DEFAULT_WAIT,
&sa);
if (INVALID_HANDLE_VALUE == hPipe)
{
printf("\nError occurred while creating the pipe: %d", GetLastError());
system("Pause");
return 1; //Error
}
else
{
printf("\nCreateNamedPipe() was successful.");
}
printf("\nWaiting for client connection...");
//Wait for the client to connect
BOOL bClientConnected = ConnectNamedPipe(hPipe, NULL);
if (FALSE == bClientConnected)
{
printf("\nError occurred while connecting to the client: %d", GetLastError());
CloseHandle(hPipe);
system("Pause");
return 1; //Error
}
else
{
printf("\nConnectNamedPipe() was successful.");
}
repeate();
}
Client Code
#include "stdafx.h"
#include "windows.h"
#include <iostream>
#define g_szPipeName "\\\\MyComputerName\\pipe\\pipename" //Name given to the pipe
#define BUFFER_SIZE 1024 //1k
#define ACK_MESG_RECV "Message received successfully"
HANDLE hPipe;
int repeate() {
char szBuffer[BUFFER_SIZE];
printf("\nEnter a message to be sent to the server: ");
gets(szBuffer);
DWORD cbBytes;
//Send the message to server
BOOL bResult = WriteFile(
hPipe, // handle to pipe
szBuffer, // buffer to write from
strlen(szBuffer) + 1, // number of bytes to write, include the NULL
&cbBytes, // number of bytes written
NULL); // not overlapped I/O
if ((!bResult) || (strlen(szBuffer) + 1 != cbBytes))
{
printf("\nError occurred while writing to the server: %d", GetLastError());
CloseHandle(hPipe);
system("Pause");
return 1; //Error
}
else
{
printf("\nWriteFile() was successful.");
}
//Read server response
bResult = ReadFile(
hPipe, // handle to pipe
szBuffer, // buffer to receive data
sizeof(szBuffer), // size of buffer
&cbBytes, // number of bytes read
NULL); // not overlapped I/O
if ((!bResult) || (0 == cbBytes))
{
printf("\nError occurred while reading from the server: %d", GetLastError());
CloseHandle(hPipe);
system("Pause");
return 1; //Error
}
else
{
printf("\nReadFile() was successful.");
}
printf("\nServer sent the following message: %s", szBuffer);
repeate();
}
int main(int argc, char* argv[])
{
//Connect to the server pipe using CreateFile()
hPipe = CreateFile(
g_szPipeName, // pipe name
GENERIC_READ | // read and write access
GENERIC_WRITE,
0, // no sharing
NULL, // default security attributes
OPEN_EXISTING, // opens existing pipe
0, // default attributes
NULL); // no template file
if (INVALID_HANDLE_VALUE == hPipe)
{
printf("\nError occurred while connecting to the server: %d", GetLastError());
//One might want to check whether the server pipe is busy
//This sample will error out if the server pipe is busy
//Read on ERROR_PIPE_BUSY and WaitNamedPipe() for that
system("Pause");
return 1; //Error
}
else
{
printf("\nCreateFile() was successful.");
}
//We are done connecting to the server pipe,
//we can start communicating with the server using ReadFile()/WriteFile()
//on handle - hPipe
repeate();
}
Configure both computers by adding ip address, subnet mask, default gateway. From Network and Sharing Center, turn on all sharing and turn off password protected sharing. Test it by pinging ip address from cmd. User account of the both computers should not be password protected. That's why i fixed the Client Error 5 and set up named pipe communication between two remote computers
The client should use OpenFile(), not CreateFile(). The client doesn't want to create anything new, it wants to talk to an existing pipe.
I have read alot of issues with serial port reading and writing. None so far have helped me figure out what my code is missing. The msdn example for c++ has undefined variables and missing brackets so although i can add brackets it still does not function. Here's what I've got at this point. It appears I can open the port and do the configuration but I cannot read a byte/char of data. I really just want a simple asyncronous serial read/write for aprogram to read from an Arduino.
class MY_SERIAL
{
HANDLE serialinstance;
DWORD dwStoredFlags;
DWORD dwRes;
DWORD dwCommEvent;
OVERLAPPED osStatus = {0};
BOOL fWaitingOnStat;
//dwStoredFlags = EV_BREAK | EV_CTS | EV_DSR | EV_ERR | EV_RING | EV_RLSD | EV_RXCHAR | EV_RXFLAG | EV_TXEMPTY ;
DCB dcb;
COMMTIMEOUTS timeouts;
COMMCONFIG serialconfig;
public:
char inBuffer[1000];
char outBuffer[100];
PDWORD noBytes;
void close_serial()
{
CloseHandle(serialinstance);
}
//----------------------------------------------------
bool open_serial(LPCSTR portNumber) // serial port name use this format "\\\\.\\COM10"
{
serialinstance = CreateFile(portNumber, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
if(serialinstance == INVALID_HANDLE_VALUE)
{
int error = GetLastError();
printf("ERROR opening serial port %s\r\n", portNumber);
if(error == 0x2){printf("ERROR_FILE_NOT_FOUND\r\n");}
if(error == 0x5){printf("ERROR_ACCESS_DENIED\r\n");}
if(error == 0xC){printf("ERROR_INVALID_ACCESS\r\n");}
if(error == 0x6){printf("ERROR_INVALID_HANDLE\r\n");}
printf("error code %d\r\n", error);
return false;
}
if(GetCommState(serialinstance, &dcb)!= true)
{
printf("ERROR getting current state of COM %d \r\n", GetLastError());
return false;
}
else{printf("debug read current comstate\r\n");}
FillMemory(&dcb, sizeof(dcb), 0); //zero initialize the structure
dcb.DCBlength = sizeof(dcb); //fill in length
dcb.BaudRate = CBR_115200; // baud rate
dcb.ByteSize = 8; // data size, xmit and rcv
dcb.Parity = NOPARITY; // parity bit
dcb.StopBits = ONESTOPBIT;
if(SetCommState(serialinstance, &dcb) != true)
{
printf("ERROR setting new state of COM %d \r\n", GetLastError());
return false;
}
else{printf("debug set new comstate\r\n");}
/*
if (!BuildCommDCB("115200,n,8,1", &dcb)) //fills in basic async details
{
printf("ERROR getting port comstate\r\n");
return FALSE;
}
*/
if (!SetCommMask(serialinstance, EV_RXCHAR))
{
printf("ERROR setting new COM MASK %d \r\n", GetLastError());
return false;
}
else{printf("debug commmask set\r\n");}
timeouts.ReadIntervalTimeout = MAXDWORD;
timeouts.ReadTotalTimeoutMultiplier = 20;
timeouts.ReadTotalTimeoutConstant = 0;
timeouts.WriteTotalTimeoutMultiplier = 0;
timeouts.WriteTotalTimeoutConstant = 0;
if (!SetCommTimeouts(serialinstance, &timeouts))
{
printf("ERROR setting timeout parameters\r\n");
return false;
}
else{printf("debug timeouts set\r\n");}
osStatus.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (osStatus.hEvent == NULL)
{// error creating event; abort
printf("ERROR creating Serial EVENT\r\n");
return false;
}
else{printf("debug event created set\r\n");}
osStatus.Internal = 0;
osStatus.InternalHigh = 0;
osStatus.Offset = 0;
osStatus.OffsetHigh = 0;
assert(osStatus.hEvent);
printf("debug com port setting complete\r\n");
return true;
}
//---------------------------------------------------------
bool read_serial_simple()
{
char m[1000];
LPDWORD bytesRead;
if (WaitCommEvent(serialinstance, &dwCommEvent, &osStatus))
{
if(dwCommEvent & EV_RXCHAR)
{
ReadFile(serialinstance, &m, 1, bytesRead, &osStatus);
printf("data read = %d, number bytes read = %d \r\n", m, bytesRead);
return true;
}
else
{
int error = GetLastError();
if(error == ERROR_IO_PENDING){printf(" waiting on incomplete IO\r\n");}
else{printf("ERROR %d\r\n", error);}
return false;
}
}
return false;
}
};
So I stripped the read function down. I now get a char and it reports reading 1 byte but the value of the char is incorrect. I get a series of 48, 13, 10, and occasionally a 50 value for the byte. However the Arduino is sending a series a 0's then a 128 as verified with TerraTerm. What else do I need here?
bool read_serial_simple()
{
unsigned char m = 0;
DWORD bytesRead;
if(ReadFile(serialinstance, &m, 1, &bytesRead, &osStatus) == true)
{
printf("data read = %d, number bytes read = %d \r\n", m, bytesRead);
return true;
}
else{
int error = GetLastError();
if(error == ERROR_IO_PENDING){printf(" waiting on incomplete IO\r\n");}
else{printf("ERROR %d\r\n", error);}
return false;
}
}
So now I can read a byte of data but I cannot write a byte or more to the port. I just get ERROR_IO_PENDING. Can someone help out with this as well. Write function of my class below.
bool write(DWORD noBytesToWrite)
{
if(WriteFile(serialinstance, outBuffer, noBytesToWrite, NULL, &osStatus) == true)
{
printf("message sent\r\n");
return true;
}
else
{
int error = GetLastError();
if(error != ERROR_IO_PENDING){LastError();}
return false;
}
}
I'm calling both functions from main as follows
myserial.open_serial(COM12);
myserial.outBuffer[0] = 'H';
myserial.outBuffer[1] = 'e';
myserial.outBuffer[2] = 'L';
myserial.outBuffer[3] = 'l';
myserial.outBuffer[4] = 'O';
for(int n=0; n<5; n++){printf("%c", myserial.outBuffer[n]);}
printf("\r\n");
while(1)
{
myserial.read();
myserial.write(5);
//system("PAUSE");
}
Currently the arduino is set up to read bytes in and repeat them back to the pc. It is doing this fine on the arduino IDE serial monitor so now I just need to get this pc program to write out.
Your bytesRead variable is an uninitialized pointer. You are passing an invalid address to ReadFile() to write to.
Replace LPDWORD bytesRead with DWORD bytesRead, then pass it to ReadFile() using &bytesRead.
Edit:
Also eliminate the FILE_FLAG_OVERLAPPED. You are not handling it properly, and there is no point in using it if you WaitForSingleObject() before reading.
Sorry my answer is a bit late, but as I was checking up on another serial port detail I found this.
There is a bit flaw in the original code. You are calling CreateFile with the FILE_FLAG_OVERLAPPED flag. This means you want to use non-blocking calls. You either need to remove this flag, or change your ReadFile and WriteFile calls so that they include a pointer to an OVERLAPPED structure WriteFile.
Your code works with ReadFile as it will complete syncrhronously as there is a character already waiting. The WriteFile will return IO_PENDING result to indicate that the write has been queued.
//#include "StdAfx.h"
#include <stdio.h>
#include <windows.h>
#include <winbase.h>
#include <iostream>
#include <tchar.h>
using namespace std;
int main()
{
int com = 'COM2';
string data = "\n 010400 \n";
char output[32];
//unsigned int length = 0;
DCB config = {0};
bool abContinue = true;
DWORD dwBytesWritten;
DWORD dwBytesRead;
int isRead = false;
HANDLE m_hCommPort = ::CreateFile(L"COM2",
GENERIC_READ|GENERIC_WRITE,//access ( read and write)
0, //(share) 0:cannot share the COM port
0, //security (None)
OPEN_EXISTING,// creation : open_existing
0, // we dont want overlapped operation
0// no templates file for COM port...
);
config.DCBlength = sizeof(config);
if((GetCommState(m_hCommPort, &config) == 0))
{
printf("Get configuration port has a problem.");
return FALSE;
}
config.BaudRate = 9600;
config.StopBits = ONESTOPBIT;
config.Parity = PARITY_NONE;
config.ByteSize = DATABITS_8;
config.fDtrControl = 0;
config.fRtsControl = 0;
if (!SetCommState(m_hCommPort, &config))
{
printf( "Failed to Set Comm State Reason: %d\n",GetLastError());
//return E_FAIL;
}
printf("Current Settings\n Baud Rate %d\n Parity %d\n Byte Size %d\n Stop Bits %d", config.BaudRate,
config.Parity, config.ByteSize, config.StopBits);
int isWritten = WriteFile(m_hCommPort, &data,(DWORD) sizeof(data), &dwBytesWritten, NULL);
//memset(output, 0, sizeof(output));
while (abContinue)
{
isRead = ReadFile(m_hCommPort, output, sizeof(output), &dwBytesRead, NULL);
if(!isRead)
{
abContinue = false;
break;
}
}
cin.get();
}
I am having trouble reading from the com port. If I step through the code, it goes into "isRead = ReadFile(m_hCommPort, output, sizeof(output), &dwBytesRead, NULL);" and doesn't come back out.... This is my first try at this with no success.
You might try some code something like this after you've opened the file, but before you try to use it:
COMMTIMEOUTS timeouts;
timeouts.ReadIntervalTimeout = 1;
timeouts.ReadTotalTimeoutMultiplier = 1;
timeouts.ReadTotalTimeoutConstant = 1;
timeouts.WriteTotalTimeoutMultiplier = 1;
timeouts.WriteTotalTimeoutConstant = 1;
if (!SetCommTimeouts(m_hCommPort, &timeouts))
// setting timeouts failed.
Edit: perhaps it's easier to start with some code that works, and make it do what you want rather than trying to get your code to work. Here's a simple terminal program. It's minimalist in the extreme, but does work (at least well enough to let me see output from my GPS, for one example). It's a long ways from what anybody (least of all me) would call sophisticated, but should give at least some idea of how to get started.
#include <stdio.h>
#include <conio.h>
#include <string.h>
#define STRICT
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
void system_error(char *name) {
// Retrieve, format, and print out a message from the last error. The
// `name' that's passed should be in the form of a present tense noun
// (phrase) such as "opening file".
//
char *ptr = NULL;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
0,
GetLastError(),
0,
(char *)&ptr,
1024,
NULL);
fprintf(stderr, "\nError %s: %s\n", name, ptr);
LocalFree(ptr);
}
int main(int argc, char **argv) {
int ch;
char buffer[1];
HANDLE file;
COMMTIMEOUTS timeouts;
DWORD read, written;
DCB port;
HANDLE keyboard = GetStdHandle(STD_INPUT_HANDLE);
HANDLE screen = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD mode;
char port_name[128] = "\\\\.\\COM3";
char init[] = ""; // e.g., "ATZ" to completely reset a modem.
if ( argc > 2 )
sprintf(port_name, "\\\\.\\COM%c", argv[1][0]);
// open the comm port.
file = CreateFile(port_name,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
0,
NULL);
if ( INVALID_HANDLE_VALUE == file) {
system_error("opening file");
return 1;
}
// get the current DCB, and adjust a few bits to our liking.
memset(&port, 0, sizeof(port));
port.DCBlength = sizeof(port);
if ( !GetCommState(file, &port))
system_error("getting comm state");
if (!BuildCommDCB("baud=19200 parity=n data=8 stop=1", &port))
system_error("building comm DCB");
if (!SetCommState(file, &port))
system_error("adjusting port settings");
// set short timeouts on the comm port.
timeouts.ReadIntervalTimeout = 1;
timeouts.ReadTotalTimeoutMultiplier = 1;
timeouts.ReadTotalTimeoutConstant = 1;
timeouts.WriteTotalTimeoutMultiplier = 1;
timeouts.WriteTotalTimeoutConstant = 1;
if (!SetCommTimeouts(file, &timeouts))
system_error("setting port time-outs.");
// set keyboard to raw reading.
if (!GetConsoleMode(keyboard, &mode))
system_error("getting keyboard mode");
mode &= ~ ENABLE_PROCESSED_INPUT;
if (!SetConsoleMode(keyboard, mode))
system_error("setting keyboard mode");
if (!EscapeCommFunction(file, CLRDTR))
system_error("clearing DTR");
Sleep(200);
if (!EscapeCommFunction(file, SETDTR))
system_error("setting DTR");
if ( !WriteFile(file, init, sizeof(init), &written, NULL))
system_error("writing data to port");
if (written != sizeof(init))
system_error("not all data written to port");
// basic terminal loop:
do {
// check for data on port and display it on screen.
ReadFile(file, buffer, sizeof(buffer), &read, NULL);
if ( read )
WriteFile(screen, buffer, read, &written, NULL);
// check for keypress, and write any out the port.
if ( kbhit() ) {
ch = getch();
WriteFile(file, &ch, 1, &written, NULL);
}
// until user hits ctrl-backspace.
} while ( ch != 127);
// close up and go home.
CloseHandle(keyboard);
CloseHandle(file);
return 0;
}
If you do not explicitly set the timeouts, then ReadFile will indefinitely block until data becomes available.
ReadFile function may be blocking your thread,if so, it will remain blocked until some data can be read from Serial port. Here is a link see if its help. Good luck.
I had this problem on a readfile, with the timeouts set. This was driving me crackers so I ended up getting some code from the web which did work and then changing line by line to see where the error was.
Turns out he readfile was fine. My problem was a WaitCommEvent which was hanging when the port was disconnected as no com event is ever received...