Unable to use windows.h ReadFile correctly on COM port. WriteFile seems to work fine - c++

I am trying to use the windows.h library to communicate through RS232 with a device (SCPI communication). I have looked at several tutorials and guides on how to set this up and think my code should work correctly. I am able to send data to the device using WriteFile. However, I am not able to receive any data using ReadFile (ReadFile generates no errors but the buffer size is 0). Here is my code:
#include <stdio.h>
#include <windows.h>
void main ()
{
// CreateFile
HANDLE rs232 = CreateFileA ("\\\\.\\COM1", GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
if (rs232 == INVALID_HANDLE_VALUE)
{
printf ("fail CreateFile: %d\n", GetLastError ()); system ("pause"); return;
}
// Get & Set CommState
DCB port_configuration;
int err = GetCommState (rs232, &port_configuration);
if (err <= 0)
{
printf ("fail GetCommState: %d\n", GetLastError ()); CloseHandle (rs232); system ("pause"); return;
}
port_configuration.BaudRate = 19200;
port_configuration.ByteSize = 8;
port_configuration.Parity = 0;
port_configuration.StopBits = 0;
port_configuration.DCBlength = sizeof (port_configuration);
err = SetCommState (rs232, &port_configuration);
if (err <= 0)
{
printf ("fail SetCommState\n"); CloseHandle (rs232); system ("pause"); return;
}
// SetCommTimeouts
COMMTIMEOUTS timeout_configuration;
timeout_configuration.ReadIntervalTimeout = 1;// MAXDWORD;
timeout_configuration.ReadTotalTimeoutMultiplier = 1;// 0;
timeout_configuration.ReadTotalTimeoutConstant = 1;// 0;
timeout_configuration.WriteTotalTimeoutMultiplier = 1;// 0;
timeout_configuration.WriteTotalTimeoutConstant = 1;// 0;
err = SetCommTimeouts (rs232, &timeout_configuration);
if (err <= 0)
{
printf ("fail SetCommTimeouts: %d\n", GetLastError ()); CloseHandle (rs232); system ("pause"); return;
}
// WriteFile
DWORD buffer_size_w;
char buffer_w[128] = "*IDN?\n";
err = WriteFile (rs232, buffer_w, strlen (buffer_w), &buffer_size_w, 0);
if (err <= 0)
{
printf ("fail WriteFile: %d\n", GetLastError ()); CloseHandle (rs232); system ("pause"); return;
}
printf ("written %d characters: %s\n", buffer_size_w, buffer_w);
// ReadFile
for (int x = 0; x < 10; ++x)
{
DWORD buffer_size_r;
char buffer_r[128] = {0};
err = ReadFile (rs232, buffer_r, 128, &buffer_size_r, 0);
if (err <= 0)
{
printf ("fail ReadFile: %d\n", GetLastError ()); Sleep (250); continue;
}
printf ("read %d characters: %s\n", buffer_size_r, buffer_r);
Sleep (250);
}
CloseHandle (rs232);
system ("pause");
}
Here is some more information about my setup:
I am using Windows 7 x64 and Microsoft Visual Studio 2013
The project is compiled as a Win32 Console
I use a FTDI Chipi-X USB to COM port converter cable
I have tried connecting with a Newport Motion Controller and a Thorlabs Piezo Controller
Here are the things I have tried so far:
Update the drivers of the Chipi-X VCOM
Change the COMMTIMEOUTS to various different values as seen in guides online
Using a HyperTerminal I am able to fully communicate back and forth with the device. If I use my own program to send commands that request something of the device, such as "*IDN?\n", my own ReadFile would thus return nothing. However, when I connect the HyperTerminal again I can press ENTER to receive the requested information.
Change the buffer sizes using SetupComm()
Change the ReadFile buffer size to 1 byte at a time
Implement the OVERLAPPED method as explained in this guide: https://msdn.microsoft.com/en-us/library/ff802693.aspx. It gave exactly the same problem as the non-overlapped code above: The windows functions would not generate errors but the read buffer would stay empty.
I tried communicating with a different device, this was interesting: Again I was able to fully communicate back and forth using the HyperTerminal. Whenever I used my own program to send, I would always receive the exact string I sent back using ReadFile. And again the actual requested information could be retrieved by reconnecting the HyperTerminal.
It seems to me there is some problem with buffers but I don't know what. I am also not sure if it is expectable that the HyperTerminal is able to pick up requested information that was requested several seconds earlier through a different COM port connection. Presumably the problem is related to my coding since the HyperTerminal works fine, but I cannot seem to find what is wrong with my code if I compare it with other code I find online.
Can someone help me out here?
EDIT:
I have created a new CLR/C++ test application using the following example: https://msdn.microsoft.com/en-us/library/system.io.ports.serialport(v=vs.110).aspx. This again gives the exact same problem of not being able to receive requests.
I have tried a Roline USB to RS232 cable: HyperTerminal works and my programming does not. The underlying hardware or drivers are likely not the problem here.

I solved the issue:
I forgot to send the carriage return (\r) at the end of my commands. Apparently the devices I was testing with both were waiting for the combination \r\n before actually parsing the request.
Somehow by using the hyperterminal I would be able to append the \r\n to the current COM port output buffer and get results delayed like that.

Related

QSerialPort is in use before application starts

I am developing an application for Apalis iMX6 with Qt C++ in Linux and I've added this application into the startup by means of profile.d
this code must set ttymxc1 into RS485 mode like below:
int enableRS485(){
struct serial_rs485 rs485conf;
int fd = open ("/dev/ttymxc1", O_RDWR);
if (fd < 0) {
printf("Error: Can't open: /dev/ttymxc1 %d\n",fd);
return fd;
}
rs485conf.flags |= SER_RS485_ENABLED;
rs485conf.flags &= ~(SER_RS485_RTS_ON_SEND);
rs485conf.flags |= SER_RS485_RTS_AFTER_SEND;
rs485conf.flags |= SER_RS485_RX_DURING_TX;
err = ioctl (fd, TIOCSRS485, &rs485conf);
if (err < 0) {
printf("Error: TIOCSRS485 ioctl not supported.\n");
return err;
}
err = close (fd);
if (err < 0) {
printf("Error: Can't close: /dev/ttyLP1 %d\n",err);
return err;
}
return 0;
}
this function is working as well and has no problem. but when I try to open the serial port sometimes during startup application couldn't get this serial port and QSerialPortInfo shows me ttymxc1 is in use. my initiation of the serial port is like below:
void SerialClass::initSerial()
{
m_serialPort = new QSerialPort();
enableRS485();
sleep(1);
m_serialPort->setPortName("/dev/ttymxc1");
m_serialPort->setFlowControl(QSerialPort::NoFlowControl);
m_serialPort->setBaudRate(9600);
m_serialPort->setRequestToSend(false);
bool res = m_serialPort->open(QIODevice::ReadWrite);
}
"QSerialPort::errorOccured" signal will emit with value "PermissionError"
but mysteriously "ls -l /proc/[0-9]/fd/ |grep /dev/ttymxc1" shows me ttymxc1 is in used by my application.
there is no application that works with serial port and my application is just for one time run.
Is there any idea?
Thanks
You need to call close() on m_serialPort when you close your application. Otherwise your serial port will keep in-use state.
I've found a new remedy, so I want to share it here.
in SerialClass constructor I've added initSerial(), in this way application at the beginning of starting, will open the ttymxc1.
There is no more problem with such a solution.
I don't have such an issue with Raspberry Pi (Raspberry Pi3 + Qt 5.6 + Raspbian). But Toradex Apalis is in another way.
Would you please tell me why?

Simplest IPC from one Linux app to another in C++ on raspberry pi

I need the simplest most reliable IPC method from one C++ app running on the RPi to another app.
All I'm trying to do is send a string message of 40 characters from one app to another
The first app is running as a service on boot, the other app is started at a later time and is frequently exited and restarted for debugging
The frequent debugging for the second app is whats causing problems with the IPCs I've tried so far
I've tried about 3 different methods and here is where they failed:
File FIFO, the problem is one program hangs while the other program is writing to the file
Shared memory: cannot initialize on one thread and read from another thread. Also frequent exiting while debugging causing GDB crashes with the following GDB command is taking too long to complete -stack-list-frames --thread 1
UDP socket with localhost - same issue as above, plus improper exits block the socket, forcing me to reboot device
Non blocking pipe - not getting any messages on the receiving process
What else can I try? I dont want to get the DBus library, seems too complex for this application.
Any simple server and client code or a link to it would be helpful
Here is my non-blockign pipe code, that doesnt work for me,
I assume its because I dont have a reference to the pipe from one app to the other
Code sourced from here: https://www.geeksforgeeks.org/non-blocking-io-with-pipes-in-c/
char* msg1 = "hello";
char* msg2 = "bye !!";
int p[2], i;
bool InitClient()
{
// error checking for pipe
if(pipe(p) < 0)
exit(1);
// error checking for fcntl
if(fcntl(p[0], F_SETFL, O_NONBLOCK) < 0)
exit(2);
//Read
int nread;
char buf[MSGSIZE];
// write link
close(p[1]);
while (1) {
// read call if return -1 then pipe is
// empty because of fcntl
nread = read(p[0], buf, MSGSIZE);
switch (nread) {
case -1:
// case -1 means pipe is empty and errono
// set EAGAIN
if(errno == EAGAIN) {
printf("(pipe empty)\n");
sleep(1);
break;
}
default:
// text read
// by default return no. of bytes
// which read call read at that time
printf("MSG = % s\n", buf);
}
}
return true;
}
bool InitServer()
{
// error checking for pipe
if(pipe(p) < 0)
exit(1);
// error checking for fcntl
if(fcntl(p[0], F_SETFL, O_NONBLOCK) < 0)
exit(2);
//Write
// read link
close(p[0]);
// write 3 times "hello" in 3 second interval
for(i = 0 ; i < 3000000000 ; i++) {
write(p[0], msg1, MSGSIZE);
sleep(3);
}
// write "bye" one times
write(p[0], msg2, MSGSIZE);
return true;
}
Please consider ZeroMQ
https://zeromq.org/
It is lightweight and has wrapper for all major programming languages.

USB Serial Device with Virtual COM port - ReadFile() reads zero bytes if use CreateFile() with USB path

I have a point of sale application that uses Serial Communication ports (RS-232) to communicate with a scale for weighing products. I am now working on being able to support USB devices directly rather than using a Virtual Serial Communication port as they have an annoying tendency to move around.
What we have found is that while Windows 7 seems to automatically create the Virtual Serial Communication port, other versions of Windows such as POS Ready 7 may not. We suspect this is due to a specific .inf file with Windows 7 that is missing from POS Ready 7. Can someone confirm that?
I have a USB sample application that works intermittently. I am having a problem with the USB level communication with the ReadFile() Windows API function. I am using CreateFile() specifying the USB device path to obtain an I/O handle followed by using WriteFile() and ReadFile() to communicate with the scale. The ReadFile() is not providing data in some cases.
Background Information
The particular scale I am using, Brecknell 67xx bench scale, worked with using Virtual Serial Communication port directly out of the box with the point of sale application. I connected the scale to my Windows 7 PC with a USB cable and Windows automatically installed the drivers to create a Virtual Serial port, COM4 in my case. I then configured the application to talk to the scale through COM4 and everything worked fine.
The protocol for using the scale is to send a two byte command, "W\r" (capital letter W followed by a carriage return character) to the scale and to then read a 16 byte response which contains the current weight as well as status information about scale mechanics such as In Motion.
The sample USB application that I am learning from will work successfully providing a weight. Then it will stop working properly with the behavior of the ReadFile() returning zero bytes read. Once it stops working it will continue failing to provide data from the ReadFile() even if I unplug and replug the USB cable or restart my PC.
A previous version of the learning application was hanging on the ReadFile() and when a Break All was done with Visual Studio, a pause followed by a message indicating a deadlock would be displayed. However since I started using SetCommTimeouts() with a 5000 millisecond timeout value in ReadTotalTimeoutConstant I see a consistent 5 second pause before the ReadFile() returns with zero bytes read.
The strange thing is that if I then use the application which opens the Virtual Serial Communication port, COM4, that application works fine and the scale reports the weight of items.
I can then return to the sample application that uses direct USB rather than the Virtual Serial Communication port and it will work fine reporting weights.
However if I then unplug the USB cable connecting scale with PC, which powers off the scale as well, then plug the USB cable back in, the sample application no longer functions correctly and once again I see the pause with timeout.
Then I try using the original point of sale application that depends on Serial Communication ports using the Virtual Serial port, COM4, and that application weighs items just fine.
And when I then retry my sample application, it also will report item weights.
My Questions.
If a USB device creates a Virtual Serial Communications port when it is plugged in then is it required to only use the Virtual Serial port by specifying the communications port, COM4 in my case, in the CreateFile() call?
How is it possible to have direct USB serial communication by using CreateFile() with the USB device path if the device causes Windows to generate a Virtual Communication port?
Is there some way of specifying that any version of Windows is to automatically create a Virtual Serial Communications port for the device when it is plugged in?
Source Code of the Sample USB Application
The source code from my sample USB Windows Console application using Visual Studio 2005 is as follows with the main being at the bottom and much of this being the class for finding a particular USB device and then allowing ReadFile() and WriteFile():
// usb_test_cons.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <windows.h>
#include <setupapi.h>
#include <initguid.h>
#include <stdio.h>
// This is the GUID for the USB device class.
// It is defined in the include file Usbiodef.h of the Microsoft Windows Driver Kit.
// See also https://msdn.microsoft.com/en-us/library/windows/hardware/ff545972(v=vs.85).aspx which
// provides basic documentation on this GUID.
DEFINE_GUID(GUID_DEVINTERFACE_USB_DEVICE, 0xA5DCBF10L, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED);
// (A5DCBF10-6530-11D2-901F-00C04FB951ED)
// Following are standard defines to be used with all of the
// devices that are use through the UIE interface.
#define UIE_DEVICE_ERROR (-11) /* error when accessing the device */
#define UIE_DEVICE_NOT_PROVIDE (-12) /* device is not provided */
#define UIE_DEVICE_ERROR_RANGE (-13) /* range error */
#define UIE_DEVICE_ERROR_COM (-14) /* communication error */
#define UIE_DEVICE_TIMEOUT (-15) /* communication error */
#define UIE_DEVICE_SPECIFIC (-20) /* device specific errors start here */
#define UIE_SCALE_ETX 0x03 /* ETX character */
#define UIE_SCALE_IN_MOTION 0x01 /* scale in motion */
#define UIE_SCALE_ZERO 0x02 /* zero weight */
#define UIE_SCALE_UNDER 0x01 /* under capacity */
#define UIE_SCALE_OVER 0x02 /* over capacity */
#define UIE_SCALE_ERROR UIE_DEVICE_ERROR /* error */
#define UIE_SCALE_NOT_PROVIDE UIE_DEVICE_NOT_PROVIDE /* not provide */
#define UIE_SCALE_TIMEOUT UIE_DEVICE_TIMEOUT /* time out when reading from scale */
#define UIE_SCALE_MOTION (UIE_DEVICE_SPECIFIC-1) /* motion */
#define UIE_SCALE_UNDER_CAPACITY (UIE_DEVICE_SPECIFIC-2) /* under capacity */
#define UIE_SCALE_OVER_CAPACITY (UIE_DEVICE_SPECIFIC-3) /* over capacity */
#define UIE_SCALE_DATAFORMAT (UIE_DEVICE_SPECIFIC-4) /* Data read from scale incorrect format in UieScaleAnalysis() */
#define UIE_SCALE_DATAUNITS (UIE_DEVICE_SPECIFIC-5) /* Units read from scale incorrect in UieScaleAnalysis() */
static SHORT UieScaleStatus(char *puchBuffer, DWORD sLength)
{
UCHAR uchByte;
switch (sLength) {
case 16:
// The scale message is a weight message with a status section.
// Move the buffer pointer to where the status section should begin.
// A status only message has the same format as the status section of a weight message.
puchBuffer += 10;
case 6:
// The scale message may be a status only message if there is a problem with the scale.
// A status only message is 6 characters with the letter S as the second character.
if (*(puchBuffer + 0) != '\n' ||
*(puchBuffer + 1) != 'S' ||
*(puchBuffer + 4) != '\r' ||
*(puchBuffer + 5) != UIE_SCALE_ETX) {
return (UIE_SCALE_DATAFORMAT); /* exit ... */
}
break;
default:
return (UIE_SCALE_DATAFORMAT); /* exit ... */
break;
}
/* --- check status of low byte --- */
uchByte = *(puchBuffer + 3) - (UCHAR)0x30;
if (uchByte & UIE_SCALE_UNDER) {
return (UIE_SCALE_UNDER_CAPACITY);
} else if (uchByte & UIE_SCALE_OVER) {
return (UIE_SCALE_OVER_CAPACITY);
}
/* --- check status of high byte --- */
uchByte = *(puchBuffer + 2) - (UCHAR)0x30;
if (uchByte & UIE_SCALE_IN_MOTION) {
return (UIE_SCALE_MOTION);
} else if (uchByte & UIE_SCALE_ZERO) {
return (0);
} else {
return (TRUE);
}
}
class UsbSerialDevice
{
public:
UsbSerialDevice();
~UsbSerialDevice();
int CreateEndPoint (wchar_t *wszVendorId);
int CloseEndPoint ();
int ReadStream (void *bString, size_t nBytes);
int WriteStream (void *bString, size_t nBytes);
DWORD m_dwError; // GetLastError() for last action
DWORD m_dwErrorWrite; // GetLastError() for last write
DWORD m_dwErrorRead; // GetLastError() for last read
DWORD m_dwBytesWritten;
DWORD m_dwBytesRead;
private:
HANDLE m_hFile;
DWORD m_dwStatError;
COMMTIMEOUTS m_timeOut;
COMSTAT m_statOut;
};
UsbSerialDevice::UsbSerialDevice() :
m_dwError(0),
m_dwErrorWrite(0),
m_dwErrorRead(0),
m_dwBytesWritten(0),
m_dwBytesRead(0),
m_hFile(NULL)
{
}
UsbSerialDevice::~UsbSerialDevice()
{
CloseHandle (m_hFile);
}
int UsbSerialDevice::WriteStream(void *bString, size_t nBytes)
{
BOOL bWrite = FALSE;
if (m_hFile) {
m_dwError = m_dwErrorWrite = 0;
m_dwBytesWritten = 0;
ClearCommError (m_hFile, &m_dwStatError, &m_statOut);
bWrite = WriteFile (m_hFile, bString, nBytes, &m_dwBytesWritten, NULL);
m_dwError = m_dwErrorWrite = GetLastError();
return 0;
}
return -1;
}
int UsbSerialDevice::ReadStream(void *bString, size_t nBytes)
{
BOOL bRead = FALSE;
if (m_hFile) {
m_dwError = m_dwErrorRead = 0;
m_dwBytesRead = 0;
ClearCommError (m_hFile, &m_dwStatError, &m_statOut);
bRead = ReadFile (m_hFile, bString, nBytes, &m_dwBytesRead, NULL);
m_dwError = m_dwErrorRead = GetLastError();
return 0;
}
return -1;
}
int UsbSerialDevice::CreateEndPoint (wchar_t *wszVendorId)
{
HDEVINFO hDevInfo;
m_dwError = ERROR_INVALID_HANDLE;
// We will try to get device information set for all USB devices that have a
// device interface and are currently present on the system (plugged in).
hDevInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_USB_DEVICE, NULL, 0, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
if (hDevInfo != INVALID_HANDLE_VALUE)
{
DWORD dwMemberIdx;
BOOL bContinue = TRUE;
SP_DEVICE_INTERFACE_DATA DevIntfData;
// Prepare to enumerate all device interfaces for the device information
// set that we retrieved with SetupDiGetClassDevs(..)
DevIntfData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
dwMemberIdx = 0;
// Next, we will keep calling this SetupDiEnumDeviceInterfaces(..) until this
// function causes GetLastError() to return ERROR_NO_MORE_ITEMS. With each
// call the dwMemberIdx value needs to be incremented to retrieve the next
// device interface information.
for (BOOL bContinue = TRUE; bContinue; ) {
PSP_DEVICE_INTERFACE_DETAIL_DATA DevIntfDetailData;
SP_DEVINFO_DATA DevData;
DWORD dwSize;
dwMemberIdx++;
SetupDiEnumDeviceInterfaces(hDevInfo, NULL, &GUID_DEVINTERFACE_USB_DEVICE, dwMemberIdx, &DevIntfData);
if (GetLastError() == ERROR_NO_MORE_ITEMS) break;
// As a last step we will need to get some more details for each
// of device interface information we are able to retrieve. This
// device interface detail gives us the information we need to identify
// the device (VID/PID), and decide if it's useful to us. It will also
// provide a DEVINFO_DATA structure which we can use to know the serial
// port name for a virtual com port.
DevData.cbSize = sizeof(DevData);
// Get the required buffer size. Call SetupDiGetDeviceInterfaceDetail with
// a NULL DevIntfDetailData pointer, a DevIntfDetailDataSize
// of zero, and a valid RequiredSize variable. In response to such a call,
// this function returns the required buffer size at dwSize.
SetupDiGetDeviceInterfaceDetail(hDevInfo, &DevIntfData, NULL, 0, &dwSize, NULL);
// Allocate memory for the DeviceInterfaceDetail struct. Don't forget to
// deallocate it later!
DevIntfDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize);
DevIntfDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
if (SetupDiGetDeviceInterfaceDetail(hDevInfo, &DevIntfData, DevIntfDetailData, dwSize, &dwSize, &DevData))
{
// Finally we can start checking if we've found a useable device,
// by inspecting the DevIntfDetailData->DevicePath variable.
//
// The DevicePath looks something like this for a Brecknell 67xx Series Serial Scale
// \\?\usb#vid_1a86&pid_7523#6&28eaabda&0&2#{a5dcbf10-6530-11d2-901f-00c04fb951ed}
//
// The VID for a particular vendor will be the same for a particular vendor's equipment.
// The PID is variable for each device of the vendor.
//
// As you can see it contains the VID/PID for the device, so we can check
// for the right VID/PID with string handling routines.
// See https://github.com/Microsoft/Windows-driver-samples/blob/master/usb/usbview/vndrlist.h
if (wcsstr (DevIntfDetailData->DevicePath, wszVendorId)) {
m_dwError = 0;
m_hFile = CreateFile (DevIntfDetailData->DevicePath, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
if (m_hFile == INVALID_HANDLE_VALUE) {
m_dwError = GetLastError();
} else {
GetCommTimeouts (m_hFile, &m_timeOut);
m_timeOut.ReadIntervalTimeout = 0;
m_timeOut.ReadTotalTimeoutMultiplier = 0;
m_timeOut.ReadTotalTimeoutConstant = 5000;
SetCommTimeouts (m_hFile, &m_timeOut);
m_dwError = GetLastError();
}
bContinue = FALSE; // found the vendor so stop processing after freeing the heap.
}
}
HeapFree(GetProcessHeap(), 0, DevIntfDetailData);
}
SetupDiDestroyDeviceInfoList(hDevInfo);
}
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
UsbSerialDevice myDev;
myDev.CreateEndPoint (L"vid_1a86&pid_7523");
switch (myDev.m_dwError) {
case 0:
// no error so just ignore.
break;
case ERROR_ACCESS_DENIED:
wprintf (_T(" CreateFile() failed. GetLastError() = %d\n ERROR_ACCESS_DENIED: Access is denied.\n Is it already in use?\n"), myDev.m_dwError);
break;
case ERROR_GEN_FAILURE:
wprintf (_T(" CreateFile() failed. GetLastError() = %d\n ERROR_GEN_FAILURE: A device attached to the system is not functioning.\n Is it an HID?\n"), myDev.m_dwError);
break;
case ERROR_INVALID_HANDLE:
wprintf (_T(" CreateFile() failed. GetLastError() = %d\n ERROR_INVALID_HANDLE: The handle is invalid.\n CreateFile() failed?\n"), myDev.m_dwError);
break;
default:
wprintf (_T(" CreateFile() failed. GetLastError() = %d\n"), myDev.m_dwError);
break;
}
if (myDev.m_dwError == 0) {
char reqWeight[] = "W\r";
char resWeight[256] = {0};
myDev.WriteStream (reqWeight, strlen (reqWeight));
wprintf (_T(" Sent request now get response.\n"));
Sleep (50);
myDev.ReadStream (resWeight, 16);
wprintf (_T(" Got response.\n"));
if (resWeight[0] != '\n' || resWeight[9] != '\r') {
wprintf (_T(" Unexpected format of response.\n"));
}
short sRet = UieScaleStatus (resWeight, myDev.m_dwBytesRead);
resWeight[9] = 0; // terminate the weight string so that we can write it out.
wprintf (_T(" ScaleStatus = %d, Response from device - \"%S\"\n"), sRet, resWeight + 1);
}
return 0;
}
Additional Information Developed
Overview of INF Files from Microsoft MSDN https://msdn.microsoft.com/en-us/windows/hardware/drivers/install/overview-of-inf-files
Stackoverflow Do I need to write my own host side USB driver for a CDC device
Stackoverflow how to get vendor id and product id of a plugged usb device on windows
Is it possible to “transplant” drivers between machines? has a link to a document Debugging USB Device Installation on Windows and this posting Remove Windows Device Class in Registry has a bit more info.
USB serial driver (Usbser.sys) from Microsoft.
USB device class drivers included in Windows from Microsoft.
The communication of the PC that runs windows (USB host) and the scale (USB device) obeys the USB protocol. If you install libusb for windows you can get similar informations as the PC gets from the USB device, when using lsusb -v. It is possible for a USB device to implement more than one USB class.
If the USB device creates a Virtual COM port it for sure implements the CDC ACM class (Communication Device Class Abstract Control Model) beside this it can also implement other USB classes like Mass Storage class,...
Direct communication with USB device depends also on what device classes it implements and its interfaces and endpoints. If the USB device implements a CDC ACM (Virtual COM) you use the specific RS-232 commands (i.e. https://www.commfront.com/pages/3-easy-steps-to-understand-and-control-your-rs232-devices or send a hexadecimal 'D' to a multimeter to receive the measured value) if it implements the Mass Storage class you normally use bulk transfers
To change the mode of the USB device you use control transfers (see USB in a nutshell)
In this link is how Win determines which driver to load after determining the USB class of the device https://msdn.microsoft.com/en-us/library/windows/hardware/ff538820%28v=vs.85%29.aspx
(https://msdn.microsoft.com/en-us/library/windows/hardware/jj649944%28v=vs.85%29.aspx)
i do not know how Brecknell implemented the CDC ACM device class that is the Virtual COM however normally any Win version that supports USB should be able to load a driver for a CDC ACM device class (Virtual COM) so you are correct this seems to be a problem of the .inf driver file or the driver loading mechanism (maybe a problem of the Brecknell CDC ACM implementation but i do not think so)
Then, if Win loads a working driver the normal way is what you did: use CreateFile() with the COM that is assigned to the USB device.
The strange thing is that if I then use the application which opens the Virtual Serial Communication port, COM4, that application works fine and the scale reports the weight of items. <- this is not strange, strange is that some Win versions do not recognize a CDC USB device .
The standard driver for CDC devices seems to be USBser.sys (https://msdn.microsoft.com/de-de/library/windows/hardware/dn707976%28v=vs.85%29.aspx)
If you search 'windows does not recognize CDC device' you get results
If a USB device creates a Virtual Serial Communications port when it is plugged in then is it required to only use the Virtual Serial port by specifying the communications port, COM4 in my case, in the CreateFile() call? Yes, if a USB device implements a virtual COM it is the easiest way to use this COM to communicate with this device
See also http://www.beyondlogic.org/usbnutshell/usb1.shtml USB in a nutshell
standard USB: device descriptor (class) -> interface -> (configuration) -> endpoint
Testing with a modified USB Serial sample application indicates that when a USB device that creates a Virtual Serial Communications port is unplugged the Virtual Serial Port created is torn down and disappears from the port listing in Device Manager app of Control Panel.
When the device, a USB scale in this case, is plugged in and turned on the Virtual Serial Communications port reappears in Device Manager. However when the Virtual Serial Communications port is created, it is created with default serial port settings (baud rate, parity, etc.) and these may not be the same as for your actual device.
In summary it appears that the Virtual Serial Communications port settings apply regardless of whether the port is opened as a COM port or if the USB device path name is used with the CreateFile().
I am still investigating the Virtual Serial Port not automatically being created when using POS Ready 7 and will update this answer once I know more. However preliminary comparison between Windows 7 and POS Ready 7 is showing that a file that specifies usbser.sys, mdmcpq.inf, that is on my Windows 7 PC is not on the POS Ready 7 terminal in the folder C:\Windows\inf.
See The INF File for a write up on the .inf file structure and the various sections. It is a bit old however it seems to cover the basics in a readable manner.
I modified the function CreateEndPoint() in the question to the following along with a change to the class and the constructor to create a set of default communication port settings for my scale.
The class and the constructor now contain a set of defaults for the communication port settings (9600 baud, 7 data bits, one stop bit, even parity for the scale) and look like:
class UsbSerialDevice
{
public:
UsbSerialDevice();
UsbSerialDevice(DWORD BaudRate, BYTE ByteSize = 8, BYTE Parity = NOPARITY, BYTE StopBits = ONESTOPBIT);
~UsbSerialDevice();
int CreateEndPoint (wchar_t *wszVendorId);
int SetCommPortSettings (DWORD BaudRate, BYTE ByteSize = 8, BYTE Parity = NOPARITY, BYTE StopBits = ONESTOPBIT);
int CloseEndPoint ();
int ReadStream (void *bString, size_t nBytes);
int WriteStream (void *bString, size_t nBytes);
int UpdateSettingsProxy (void);
DWORD m_dwError; // GetLastError() for last action
DWORD m_dwErrorWrite; // GetLastError() for last write
DWORD m_dwErrorRead; // GetLastError() for last read
DWORD m_dwErrorCommState;
DWORD m_dwErrorCommTimeouts;
DWORD m_dwBytesWritten;
DWORD m_dwBytesRead;
COMMTIMEOUTS m_timeOut; // last result from GetCommTimeouts(), updated by UpdateSettingsProxy()
COMSTAT m_statOut; // last result from ClearCommError()
DCB m_commSet; // last result from GetCommState(), updated by UpdateSettingsProxy()
private:
HANDLE m_hFile;
DWORD m_dwStatError;
DCB m_commSetDefault; // the defaults used as standard
wchar_t m_portName[24]; // contains portname if defined for device in form \\.\\COMnn
};
UsbSerialDevice::UsbSerialDevice() :
m_dwError(0),
m_dwErrorWrite(0),
m_dwErrorRead(0),
m_dwBytesWritten(0),
m_dwBytesRead(0),
m_hFile(NULL)
{
// initialize our COM port settings and allow people to change with
memset (&m_commSetDefault, 0, sizeof(m_commSetDefault));
m_commSetDefault.DCBlength = sizeof(m_commSetDefault);
m_commSetDefault.BaudRate = CBR_9600;
m_commSetDefault.ByteSize = 7;
m_commSetDefault.Parity = EVENPARITY;
m_commSetDefault.StopBits = ONESTOPBIT;
m_commSet.fDtrControl = DTR_CONTROL_DISABLE;
m_portName[0] = 0;
}
The function CreateEndPoint() is modified so that after doing the CreateFile() to open the USB device using the pathname of the USB Device, it will now also set the communication port parameters.
An additional experimental change to the method was to check if a communications port name was also created and if so to generate the proper COM port specification to be used with CreateFile(). I plan to split out the CreateEndPoint() method into two methods, one to do a look up of the USB device and a second to actually do the open as I continue my investigation.
The format for the COM port specifier for CreateFile() for COM ports greater than COM9 appear to need the \\.\ as a prefix. See HOWTO: Specify Serial Ports Larger than COM9 from Microsoft Support.
The new version of CreateEndPoint() looks like:
int UsbSerialDevice::CreateEndPoint (wchar_t *wszVendorId)
{
HDEVINFO hDevInfo;
m_dwError = ERROR_INVALID_HANDLE;
// We will try to get device information set for all USB devices that have a
// device interface and are currently present on the system (plugged in).
hDevInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_USB_DEVICE, NULL, 0, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
if (hDevInfo != INVALID_HANDLE_VALUE)
{
DWORD dwMemberIdx;
BOOL bContinue = TRUE;
SP_DEVICE_INTERFACE_DATA DevIntfData;
// Prepare to enumerate all device interfaces for the device information
// set that we retrieved with SetupDiGetClassDevs(..)
DevIntfData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
dwMemberIdx = 0;
// Next, we will keep calling this SetupDiEnumDeviceInterfaces(..) until this
// function causes GetLastError() to return ERROR_NO_MORE_ITEMS. With each
// call the dwMemberIdx value needs to be incremented to retrieve the next
// device interface information.
for (BOOL bContinue = TRUE; bContinue; ) {
PSP_DEVICE_INTERFACE_DETAIL_DATA DevIntfDetailData;
SP_DEVINFO_DATA DevData;
DWORD dwSize;
dwMemberIdx++;
SetupDiEnumDeviceInterfaces(hDevInfo, NULL, &GUID_DEVINTERFACE_USB_DEVICE, dwMemberIdx, &DevIntfData);
if (GetLastError() == ERROR_NO_MORE_ITEMS) break;
// As a last step we will need to get some more details for each
// of device interface information we are able to retrieve. This
// device interface detail gives us the information we need to identify
// the device (VID/PID), and decide if it's useful to us. It will also
// provide a DEVINFO_DATA structure which we can use to know the serial
// port name for a virtual com port.
DevData.cbSize = sizeof(DevData);
// Get the required buffer size. Call SetupDiGetDeviceInterfaceDetail with
// a NULL DevIntfDetailData pointer, a DevIntfDetailDataSize
// of zero, and a valid RequiredSize variable. In response to such a call,
// this function returns the required buffer size at dwSize.
SetupDiGetDeviceInterfaceDetail(hDevInfo, &DevIntfData, NULL, 0, &dwSize, NULL);
// Allocate memory for the DeviceInterfaceDetail struct. Don't forget to
// deallocate it later!
DevIntfDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize);
DevIntfDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
if (SetupDiGetDeviceInterfaceDetail(hDevInfo, &DevIntfData, DevIntfDetailData, dwSize, &dwSize, &DevData))
{
// Finally we can start checking if we've found a useable device,
// by inspecting the DevIntfDetailData->DevicePath variable.
//
// The DevicePath looks something like this for a Brecknell 67xx Series Serial Scale
// \\?\usb#vid_1a86&pid_7523#6&28eaabda&0&2#{a5dcbf10-6530-11d2-901f-00c04fb951ed}
//
// The VID for a particular vendor will be the same for a particular vendor's equipment.
// The PID is variable for each device of the vendor.
//
// As you can see it contains the VID/PID for the device, so we can check
// for the right VID/PID with string handling routines.
// See https://github.com/Microsoft/Windows-driver-samples/blob/master/usb/usbview/vndrlist.h
if (wcsstr (DevIntfDetailData->DevicePath, wszVendorId)) {
HKEY hKey;
m_dwError = 0;
// To find out the serial port for our scale device,
// we'll need to check the registry:
hKey = SetupDiOpenDevRegKey(hDevInfo, &DevData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ);
if (hKey != INVALID_HANDLE_VALUE) {
DWORD dwSize = 0, dwType = 0;
wchar_t lpData[16] = {0};
dwType = REG_SZ;
dwSize = sizeof(lpData);
LONG queryStat = RegQueryValueEx(hKey, _T("PortName"), NULL, &dwType, (LPBYTE)&lpData[0], &dwSize);
RegCloseKey(hKey);
if (queryStat == ERROR_SUCCESS) {
wcscpy (m_portName, L"\\\\.\\");
wcsncat (m_portName, lpData, dwSize / sizeof(wchar_t));
}
} else {
m_dwError = GetLastError();
}
m_hFile = CreateFile (DevIntfDetailData->DevicePath, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
if (m_hFile == INVALID_HANDLE_VALUE) {
m_dwError = GetLastError();
} else {
m_dwError = 0;
GetCommState (m_hFile, &m_commSet);
m_commSet = m_commSetDefault;
SetCommState (m_hFile, &m_commSet);
m_dwErrorCommState = GetLastError();
GetCommState (m_hFile, &m_commSet);
GetCommTimeouts (m_hFile, &m_timeOut);
m_timeOut.ReadIntervalTimeout = 0;
m_timeOut.ReadTotalTimeoutMultiplier = 0;
m_timeOut.ReadTotalTimeoutConstant = 5000;
SetCommTimeouts (m_hFile, &m_timeOut);
GetCommTimeouts (m_hFile, &m_timeOut);
m_dwErrorCommTimeouts = GetLastError();
}
bContinue = FALSE; // found the vendor so stop processing after freeing the heap.
}
}
HeapFree(GetProcessHeap(), 0, DevIntfDetailData);
}
SetupDiDestroyDeviceInfoList(hDevInfo);
}
return 0;
}
POS Ready 7 Investigation
Looking back on the Windows 7 PC which seems to work fine with the scale, we looked in the driver details for the Virtual Serial Communications port using Device Manager from the Control Panel. The driver details indicated that the driver being used was CH341S64.SYS provided by www.winchiphead.com and the Property "Inf name" has a value of oem50.inf. I found a forum post http://doityourselfchristmas.com/forums/showthread.php?14690-CH340-USB-RS232-Driver which provides a link to a driver download at http://www.winchiphead.com/download/CH341/CH341SER.ZIP however another version available from http://www.wch.cn/download/CH341SER_ZIP.html may be more up to date.
Putting the downloaded zip file, CH341SER.ZIP from the later on to the POS Ready 7 terminal, I unzipped the contents and ran SETUP.EXE in the folder CH341SER (there were two folders in the zip file and the one called INSTALL seemed for device development) which displayed a dialog and allowed me to install the CH341SER.INF. Once the install completed, when I plugged in the USB scale, the device was recognized and a Virtual Serial Communications port was created and my test application worked.
I did find some documentation however it was all in Chinese. Google Translate provided a readable version of the USB device documentation. It looks like there is additional work to be done for device management when the scale may be unplugged/replugged while in use.
One other strange thing is that the scale is now using a different COM port name, COM5 rather than COM4. Looking in the Advanced Settings it appears that COM4 is "In Use" though not showing in the list of ports. Further experiments indicates that the COM port name used for the scale device depends on which of the two front panel USB ports are plugged into. I had originally plugged into the left one and today, plugged into the right USB port with the result of the Virtual Serial Communications port being created with a new COM port name.
However since we are using the USB path in the CreateFile(), no change was needed in the USB sample test application.
Further testing with POS Ready 7 using three USB to Serial converter cables showed that different vendor's cables had the same vendor id and product code in the USB path. The USB path also changed depending on which USB port a cable was plugged into. In some cases only the last digit in the path name differed. An interesting experiment would be if a USB hub is connected to a USB port and then USB connections are made to the hub what does the path name look like then?
You are confusing two issues, and it's probably not viable for us to tell them apart.
I say this because you link ReadFile problems to the device name. However, ReadFile works on a HANDLE. The function which takes a name and converts it into a HANDLE is called CreateFile. That means ReadFile doesn't even know on what name it's operating.
This misunderstanding also explains a few other behaviors. For instance, when you unplug the device, the HANDLE becomes invalid, and it stays invalid. Replugging the device may restore the name, but not the HANDLE.

Unable to receive data from serial port

Currently I try to write a serial port communication in VC++ to transfer data from PC and robot via XBee transmitter. But after I wrote some commands to poll data from robot, I didn't receive anything from the robot (the output of filesize is 0 in the code.). Because my MATLAB interface works, so the problem should happen in the code not the hardware or communication. Would you please give me help?
01/03/2014 Updated: I have updated my codes. It still can not receive any data from my robot (the output of read is 0). When I use "cout<<&read" in the while loop, I obtain "0041F01C1". I also don't know how to define the size of buffer, because I don't know the size of data I will receive. In the codes, I just give it a random size like 103. Please help me.
// This is the main DLL file.
#include "StdAfx.h"
#include <iostream>
#define WIN32_LEAN_AND_MEAN //for GetCommState command
#include "Windows.h"
#include <WinBase.h>
using namespace std;
int main(){
char init[]="";
HANDLE serialHandle;
// Open serial port
serialHandle = CreateFile("\\\\.\\COM8", GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
// Do some basic settings
DCB serialParams;
DWORD read, written;
serialParams.DCBlength = sizeof(serialParams);
if((GetCommState(serialHandle, &serialParams)==0))
{
printf("Get configuration port has a problem.");
return FALSE;
}
GetCommState(serialHandle, &serialParams);
serialParams.BaudRate = CBR_57600;
serialParams.ByteSize = 8;
serialParams.StopBits = ONESTOPBIT;
serialParams.Parity = NOPARITY;
//set flow control="hardware"
serialParams.fOutX=false;
serialParams.fInX=false;
serialParams.fOutxCtsFlow=true;
serialParams.fOutxDsrFlow=true;
serialParams.fDsrSensitivity=true;
serialParams.fRtsControl=RTS_CONTROL_HANDSHAKE;
serialParams.fDtrControl=DTR_CONTROL_HANDSHAKE;
if (!SetCommState(serialHandle, &serialParams))
{
printf("Set configuration port has a problem.");
return FALSE;
}
GetCommState(serialHandle, &serialParams);
// Set timeouts
COMMTIMEOUTS timeout = { 0 };
timeout.ReadIntervalTimeout = 30;
timeout.ReadTotalTimeoutConstant = 30;
timeout.ReadTotalTimeoutMultiplier = 30;
timeout.WriteTotalTimeoutConstant = 30;
timeout.WriteTotalTimeoutMultiplier = 30;
SetCommTimeouts(serialHandle, &timeout);
if (!SetCommTimeouts(serialHandle, &timeout))
{
printf("Set configuration port has a problem.");
return FALSE;
}
//write packet to poll data from robot
WriteFile(serialHandle,">*>p4",strlen(">*>p4"),&written,NULL);
//check whether the data can be received
char buffer[103];
do {
ReadFile (serialHandle,buffer,sizeof(buffer),&read,NULL);
cout << read;
} while (read!=0);
//buffer[read]="\0";
CloseHandle(serialHandle);
return 0;
}
GetFileSize is documented not to be valid when used with a serial port handle. Use the ReadFile function to receive serial port data.
You should use strlen instead of sizeof here:
WriteFile(serialHandle,init,strlen(init),&written,NULL)
You would be even better off creating a function like this:
function write_to_robot (const char * msg)
{
DWORD written;
BOOL ok = WriteFile(serialHandle, msg, strlen(msg), &written, NULL)
&& (written == strlen(msg));
if (!ok) printf ("Could not send message '%s' to robot\n", msg);
}
But that's only the appetizer. The main trouble is, as MDN says:
You cannot use the GetFileSize function with a handle of a nonseeking device such as a pipe or a communications device.
If you want to read from the port, you can simply use ReadFile until it returns zero bytes.
If you already know the max size of your robot's response, try reading that many characters.
Continue reading until the read reports an actual number of bytes read inferior to the size of the buffer. For instance:
#define MAX_ROBOT_ANSWER_LENGTH 1000 /* bytes */
const char * read_robot_response ()
{
static char buffer[MAX_ROBOT_ANSWER_LENGTH];
DWORD read;
if (!ReadFile (serialHandle, buffer, sizeof(buffer), &read, NULL))
{
printf ("something wrong with the com port handle");
exit (-1);
}
if (read == sizeof(buffer))
{
// the robot response is bigger than it should
printf ("this robot is overly talkative. Flushing input\n");
// read the rest of the input so that the next answer will not be
// polluted by leftovers of the previous one.
do {
ReadFile (serialHandle, buffer, sizeof(buffer), &read, NULL);
} while (read != 0);
// report error
return "error: robot response exceeds maximal length";
}
else
{
// add a terminator to string in case Mr Robot forgot to provide one
buffer[read] = '\0';
printf ("Mr Robot said '%s'\n", buffer);
return buffer;
}
}
This simplistic function returns a static variable, which will be overwritten each time you call read_robot_response.
Of course the proper way of doing things would be to use blocking I/Os instead of waiting one second and praying for the robot to answer in time, but that would require a lot more effort.
If you feel adventurous, you can use overlapped I/O, as this lenghty MDN article thoroughly explores.
EDIT: after looking at your code
// this reads at most 103 bytes of the answer, and does not display them
if (!ReadFile(serialHandle,buffer,sizeof(buffer),&read,NULL))
{
printf("Reading data to port has a problem.");
return FALSE;
}
// this could display the length of the remaining of the answer,
// provided it is more than 103 bytes long
do {
ReadFile (serialHandle,buffer,sizeof(buffer),&read,NULL);
cout << read;
}
while (read!=0);
You are displaying nothing but the length of the response beyond the first 103 characters received.
This should do the trick:
#define BUFFER_LEN 1000
DWORD read;
char buffer [BUFFER_LEN];
do {
if (!ReadFile(
serialHandle, // handle
buffer, // where to put your characters
sizeof(buffer) // max nr of chars to read
-1, // leave space for terminator character
&read, // get the number of bytes actually read
NULL)) // Yet another blody stupid Microsoft parameter
{
// die if something went wrong
printf("Reading data to port has a problem.");
return FALSE;
}
// add a terminator after last character read,
// so as to have a null terminated C string to display
buffer[read] = '\0';
// display what you actually read
cout << buffer;
}
while (read!=0);
I advised you to wrap the actual calls to serial port accesses inside simpler functions for a reason.
As I said before, Microsoft interfaces are a disaster. They are verbose, cumbersome and only moderately consistent. Using them directly leads to awkward and obfuscated code.
Here, for instance, you seem to have gotten confused between read and buffer
read holds the number of bytes actually read from the serial port
buffer holds the actual data.
buffer is what you will want to display to see what the robot answered you
Also, you should have a documentation for your robot stating which kind of answers you are supposed to expect. It would help to know how they are formatted, for instance whether they are null-terminated strings or not. That could dispense to add the string terminator.

FILE_NOT_FOUND when trying to open COM port C++

I am trying to open a com port for reading and writing using C++ but I can't seem to pass the first stage of actually opening it. I get an INVALID_HANDLE_VALUE on the handle
with GetLastError FILE_NOT_FOUND. I have searched around the web for a couple of days I'm fresh out of ideas. I have searched through all the questions regarding COM on this website too.
I have scanned through the existing ports (or so I believe) to get the name of the port right.
I also tried combinations of _T("COM1") with the slashes, without the slashes, with colon, without colon and without the _T
I'm using windows 7 on 64 bit machine.
this is the code i got
I'll be glad for any input on this
void SendToCom(char* data, int len)
{
DWORD cbNeeded = 0;
DWORD dwPorts = 0;
EnumPorts(NULL, 1, NULL, 0, &cbNeeded, &dwPorts);
//What will be the return value
BOOL bSuccess = FALSE;
LPCSTR COM1 ;
BYTE* pPorts = static_cast<BYTE*>(malloc(cbNeeded));
bSuccess = EnumPorts(NULL, 1, pPorts, cbNeeded, &cbNeeded, &dwPorts);
if (bSuccess){
PORT_INFO_1* pPortInfo = reinterpret_cast<PORT_INFO_1*>(pPorts);
for (DWORD i=0; i<dwPorts; i++)
{
//If it looks like "COMX" then
size_t nLen = _tcslen(pPortInfo->pName);
if (nLen > 3)
{
if ((_tcsnicmp(pPortInfo->pName, _T("COM"), 3) == 0) ){
COM1 =pPortInfo->pName;
//COM1 ="\\\\.\\COM1";
HANDLE m_hCommPort = CreateFile( COM1 ,
GENERIC_READ|GENERIC_WRITE, // access ( read and write)
0, // (share) 0:cannot share the COM port
NULL, // security (None)
OPEN_EXISTING, // creation : open_existing
FILE_FLAG_OVERLAPPED, // we want overlapped operation
NULL // no templates file for COM port...
);
if (m_hCommPort==INVALID_HANDLE_VALUE)
{
DWORD err = GetLastError();
if (err == ERROR_FILE_NOT_FOUND) {
MessageBox(hWnd,"ERROR_FILE_NOT_FOUND",NULL,MB_ABORTRETRYIGNORE);
}
else
if(err == ERROR_INVALID_NAME) {
MessageBox(hWnd,"ERROR_INVALID_NAME",NULL,MB_ABORTRETRYIGNORE);
}
else
{
MessageBox(hWnd,"unkown error",NULL,MB_ABORTRETRYIGNORE);
}
}
else{
WriteAndReadPort(m_hCommPort,data);
}
}
pPortInfo++;
}
}
}
}
The Solution is to use
The Problem is, if your port is Bigger then 9 then you have to use the Syntax
LPCWSTR szPortName = L"\\\\.\\COM11";.
If you are on Windows 10 - running all system updates might help !
I had the same issue that opening port "COM4" returned an error ERROR_FILE_NOT_FOUND. When running the program as "Administrator" it worked. Now after a updating to 1511 the program can open "COM4" even not running as "Administrator".
http://www.cplusplus.com/forum/windows/163855/
Use CreateFileA(...) instead of CreateFile(...)
ERROR_FILE_NOT_FOUND can be produced from CreateFile(L"\\\\.\\COM1", ...) and CreateFile(L"COM1:", ...) after using the Device Manager to change the assigned COM Port number. Disabling and re-enabling the device, or unplugging and reconnecting the USB adapter resolves the issue.
A useful test to confirm whether it is your program or the system is to send data to the port in command prompt. A successful test will show an empty line. A failed test will show an error message.
C:\drop>echo > \\.\COM1
The system cannot find the file specified.
C:\drop>echo > \\.\COM1
C:\drop>