Serial Port Fails to open, Error 2? - c++

I'm having problems with opening a serial port in C++ on Windows 7. I'd like to send serial data from my computer to another one through a USB cable. The code I've found from various online sources is as follows:
#include <windows.h>
#include <stdio.h>
int main()
{
// Define the five bytes to send ("hello")
char bytes_to_send[5];
bytes_to_send[0] = 104;
bytes_to_send[1] = 101;
bytes_to_send[2] = 108;
bytes_to_send[3] = 108;
bytes_to_send[4] = 111;
// Declare variables and structures
HANDLE hSerial;
DCB dcbSerialParams = {0};
COMMTIMEOUTS timeouts = {0};
// Open the highest available serial port number
fprintf(stderr, "Opening serial port...");
hSerial = CreateFile(
"COM8", GENERIC_READ|GENERIC_WRITE, 0, 0,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 );
if (hSerial == INVALID_HANDLE_VALUE)
{
fprintf(stderr, "Error\n");
printf ("CreateFile failed with error %d.\n", GetLastError());
return 1;
}
else fprintf(stderr, "OK\n");
The programme never gets past this point, and the error which it throws is "Error 2". From what I've read I think this corresponds to "System cannot find the file specified". However it won't open for whatever COM port I try to use. I've also tried "\\.\COM8" but to no avail. Does anyone know some common problems that could be causing this issue? Are there any hardware specific issues to look out for?

Related

Configuring serial port with Windows API: CreateFile failed with error 2 (ERROR_FILE_NOT_FOUND)

I'm trying to create a C++ program to communicate with a serial port device using Windows API in Visual Studio Community 2017 on Windows 7. Running this example from MSDN with one change - using this:
const wchar_t *pcCommPort = TEXT("\\.\COM16"); // Most systems have a COM1 port
instead of this (otherwise it wouldn't compile):
TCHAR *pcCommPort = TEXT("COM1"); // Most systems have a COM1 port
I get a CreateFile error 2 (ERROR_FILE_NOT_FOUND). I'm quite clueless what's going wrong here.
Here's the code:
#include "stdafx.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(int argc, TCHAR *argv[])
{
DCB dcb;
HANDLE hCom;
BOOL fSuccess;
const wchar_t *pcCommPort = TEXT("\\.\COM16"); // 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());
system("PAUSE");
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_9600; // 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);
return (0);
}
There are two different defines that control the ANSI/Unicode character stuff:
#define UNICODE controls the Windows SDK API (LPTSTR and TEXT)
#define _UNICODE controls the C Run Time (TCHAR, _TEXT and _T)
You normally define none or both and if you don't you have to use the correct combinations:
const TCHAR* cstr = _T("Hello");
LPCTSTR winstr = TEXT("World");
The other issue with your code is that you are using TCHAR* and not const TCHAR*. Depending on your compiler version and switches, literal strings might be located in the read-only data section of the binary so make sure the type is a pointer to a constant string.
If you are still unsure of the sizes you can do this:
LPCTSTR x;
printf("TEXT=%d LPCTSTR=%d _T=%d TCHAR=%d\n", sizeof(TEXT("")), sizeof(*x), sizeof(_T("")), sizeof(TCHAR));
I just tested on a virtual machine with a COM port and the plain name works just fine:
LPCTSTR pcCommPort = TEXT("COM1");
HANDLE 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 you want to use a COM port above 9 you have to use the Win32 device path syntax:
LPCTSTR pcCommPortWin32DevicePath = TEXT("\\\\.\\COM16");
HANDLE hCom = CreateFile(pcCommPortWin32DevicePath, ...);
(MSDN describes the string as it should look in memory, not in your code. Your clue to this is the single slash in the example string. This means you must double all backslashes to get a correct C literal string.)
You need to escape backslashes in string literals, eg
const TCHAR *pcCommPort = TEXT("\\\\.\\COM16");

Which ReadFile parameter in this code is incorrect? (Error code 87)

(Edit: I didn't exclude any code except the headers and the main() function's brackets. Nothing is written between lines of code listed here.)
.
I used the ReadFile function to read this COM3 port (which returned no INVALID_HANDLE_VALUE or ERROR_FILE_NOT_FOUND):
LPCTSTR portName = "COM3" ;
HANDLE hSerial;
hSerial = CreateFile(portName,
GENERIC_READ | GENERIC_WRITE,
0, // exclusive access
NULL, // default security attributes
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL);
And the ReadFile function in question uses following parameters:
DWORD n = 512 ;
char szBuff[n] = {0};
DWORD dwBytesRead = 0;
if(!ReadFile(hSerial, szBuff, n, &dwBytesRead, NULL))
{
cout << "ReadFile error. Error code: " << GetLastError() << endl ;
cin.get() ;
return 0 ;
}
What changes should I introduce to cause the read to succeed?
(I searched through the function's documentation and other StackOverflow questions, tested lots of things, but couldn't find an answer.)
In ReadFile documentation you can read:
lpOverlapped [in, out, optional]
A pointer to an OVERLAPPED structure is required if the hFile parameter was opened with FILE_FLAG_OVERLAPPED, otherwise it can be NULL.
so since you specified FILE_FLAG_OVERLAPPED in CreateFile you should provide OVERLAPPED in ReadFile.
In CreateFile you can read on parameters for Communications Resources:
... and the handle can be opened for overlapped I/O.
so you can skip FILE_FLAG_OVERLAPPED in CreateFile
Marcin Jędrzejewski's answer is correct about the mismatch between the overlapped IO Flag and the ReadFile function, but I will leave this up just to be helpful.
You are missing a lot of initialisation which may be helpful to you when operating a COM port.
This code is used to open, configure, and read from a COM port on windows using C++.
FOR REFERENCE
READ_BUFFER_SIZE = 1024;
WRITE_BUFFER_SIZE = 1024;
COM_READ_BUFFER_SIZE = 1024;
COM_WRITE_BUFFER_SIZE = 1024;
READ_TIMEOUT = 50;
WRITE_TIMEOUT = 100;
port = "\\.\COM6"
portFormat = "9600,N,8,1" /* for information on this, google the MODE command for windows. */
HANDLE hComPort;
DCB dcbComConfig;
OPENING COM PORT
DWORD dwStoredFlags = EV_BREAK | EV_ERR | EV_RXCHAR;
COMMTIMEOUTS timeouts;
FillMemory(&dcbComConfig, sizeof(dcbComConfig), 0);
dcbComConfig.DCBlength = sizeof(dcbComConfig);
/* assign a COM format to the COM Port. */
if(!BuildCommDCB(portFormat, &dcbComConfig))
{
printf("Failed to build comm format data %s\n", portFormat);
}
/* Open the COM port with overlapped IO. */
hComPort = CreateFile(port, GENERIC_READ | GENERIC_WRITE, 0, 0,
OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
if (hComPort == INVALID_HANDLE_VALUE)
{
printf("Error opening port %s\n", port);
}
/* Set the COM Ports internal Read and Write buffer sizes. */
if(!SetupComm(hComPort, COM_READ_BUFFER_SIZE, COM_WRITE_BUFFER_SIZE))
{
printf("Could not set COM buffers\n");
}
/* assign the previously created COM Format to the COM Port. */
if(!SetCommState(hComPort, &dcbComConfig))
{
printf("Error setting com to format data.\n");
}
/* Mask what events you want to look for in the COM Port. */
if (!SetCommMask(hComPort, dwStoredFlags))
{
printf("Error setting communications mask\n");
}
/*-- Read Timeouts set like this so we can use the event based reading. --*/
timeouts.ReadIntervalTimeout = MAXDWORD;
timeouts.ReadTotalTimeoutMultiplier = 0;
timeouts.ReadTotalTimeoutConstant = 0;
timeouts.WriteTotalTimeoutMultiplier = 10;
timeouts.WriteTotalTimeoutConstant = 100;
if (!SetCommTimeouts(hComPort, &timeouts))
{
printf("Error setting time-outs.\n");
}
READING COM PORT
DWORD dwRead = 0;
DWORD dwComEvent = EV_RXCHAR;
DWORD lpErrors = 0;
char readBuffer[READ_BUFFER_SIZE];
/* Create the Overlapped IO Read Event. */
OVERLAPPED osRead = {0};
osRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
/* Used to monitor the COM Port State. */
COMSTAT ComStatus;
/* Loop at 20Hz to read the COM Port until a Kill event has been set. */
while(WaitForSingleObject(hKillEvent, 50) == WAIT_TIMEOUT)
{
/* Wait for a COM Event to occur ( Read Event in this Case ). */
if (WaitCommEvent(hComPort, &dwComEvent , NULL))
{
/* If the COM Port had an error Clear it. */
ClearCommError(hComPort, &lpErrors, &ComStatus);
/*-- Reset read operation's OVERLAPPED structure's hEvent --*/
ResetEvent(osRead.hEvent);
if (ReadFile(hComPort, readBuffer, ComStatus.cbInQue, &dwRead, &osRead))
{
/*-- bytes have been read; process it --*/
USE_DATA(readBuffer, dwRead);
}
else
{
/*-- An error occurred in the ReadFile call --*/
printf("ReadFile encountered an error.\n");
break;
}
}
else
{
/*-- Error in WaitCommEvent --*/
printf("WaitCommEvent encountered an error.\n");
break;
}
}
/* Close the Overlapped IO Read Event. */
CloseHandle(osRead.hEvent);
The top answer is correct. In this case, opening with FILE_FLAG_OVERLAPPED, ReadFile expects an OVERLAPPED structure as last argument.
Would like to add that you can also get 'parameter is incorrect' error if you do supply an OVERLAPPED struct, but forget to ZeroMemory it.
From the documentation:
Any unused members of this structure should always be initialized to zero before the structure is used in a function call. Otherwise, the function may fail and return ERROR_INVALID_PARAMETER.
So don't forget to:
OVERLAPPED ovl;
ZeroMemory(&ovl, sizeof(ovl));
...
ReadFile(hSerial, szBuff, n, &dwBytesRead, &ovl);

GetCommState always false

I was trying to make a simple console program that reads all signals from my mouse plugged in with USB. I faced a problem: GetCommState(nCom, &dcb) always returns zero, which is not very usefull for my task.
Here is the code:
int _tmain(int argc, TCHAR *argv[]) {
DCB dcb;
HANDLE hCom;
BOOL fSuccess;
TCHAR *pcCommPort = TEXT("\\\\.\\HCD0"); // USB name
// 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());
Sleep(15000);
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 %s.\n", GetLastError());
printf("Cannot get first time");
Sleep(12000);
return (2);
}
.......
GetLastError() returns 1, but lurking for this problem gave me no results.
Thats simply a copypaste from msdn example, but it occurs that it didn't work for me.
Tell me please: what should i change to make it return nonzero and let me proceed with another part of task.
USB mice have nothing to do with COM ports, thus calling GetCommState makes no sense at all.
A serial mouse is ancient hardware that is outdated since about 1995. Modern USB mice are based on USB HID protocol.

error opening port

My problem is that I have try and check with different port_name like 7 or 14 or 25. It's not opening or process the serial data the handle simply matching with the if condition and it is closing the handle. Is there any problem with the code?
void command_handler::start()
{
char port_name[] = "COM7:"; /* Name of the serial port */
serial_port = CreateFile(port_name, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
/* Make sure port was opened */
if (serial_port == INVALID_HANDLE_VALUE)
{
fprintf(stderr, "Error opening port\n");
printf("I'm here");
CloseHandle(serial_port);
exit(0);
}
set_up_serial_port(serial_port, baud_rate);
process_serial_data = false;
}
Did you tried below naming:
char port_name[] = "\\\\.\\COM7";
The second issue maybe is difference of CHAR and WCHAR. I think you should send a WCHAR string to the API.

ReadFile() says it failed, but the error code is ERROR_SUCCESS

I'm using ReadFile() on Windows to read data from a serial port. This code was working fine at one point in time, but it's now failing and I'm trying to track down the source of the problem, so I doubt it's a problem with the serial configuration or timeouts, since none of that has changed.
ReadFile() returns false, indicating that an error occurred. However, when I immediately check the value of GetLastError(), it returns 0, which is ERROR_SUCCESS. The number of bytes read is 0, so I'm inclined to think that indeed something has gone wrong, but that error code is utterly useless.
Any ideas? Thanks.
EDIT: Here are some relevant code snippets:
#define GPS_COM_PORT L"COM3"
// for reference, the device communicates at 115200 baud,
// no parity, 1 stop bit, no flow control
// open gps com port
hGpsUart = CreateFile(GPS_COM_PORT, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (hGpsUart == INVALID_HANDLE_VALUE)
{
if (GetLastError() == ERROR_FILE_NOT_FOUND)
{
msg.setText("GPS COM port does not exist!");
msg.exec();
QApplication::quit();
}
msg.setText("Error occurred while trying to open GPS COM port!");
msg.exec();
QApplication::quit();
}
// set gps com port settings
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
if (!GetCommState(hGpsUart, &dcbSerialParams))
{
msg.setText("Could not get GPS COM port settings!");
msg.exec();
QApplication::quit();
}
dcbSerialParams.BaudRate = CBR_115200;
dcbSerialParams.ByteSize = 8;
dcbSerialParams.StopBits = ONESTOPBIT;
dcbSerialParams.Parity = NOPARITY;
if (!SetCommState(hGpsUart, &dcbSerialParams))
{
msg.setText("Could not set GPS COM port settings!");
msg.exec();
QApplication::quit();
}
// set gps com port timeouts
timeouts.ReadIntervalTimeout = MAXDWORD;
timeouts.ReadTotalTimeoutConstant = 0;
timeouts.ReadTotalTimeoutMultiplier = 0;
timeouts.WriteTotalTimeoutConstant = 50;
timeouts.WriteTotalTimeoutMultiplier = 10;
if (!SetCommTimeouts(hGpsUart, &timeouts))
{
msg.setText("Could not set GPS COM port timeouts!");
msg.exec();
QApplication::quit();
}
// ... later in the code ...
char buf[161] = {0};
DWORD bytes_read = 0;
// This returns false...
if (!ReadFile(hGpsUart, buf, 160, &bytes_read, NULL))
{
// Yet in here, GetLastError() returns ERROR_SUCCESS (0)
QMessageBox msg;
msg.setText("Error reading from GPS UART!");
msg.exec();
}
I think the key to your observations is the phrase in your source that says "Yet in here, GetLastError() returns ERROR_SUCCESS (0)"
The call to GetLastError has to be the very next Win32 call made after the (presumably) failing call. As an experiment, try putting an explicit call to GetLastError() within your failure handler, but just before the message box call. I suspect you'll see the true failure code.
Good luck!
The constructor of QMessageBox may be doing something that clears `GetLastError'. Try this:
if (!ReadFile(hGpsUart, buf, 160, &bytes_read, NULL))
{
int LastError = GetLastError() ;
QMessageBox msg;
msg.setText(QString("Error %1 reading from GPS UART!").arg(LastError));
msg.exec();
}