Hi stackoverflow users!
I need to poll the CTS line of my serial port in Windows environment,
I have opened successfully the COM port,
HANDLE hSerialIn;
const char* pcCommPort = TEXT("COM3");
hSerialIn = CreateFile(pcCommPort, GENERIC_READ | GENERIC_WRITE, \
0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
Then I want to have something like this
DCB dcb = { 0 };
while (GetCommState(hSerialIn, &dcb)) {
if (dcb.fOutxCtsFlow)
;
else
;
}
The background of my interest in COM port is that there, I have a USB->UART convertor which in connected to the trigger output of the measuring device, this device triggers the output each second, and I want to have it in my program. When I connect to the COM port via Hercules(Terminal app) it works, I see that my CTS line is changing each second. So how to check the state of the CTS line?
Thanks in advance.
DWORD dwModemStatus;
BOOL fCTS = 0;
if (!SetCommMask(hSerialIn, EV_CTS))
{
DWORD err = GetLastError();
printf("\nHandle creation error code: %x\n", err);
}
DWORD dwCommEvent;
while(1)
{
if (!WaitCommEvent(hSerialIn, &dwCommEvent, NULL)) // An error occurred waiting for the event.
printf("");
else
{
if (!GetCommModemStatus(hSerialIn, &dwModemStatus)) // Error in GetCommModemStatus;
return;
fCTS = MS_CTS_ON & dwModemStatus;
if(fCTS)
printf("%x ", fCTS);
}
}
Related
Can someone tell me what I am doing wrong in the following snippet?
The problem is that this snippet, which is supposed to print "Hello, World!" with colors works exactly as expected when ran in cmder with cmd.exe as the shell, but is is completly broken when used in the native cmd.exe terminal emulator or the native PowerShell emulator.
Specifically, the background color is changed, and the reset doesn't work.
#include <windows.h>
#include <io.h>
#include <conio.h>
#include <fileapi.h>
#include <assert.h>
#include <stdio.h>
typedef struct {
HANDLE h;
HANDLE hin;
WORD savedAttr;
} Terminal;
#define FOREGROUND_RGB (FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN)
#define BACKGROUND_RGB (BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_GREEN)
#define TRY_OS(expr) if ((expr) == 0) { osError(); }
#define TRY_OR(expr) if ((expr) == 0)
static WORD get_text_attributes(Terminal term)
{
CONSOLE_SCREEN_BUFFER_INFO c;
TRY_OR(GetConsoleScreenBufferInfo(term.h, &c)) {
return 0x70;
}
return c.wAttributes;
}
Terminal getHandle(FILE* in, FILE* out)
{
Terminal term;
if ((in == stdin) && (out == stdout)) {
// grab the current console even if stdin/stdout have been redirected
term.h =
CreateFile("CON", GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
0, 0);
term.hin =
CreateFile("CON", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0,
0);
// term.h = GetStdHandle(STD_OUTPUT_HANDLE);
// term.hin = GetStdHandle(STD_INPUT_HANDLE);
} else {
term.h = (HANDLE) _get_osfhandle(_fileno(out));
term.hin = (HANDLE) _get_osfhandle(_fileno(in));
}
term.savedAttr = get_text_attributes(term);
return term;
}
void setFG(Terminal term, int color)
{
WORD attr = get_text_attributes(term);
attr &= ~FOREGROUND_RGB; // clear FG color
attr &= ~FOREGROUND_INTENSITY; // clear FG intensity
attr |= color;
SetConsoleTextAttribute(term.h, attr);
}
void setBG(Terminal term, int color)
{
WORD attr = get_text_attributes(term);
attr &= ~BACKGROUND_RGB; // clear BG color
attr &= ~BACKGROUND_INTENSITY; // clear BG intensity
attr |= color;
SetConsoleTextAttribute(term.h, attr);
}
int main()
{
Terminal term = getHandle(stdin, stdout);
setFG(term, FOREGROUND_RED);
WriteConsole(term.h, "Hello, ", 7, NULL, NULL);
setFG(term, FOREGROUND_BLUE);
WriteConsole(term.h, "World !\r\n", 9, NULL, NULL);
// reset style
SetConsoleTextAttribute(term.h, term.savedAttr);
return 0;
}
I guess I am doing something wrong in my use of the API and cmder is looser about it, but I wrote this whole code by reading the official Microsoft doc, so I am a bit confused.
I suggest you could try to use Multi-Byte Character Set in stead of Unicode Character Set.
Or you could try to use wide-character literal, like:
term.h =
CreateFile(L"CON", GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
0, 0);
term.hin =
CreateFile(L"CON", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0,
.
WriteConsole(term.h, L"Hello, ", 8, NULL, NULL);
.
WriteConsole(term.h, L"World !\n\r", 9, NULL, NULL);
EDIT:
Results of running with cmd:
Results of running with visual studio:
I write driver .
Creates an Device Object (name = ICOCTL_1) when the service starts but getlastError function return not_foun_file(code 2)
enter image description here
void CUserAppDlg::OnBnClickedbtncreate(){
deviceHandle = CreateFile(L"\\\\.\\IOCTL_1", GENERIC_ALL, 0, 0, OPEN_EXISTING,
FILE_ATTRIBUTE_SYSTEM, 0);
DWORD data = GetLastError();
TCHAR s[100];
_stprintf_s(s, _T("%X"), data);
MessageBox(s);}
I`m having a problem communicating with the serial port of Windows.
I have a Windows Service written in C.
This service is ready to listen requests from an application to communicate with a Pinpad. Pretty Simple.
The problem comes when the Pinpad's Com is assigned, sometimes it is assigned COM4,COM5, COM9 (these coms are working properly), so when the Pinpad's comm gets the COM10 or later, I get an error, and I cannot communicate with the pinpad. It sends me an error, this error is already defined, but I cannot figure what is the problem, cause in the function CreateFileA. Everything works perfect, I mean, it returns a handle, but in the next function: GetCommState, I get the error.
int srlOpen(char * szCOM)
{
DCB dcbSrlParms;
COMMTIMEOUTS timeouts;
int inRetVal = P_SUCCESS;
memset(&dcbSrlParms, 0x00, sizeof(dcbSrlParms));
memset(&timeouts, 0x00, sizeof(timeouts));
if(inRetVal > P_ERROR)
{
hSerial = CreateFileA(szCOM, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,0);
//hSerial = CreateFileA("COM21", GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_ALWAYS,
// FILE_ATTRIBUTE_NORMAL,0);
if(hSerial == INVALID_HANDLE_VALUE)
{
if(GetLastError() == ERROR_FILE_NOT_FOUND)
{
inRetVal = ERR_PORT_NOT_FOUND;
}
}
}
if(inRetVal > P_ERROR)
{
dcbSrlParms.DCBlength = sizeof(dcbSrlParms);
if(!GetCommState(hSerial, &dcbSrlParms))
{
inRetVal = ERR_GET_PORT_CONFIG;
}
}
if(inRetVal > P_ERROR)
{
dcbSrlParms.BaudRate = CBR_19200;
dcbSrlParms.ByteSize = 8;
dcbSrlParms.Parity = NOPARITY;
dcbSrlParms.StopBits = ONESTOPBIT;
if(!SetCommState(hSerial, &dcbSrlParms))
{
inRetVal = ERR_SET_PORT_CONFIG;
}
}
if(inRetVal > P_ERROR)
{
timeouts.ReadIntervalTimeout = COMM_READ_INT_TMEOUT;
timeouts.ReadTotalTimeoutConstant = COMM_READ_TOTAL_TIMEOUT;
timeouts.ReadTotalTimeoutMultiplier = COMM_READ_TOTAL_MULTI;
timeouts.WriteTotalTimeoutConstant = COMM_WRITE_TOTAL_TIMEOUT;
timeouts.WriteTotalTimeoutMultiplier = COMM_WRITE_TOTAL_MULTI;
if(!SetCommTimeouts(hSerial, &timeouts))
{
inRetVal = ERR_SET_TIMEOUT_CONFIG;
}
}
pdebug (("inRetVal=%x", inRetVal));
return inRetVal;
}
Invalid com port name.
A com port past "COM9" needs a different string format.
See Specify Serial Ports Larger than COM9
srlOpen("COM9"); //OK
srlOpen("COM10"); //Not OK
srlOpen("\\\\.\\COM9"); //OK
srlOpen("\\\\.\\COM10"); //OK
I'm attempting to send serial messages over USB to an Arduino Uno, using raw WinAPI commands. When using baud rates less than 115200, it works perfectly fine. However, when I send at 115200 baud, two extra bytes are sent prefixing the data I sent, but ONLY for the first message after connecting to the Arduino. For example, if I connect to the Arduino and send two bytes, "Hi", the Arduino receives "ððHi". If I send "Hi" again, the Arduino receives "Hi" like it should. (The extra bytes are usually ð (0xF0), but not always.)
I know that my computer and the Arduino are capable of communicating at 115200 baud, because other programs such as avrdude and the Arduino IDE's serial monitor can do it fine.
I have tried clearing the RX and TX buffers on both sides and also messing the DCB settings, with no effect. Does anyone know what might be causing this?
Thanks!
Here is my code to reproduce the problem:
Computer side:
#include <Windows.h>
int main()
{
// Open device as non-overlapped
HANDLE device = CreateFile(L"COM6",
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
// Make sure the device is valid
if(device == INVALID_HANDLE_VALUE)
return 0;
DCB dcb;
if(!GetCommState(device, &dcb))
return 0;
dcb.fOutX = 0;
dcb.fInX = 0;
dcb.fDtrControl = DTR_CONTROL_DISABLE;
dcb.fRtsControl = RTS_CONTROL_DISABLE;
dcb.fNull = 0;
dcb.BaudRate = CBR_115200;
dcb.ByteSize = 8;
dcb.Parity = NOPARITY;
dcb.StopBits = ONESTOPBIT;
if(!SetCommState(device, &dcb))
return 0;
COMMTIMEOUTS Timeouts = { 0 };
Timeouts.ReadTotalTimeoutConstant = 1000;
Timeouts.WriteTotalTimeoutConstant = 1000;
if(!SetCommTimeouts(device, &Timeouts))
return 0;
char *buf = "abcdef";
DWORD written;
WriteFile(device, buf, 6, &written, NULL);
DWORD read;
char inbuf[100];
ReadFile(device, inbuf, 100, &read, NULL);
// When I get the result inbuf, it has 8 bytes: {0xF0, 0xF0, a, b, c, d, e, f}
// Doing a 2nd set of Write/ReadFile, with the same message, gives the correct response
return 0;
}
Arduino side:
void setup()
{
Serial.begin(115200);
}
void loop()
{
if(Serial.available())
Serial.write(Serial.read());
}
I'm using CreateFile to open an asynchronous file handle to a Bluetooth HID device on the system. The device will then start streaming data, and I use ReadFile to read data from the device. The problem is, that if the Bluetooth connection is dropped, ReadFile just keeps giving ERROR_IO_PENDING instead of reporting a failure.
I cannot rely on timeouts, because the device doesn't send any data if there is nothing to report. I do not want it to time out if the connection is still alive, but there is simply no data for a while.
Still, the Bluetooth manager (both the Windows one and the Toshiba one) do immediately notice that the connection was lost. So this information is somewhere inside the system; it's just not getting through to ReadFile.
I have available:
the file handle (HANDLE value) to the device,
the path that was used to open that handle (but I don't want to attempt to open it another time, creating a new connection...)
an OVERLAPPED struct used for asynchronous ReadFile.
I am not sure if this issue is Bluetooth-specific, HID-specific, or occurs with devices in general. Is there any way that I can either
get ReadFile to return an error when the connection was dropped, or
detect quickly upon a timeout from ReadFile whether the connection is still alive (it needs to be fast because ReadFile is called at least 100 times per second), or
solve this problem in another way I haven't thought of?
You are going to have to have some sort of polling to check. Unless there is a event you can attach (I'm not familiar with the driver), the simplest way is to poll your COM port by doing a ReadFile and check is dwBytesRead > 0 when you send a command. There should be some status command you can send or you can check if you can write to the port and copy those bytes written to dwBytesWrite using WriteFile, for instance, and check if that is equal to the length of bytes you are sending. For instance:
WriteFile(bcPort, cmd, len, &dwBytesWrite, NULL);
if (len == dwBytesWrite) {
// Good! Return true
} else
// Bad! Return false
}
This is how I do it in my application. Below may seem like a bunch of boilerplate code, but I think it will help you get to the root of your problem. I first open the Comm Port in the beginning.
I have an array of COM ports that I maintain and check to see if they are open before writing to a particular COM port. For instance, they are opened in the beginning.
int j;
DWORD dwBytesRead;
if (systemDetect == SYS_DEMO)
return;
if (port <= 0 || port >= MAX_PORT)
return;
if (hComm[port]) {
ShowPortMessage(true, 20, port, "Serial port already open:");
return;
}
wsprintf(buff, "COM%d", port);
hComm[port] = CreateFile(buff,
GENERIC_READ | GENERIC_WRITE,
0, //Set of bit flags that specifies how the object can be shared
0, //Security Attributes
OPEN_EXISTING,
0, //Specifies the file attributes and flags for the file
0); //access to a template file
if (hComm[port] != INVALID_HANDLE_VALUE) {
if (GetCommState(hComm[port], &dcbCommPort)) {
if(baudrate == 9600) {
dcbCommPort.BaudRate = CBR_9600;//current baud rate
} else {
if(baudrate == 115200) {
dcbCommPort.BaudRate = CBR_115200;
}
}
dcbCommPort.fBinary = 1; //binary mode, no EOF check
dcbCommPort.fParity = 0; //enable parity checking
dcbCommPort.fOutxCtsFlow = 0; //CTS output flow control
dcbCommPort.fOutxDsrFlow = 0; //DSR output flow control
// dcbCommPort.fDtrControl = 1; //DTR flow control type
dcbCommPort.fDtrControl = 0; //DTR flow control type
dcbCommPort.fDsrSensitivity = 0;//DSR sensitivity
dcbCommPort.fTXContinueOnXoff = 0; //XOFF continues Tx
dcbCommPort.fOutX = 0; //XON/XOFF out flow control
dcbCommPort.fInX = 0; //XON/XOFF in flow control
dcbCommPort.fErrorChar = 0; //enable error replacement
dcbCommPort.fNull = 0; //enable null stripping
//dcbCommPort.fRtsControl = 1; //RTS flow control
dcbCommPort.fRtsControl = 0; //RTS flow control
dcbCommPort.fAbortOnError = 0; //abort reads/writes on error
dcbCommPort.fDummy2 = 0; //reserved
dcbCommPort.XonLim = 2048; //transmit XON threshold
dcbCommPort.XoffLim = 512; //transmit XOFF threshold
dcbCommPort.ByteSize = 8; //number of bits/byte, 4-8
dcbCommPort.Parity = 0; //0-4=no,odd,even,mark,space
dcbCommPort.StopBits = 0; //0,1,2 = 1, 1.5, 2
dcbCommPort.XonChar = 0x11; //Tx and Rx XON character
dcbCommPort.XoffChar = 0x13; //Tx and Rx XOFF character
dcbCommPort.ErrorChar = 0; //error replacement character
dcbCommPort.EofChar = 0; //end of input character
dcbCommPort.EvtChar = 0; //received event character
if (!SetCommState(hComm[port], &dcbCommPort)) {
setBit(SystemState, SYSTEM_PORT_ERROR);
//ShowPortMessage(true, 21, port, "Cannot set serial port state information:");
if (!CloseHandle(hComm[port])) {
//ShowPortMessage(true, 22, port, "Cannot close serial port:");
}
hComm[port] = NULL;
return;
}
} else {
setBit(SystemState, SYSTEM_PORT_ERROR);
//ShowPortMessage(true, 29, port, "Cannot get serial port state information:");
if (!CloseHandle(hComm[port])) {
//ShowPortMessage(true, 22, port, "Cannot close serial port:");
}
hComm[port] = NULL;
return;
}
if (!SetupComm(hComm[port], 1024*4, 1024*2)) {
setBit(SystemState, SYSTEM_PORT_ERROR);
//ShowPortMessage(true, 23, port, "Cannot set serial port I/O buffer size:");
if (!CloseHandle(hComm[port])) {
//ShowPortMessage(true, 22, port, "Cannot close serial port:");
}
hComm[port] = NULL;
return;
}
if (GetCommTimeouts(hComm[port], &ctmoOld)) {
memmove(&ctmoNew, &ctmoOld, sizeof(ctmoNew));
//default setting
ctmoNew.ReadTotalTimeoutConstant = 100;
ctmoNew.ReadTotalTimeoutMultiplier = 0;
ctmoNew.WriteTotalTimeoutMultiplier = 0;
ctmoNew.WriteTotalTimeoutConstant = 0;
if (!SetCommTimeouts(hComm[port], &ctmoNew)) {
setBit(SystemState, SYSTEM_PORT_ERROR);
//ShowPortMessage(true, 24, port, "Cannot set serial port timeout information:");
if (!CloseHandle(hComm[port])) {
//ShowPortMessage(true, 22, port, "Cannot close serial port:");
}
hComm[port] = NULL;
return;
}
} else {
setBit(SystemState, SYSTEM_PORT_ERROR);
//ShowPortMessage(true, 25, port, "Cannot get serial port timeout information:");
if (!CloseHandle(hComm[port])) {
//ShowPortMessage(true, 22, port, "Cannot close serial port:");
}
hComm[port] = NULL;
return;
}
for (j = 0; j < 255; j++) {
if (!ReadFile(hComm[port], buff, sizeof(buff), &dwBytesRead, NULL)) {
setBit(SystemState, SYSTEM_PORT_ERROR);
//ShowPortMessage(true, 26, port, "Cannot read serial port:");
j = 999; //read error
break;
}
if (dwBytesRead == 0) //No data in COM buffer
break;
Sleep(10); //Have to sleep certain time to let hardware flush buffer
}
if (j != 999) {
setBit(pcState[port], PORT_OPEN);
}
} else {
setBit(SystemState, SYSTEM_PORT_ERROR);
//ShowPortMessage(true, 28, port, "Cannot open serial port:");
hComm[port] = NULL;
}
HANDLE TCommPorts::OpenCommPort(void) {
// OPEN THE COMM PORT.
if (hComm)
return NULL; // if already open, don't bother
if (systemDetect == SYS_DEMO)
return NULL;
hComm = CreateFile(port,
GENERIC_READ | GENERIC_WRITE,
0, //Set of bit flags that specifies how the object can be shared
0, //Security Attributes
OPEN_EXISTING,
0, //Specifies the file attributes and flags for the file
0);//access to a template file
// If CreateFile fails, throw an exception. CreateFile will fail if the
// port is already open, or if the com port does not exist.
// If the function fails, the return value is INVALID_HANDLE_VALUE.
// To get extended error information, call GetLastError.
if (hComm == INVALID_HANDLE_VALUE) {
// throw ECommError(ECommError::OPEN_ERROR);
return INVALID_HANDLE_VALUE;
}
// GET THE DCB PROPERTIES OF THE PORT WE JUST OPENED
if (GetCommState(hComm, &dcbCommPort)) {
// set the properties of the port we want to use
dcbCommPort.BaudRate = CBR_9600;// current baud rate
//dcbCommPort.BaudRate = CBR_115200;
dcbCommPort.fBinary = 1; // binary mode, no EOF check
dcbCommPort.fParity = 0; // enable parity checking
dcbCommPort.fOutxCtsFlow = 0; // CTS output flow control
dcbCommPort.fOutxDsrFlow = 0; // DSR output flow control
//dcbCommPort.fDtrControl = 1; // DTR flow control type
dcbCommPort.fDtrControl = 0; // DTR flow control type
dcbCommPort.fDsrSensitivity = 0;// DSR sensitivity
dcbCommPort.fTXContinueOnXoff = 0; // XOFF continues Tx
dcbCommPort.fOutX = 0; // XON/XOFF out flow control
dcbCommPort.fInX = 0; // XON/XOFF in flow control
dcbCommPort.fErrorChar = 0; // enable error replacement
dcbCommPort.fNull = 0; // enable null stripping
//dcbCommPort.fRtsControl = 1; // RTS flow control
dcbCommPort.fRtsControl = 0; // RTS flow control
dcbCommPort.fAbortOnError = 0; // abort reads/writes on error
dcbCommPort.fDummy2 = 0; // reserved
dcbCommPort.XonLim = 2048; // transmit XON threshold
dcbCommPort.XoffLim = 512; // transmit XOFF threshold
dcbCommPort.ByteSize = 8; // number of bits/byte, 4-8
dcbCommPort.Parity = 0; // 0-4=no,odd,even,mark,space
dcbCommPort.StopBits = 0; // 0,1,2 = 1, 1.5, 2
dcbCommPort.XonChar = 0x11; // Tx and Rx XON character
dcbCommPort.XoffChar = 0x13; // Tx and Rx XOFF character
dcbCommPort.ErrorChar = 0; // error replacement character
dcbCommPort.EofChar = 0; // end of input character
dcbCommPort.EvtChar = 0; // received event character
}
else
{
// something is way wrong, close the port and return
CloseHandle(hComm);
throw ECommError(ECommError::GETCOMMSTATE);
}
// SET BAUD RATE, PARITY, WORD SIZE, AND STOP BITS TO OUR SETTINGS.
// REMEMBERTHAT THE ARGUMENT FOR BuildCommDCB MUST BE A POINTER TO A STRING.
// ALSO NOTE THAT BuildCommDCB() DEFAULTS TO NO HANDSHAKING.
// wsprintf(portSetting, "%s,%c,%c,%c", baud, parity, databits, stopbits);
dcbCommPort.DCBlength = sizeof(DCB);
// BuildCommDCB(portSetting, &dcbCommPort);
if (!SetCommState(hComm, &dcbCommPort)) {
// something is way wrong, close the port and return
CloseHandle(hComm);
throw ECommError(ECommError::SETCOMMSTATE);
}
// set the intial size of the transmit and receive queues.
// I set the receive buffer to 32k, and the transmit buffer
// to 9k (a default).
if (!SetupComm(hComm, 1024*32, 1024*9))
{
// something is hay wire, close the port and return
CloseHandle(hComm);
throw ECommError(ECommError::SETUPCOMM);
}
// SET THE COMM TIMEOUTS.
if (GetCommTimeouts(hComm,&ctmoOld)) {
memmove(&ctmoNew, &ctmoOld, sizeof(ctmoNew));
//default settings
ctmoNew.ReadTotalTimeoutConstant = 100;
ctmoNew.ReadTotalTimeoutMultiplier = 0;
ctmoNew.WriteTotalTimeoutMultiplier = 0;
ctmoNew.WriteTotalTimeoutConstant = 0;
if (!SetCommTimeouts(hComm, &ctmoNew)) {
// something is way wrong, close the port and return
CloseHandle(hComm);
throw ECommError(ECommError::SETCOMMTIMEOUTS);
}
} else {
CloseHandle(hComm);
throw ECommError(ECommError::GETCOMMTIMEOUTS);
}
return hComm;
}