Products > Programming
Windows Com port control C++
(1/1)
TeddyPython:
I'm trying to write a terminal program in Visual Studio to allow me to communicate with a E3632A over a serial link. I've managed to send and receive data using Termite, but only when RS/CTS flow control is enabled.
The example code (from here https://aticleworld.com/serial-port-programming-using-win32-api/) I have used thusfar did not have any flow control, but I think I have managed to add the RTS/CTS handshaking with
--- Code: ---dcbSerialParams.fOutxCtsFlow = TRUE; // CTS used for output flow control
dcbSerialParams.fRtsControl = RTS_CONTROL_HANDSHAKE; // Enable RTS
--- End code ---
before SetCommState().
However, when I attempt to run my code, it fails to send any bytes, returning "Number of bytes written to the serial port = 0". Do I need to specifically control the RTS/CTS lines myself, using EscapeCommFunction() and GetCommModemStatus()? In another example (here http://www2.eng.cam.ac.uk/~dmh/ptiialab/3B2/handouts/LA-code/raw-code/ComPort.cpp) they have used the fRtsControl and fOutxCtsFlow, but have no needed to using EscapeCommFunction() and GetCommModemStatus()...
Why is the data not being sent?
My code is as follows:
--- Code: ---#include "stdafx.h"
#include <Windows.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
HANDLE hComm; // Handle to the Serial port
BOOL Status; // Status
DCB dcbSerialParams = { 0 }; // Initializing DCB structure
COMMTIMEOUTS timeouts = { 0 }; //Initializing timeouts structure
char SerialBuffer[64] = { 0 }; //Buffer to send and receive data
DWORD BytesWritten = 0; // No of bytes written to the port
DWORD dwEventMask; // Event mask to trigger
char ReadData; //temperory Character
DWORD NoBytesRead; // Bytes read by ReadFile()
unsigned char loop = 0;
wchar_t pszPortName[10] = { 0 }; //com port id
wchar_t PortNo[20] = { 0 }; //contain friendly name
//Enter the com port id
printf_s("Enter the Com Port: ");
wscanf_s(L"%s", pszPortName, (unsigned)_countof(pszPortName));
swprintf_s(PortNo, 20, L"%s", pszPortName);
//Open the serial com port
hComm = CreateFile(PortNo, //friendly name
GENERIC_READ | GENERIC_WRITE, // Read/Write Access
0, // No Sharing, ports cant be shared
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_s("\n Port can't be opened\n\n");
}
//Setting the Parameters for the SerialPort
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
Status = GetCommState(hComm, &dcbSerialParams); //retreives the current settings
if (Status == FALSE)
{
printf_s("\nError to Get the Com state\n\n");
}
dcbSerialParams.BaudRate = CBR_9600; //BaudRate = 9600
dcbSerialParams.ByteSize = 8; //ByteSize = 8
dcbSerialParams.StopBits = TWOSTOPBITS; //StopBits = 1
dcbSerialParams.Parity = NOPARITY; //Parity = None
// Enable RTS/CTS handshaking
dcbSerialParams.fOutxCtsFlow = TRUE; // CTS used for output flow control
dcbSerialParams.fRtsControl = RTS_CONTROL_HANDSHAKE; // Enable RTS
// Disable DTR/DSR handshaking
dcbSerialParams.fOutxDsrFlow = FALSE; // DSR not used for output flow control
dcbSerialParams.fDsrSensitivity = FALSE; // Ignore DSR
dcbSerialParams.fDtrControl = DTR_CONTROL_ENABLE; // Turn on DTR upon device open
// Disable XON/XOFF handshaking
dcbSerialParams.fOutX = FALSE; // No outbound XON/XOFF flow control
dcbSerialParams.fInX = FALSE; // No inbound XON/XOFF flow control
// Error handling
dcbSerialParams.fErrorChar = FALSE; // No replacement of bytes with parity error
dcbSerialParams.fNull = FALSE; // Don't discard NULL bytes
dcbSerialParams.fAbortOnError = FALSE;
Status = SetCommState(hComm, &dcbSerialParams);
if (Status == FALSE)
{
printf_s("\nError to Setting DCB Structure\n\n");
}
//Setting Timeouts
timeouts.ReadIntervalTimeout = 50;
timeouts.ReadTotalTimeoutConstant = 50;
timeouts.ReadTotalTimeoutMultiplier = 10;
timeouts.WriteTotalTimeoutConstant = 50;
timeouts.WriteTotalTimeoutMultiplier = 10;
if (SetCommTimeouts(hComm, &timeouts) == FALSE)
{
printf_s("\nError to Setting Time outs");
}
printf_s("\n\nEnter your message: ");
scanf_s("%s", SerialBuffer, (unsigned)_countof(SerialBuffer));
//Writing data to Serial Port
EscapeCommFunction(hComm, SETRTS);
GetCommModemStatus(hComm, MS_CTS_ON);
Status = WriteFile(hComm,// Handle to the Serialport
SerialBuffer, // Data to be written to the port
sizeof(SerialBuffer), // No of bytes to write into the port
&BytesWritten, // No of bytes written to the port
NULL);
if (Status == FALSE)
{
printf_s("\nFail to Written");
}
//print numbers of byte written to the serial port
printf_s("\nNumber of bytes written to the serial port = %d\n\n", BytesWritten);
//Setting Receive Mask
Status = SetCommMask(hComm, EV_RXCHAR);
if (Status == FALSE)
{
printf_s("\nError to in Setting CommMask\n\n");
}
//Setting WaitComm() Event
Status = WaitCommEvent(hComm, &dwEventMask, NULL); //Wait for the character to be received
if (Status == FALSE)
{
printf_s("\nError! in Setting WaitCommEvent()\n\n");
}
//Read data and store in a buffer
do
{
Status = ReadFile(hComm, &ReadData, sizeof(ReadData), &NoBytesRead, NULL);
SerialBuffer[loop] = ReadData;
++loop;
} while (NoBytesRead > 0);
--loop; //Get Actual length of received data
printf_s("\nNumber of bytes received = %d\n\n", loop);
//print receive data on console
printf_s("\n\n");
int index = 0;
for (index = 0; index < loop; ++index)
{
printf_s("%c", SerialBuffer[index]);
}
printf_s("\n\n");
CloseHandle(hComm);//Closing the Serial Port
printf_s("Port Closed.\n\n");
return 0;
}
--- End code ---
MarkF:
I have not studied your code very close.
Here is some code I wrote as another example (It is for both Windows and Linux):
I HAVE CHANGED ALL '#' CHARACTERS TO '##' BECAUSE THE FORUM CODE TAG IS REMOVING #endif STATEMENTS!
Header:
--- Code: ---##ifndef __SERIALPORT_H
##define __SERIALPORT_H
##include <stdio.h>
##include <stdlib.h>
##ifdef WIN32
##include <winsock2.h>
##include <commctrl.h>
##else
##include <unistd.h>
##include <sys/types.h>
##include <sys/stat.h>
##include <sys/socket.h>
##include <netinet/in.h>
##include <arpa/inet.h>
##include <fcntl.h>
##include <termio.h>
##include <strings.h>
##endif
##define ASCII_XON 0x11
##define ASCII_XOFF 0x13
class serialPort
{
public:
// BAUD RATE
// 0="110", 1="300", 2="1200", 3="2400", 4="4800", 5="9600", 6="14400", 7="19200", 8="57600", 9="115200"
int baudRateIdx;
// DATA BITS
// 0="4", 1="5", 2="6", 3="7", 4="8"
int dataBitsIdx;
// PARITY
// 0="None", 1="Odd", 2="Even", 3="Mark", 4="Space"
int parityIdx;
// STOP BITS
// 0="1", 1="1.5", 2="2"
int stopBitsIdx;
// FLOW CONTROL
// 0="None", 1="Xon/Xoff", 2="Rts/Cts", 3="Dtr/Dsr"
int flowControlIdx;
serialPort();
virtual ~serialPort();
int OpenCommConnection( char *port );
int CloseCommConnection( void );
int WriteCommBlock( char *lpByte , int dwBytesToWrite );
int ReadCommBlock( char *lpszBlock, int nMaxLength );
private:
int td;
int serialConnected;
##ifdef WIN32
HANDLE idComDev;
OVERLAPPED osWrite;
OVERLAPPED osRead;
##endif
int SetupCommConnection( void );
};
##endif
--- End code ---
Code:
--- Code: ---##include "serialPort.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
serialPort::serialPort()
{
baudRateIdx = 5;
dataBitsIdx = 4;
parityIdx = 0;
stopBitsIdx = 0;
flowControlIdx = 0;
td = -1;
serialConnected = 0;
}
serialPort::~serialPort()
{
}
//----------------------------------------------------------------------
int serialPort::OpenCommConnection( char *port )
{
##ifdef WIN32
int fRetVal;
// create I/O event used for overlapped reads / writes
osRead.Offset = 0;
osRead.OffsetHigh = 0;
osRead.hEvent = CreateEvent( NULL, 1, 0, NULL );
osWrite.Offset = 0;
osWrite.OffsetHigh = 0;
osWrite.hEvent = CreateEvent( NULL, 1, 0, NULL );
// open COMM device
idComDev = CreateFile( port,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH | FILE_FLAG_OVERLAPPED,
NULL );
if ( idComDev == (HANDLE) -1 ) {
return 0;
}
else {
// get any early notifications
SetCommMask( idComDev, EV_RXCHAR );
// setup device buffers
SetupComm( idComDev, 4096, 4096 );
// purge any information in the buffer
PurgeComm( idComDev, PURGE_TXABORT | PURGE_RXABORT |
PURGE_TXCLEAR | PURGE_RXCLEAR );
}
fRetVal = SetupCommConnection();
if (fRetVal) {
// assert DTR
EscapeCommFunction( idComDev, SETDTR );
// set connected flag to 1
serialConnected = 1;
}
else {
CloseHandle( idComDev );
}
return ( fRetVal );
##else
// Open Serial Port
if ( (td = open(port,O_RDWR)) == -1) {
printf("ERROR - Unable to open serial port: %s\n", port);
exit(0);
}
SetupCommConnection();
// Clear input and output queues
tcflush(td,TCIOFLUSH);
return (1);
##endif
}
//----------------------------------------------------------------------
int serialPort::SetupCommConnection( void )
{
##ifdef WIN32
int fRetVal;
DCB dcb;
COMMTIMEOUTS CommTimeOuts;
DWORD baudRateTable[] = {
CBR_110, CBR_300, CBR_1200, CBR_2400, CBR_4800, CBR_9600,
CBR_14400, CBR_19200, CBR_57600, CBR_115200
};
// set up for overlapped I/O
CommTimeOuts.ReadIntervalTimeout = 0xFFFFFFFF;
CommTimeOuts.ReadTotalTimeoutMultiplier = 0;
CommTimeOuts.ReadTotalTimeoutConstant = 1000;
// CBR_9600 is approximately 1byte/ms. For our purposes, allow
// double the expected time per character for a fudge factor.
CommTimeOuts.WriteTotalTimeoutMultiplier = 10*CBR_9600/baudRateTable[ baudRateIdx ];
CommTimeOuts.WriteTotalTimeoutConstant = 0;
SetCommTimeouts( idComDev, &CommTimeOuts );
dcb.DCBlength = sizeof( DCB );
GetCommState( idComDev, &dcb );
dcb.BaudRate = baudRateTable[ baudRateIdx ];
dcb.ByteSize = dataBitsIdx + 4;
dcb.Parity = parityIdx;
dcb.StopBits = stopBitsIdx;
// setup flow control
switch ( flowControlIdx ) {
case 1: // Xon/Xoff control
dcb.fInX = dcb.fOutX = 1;
dcb.XonChar = ASCII_XON;
dcb.XoffChar = ASCII_XOFF;
dcb.XonLim = 200;
dcb.XoffLim = 200;
dcb.fRtsControl = RTS_CONTROL_ENABLE;
dcb.fDtrControl = DTR_CONTROL_ENABLE;
break;
case 2: // Rts/Cts control
dcb.fInX = dcb.fOutX = 0;
dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
dcb.fDtrControl = DTR_CONTROL_ENABLE;
break;
case 3: // Dtr/Dsr control
dcb.fInX = dcb.fOutX = 0;
dcb.fRtsControl = RTS_CONTROL_ENABLE;
dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
break;
default: // None
dcb.fInX = dcb.fOutX = 0;
dcb.fRtsControl = RTS_CONTROL_ENABLE;
dcb.fDtrControl = DTR_CONTROL_ENABLE;
break;
}
// other various settings
dcb.fNull = 0;
dcb.fBinary = 1;
dcb.fParity = 1;
fRetVal = SetCommState( idComDev, &dcb );
return ( fRetVal );
##else
struct termios t;
unsigned int baudRateTable[] = {
B110, B300, B1200, B2400, B4800, B9600, 0, B19200, B57600, B115200
};
unsigned int charSizeTable[] = {
0, CS5, CS6, CS7, CS8
};
// Setup Terminal Parameters
tcgetattr(td,&t);
t.c_iflag = 0; // input modes
t.c_oflag = 0; // output modes
t.c_lflag = 0; // local modes
t.c_cc[VMIN] = 0;
t.c_cc[VTIME] = 0;
t.c_cflag = CREAD; // control modes
t.c_cflag |= baudRateTable[ baudRateIdx ];
if (parityIdx == 1)
t.c_cflag |= PARENB | PARODD;
else if (parityIdx == 2)
t.c_cflag |= PARENB;
t.c_cflag |= charSizeTable[ dataBitsIdx ];
if (stopBitsIdx == 2)
t.c_cflag |= CSTOPB;
if (flowControlIdx < 2) t.c_cflag |= CLOCAL;
cfsetispeed(&t, baudRateTable[baudRateIdx]);
cfsetospeed(&t, baudRateTable[baudRateIdx]);
tcsetattr(td,0,&t);
return 1;
##endif
}
//----------------------------------------------------------------------
int serialPort::CloseCommConnection( void )
{
##ifdef WIN32
// set connected flag to 0
serialConnected = 0;
// disable event notification and wait for thread to halt
SetCommMask( idComDev, 0 );
// drop DTR
EscapeCommFunction( idComDev, CLRDTR );
// purge any outstanding reads/writes and close device handle
PurgeComm( idComDev, PURGE_TXABORT | PURGE_RXABORT |
PURGE_TXCLEAR | PURGE_RXCLEAR );
CloseHandle( idComDev );
CloseHandle( osRead.hEvent );
CloseHandle( osWrite.hEvent );
return 1;
##else
if (td != -1) {
close(td);
}
return 1;
##endif
}
//----------------------------------------------------------------------
int serialPort::WriteCommBlock( char *lpByte , int dwBytesToWrite )
{
##ifdef WIN32
int fWriteStat;
DWORD dwBytesWritten;
DWORD dwErrorFlags;
DWORD dwError;
DWORD dwBytesSent=0;
COMSTAT ComStat;
if ( !serialConnected ) return 0;
fWriteStat = WriteFile( idComDev,
(LPSTR)lpByte,
dwBytesToWrite,
&dwBytesWritten,
&osWrite );
// Note that normally the code will not execute the following
// because the driver caches write operations. Small I/O requests
// (up to several thousand bytes) will normally be accepted
// immediately and WriteFile will return 1 even though an
// overlapped operation was specified
if ( !fWriteStat ) {
if ( GetLastError() == ERROR_IO_PENDING ) {
// We should wait for the completion of the write operation
// so we know if it worked or not
// This is only one way to do this. It might be beneficial
// to place the write operation in a separate thread
// so that blocking on completion will not negatively
// affect the responsiveness of the UI
// If the write takes too long to complete, this
// function will timeout according to the
// CommTimeOuts.WriteTotalTimeoutMultiplier variable.
// This code logs the timeout but does not retry
// the write.
while ( !GetOverlappedResult( idComDev, &osWrite, &dwBytesWritten, 1 ) )
{
dwError = GetLastError();
if ( dwError == ERROR_IO_INCOMPLETE ) {
// normal result if not finished
dwBytesSent += dwBytesWritten;
continue;
}
else {
// an error occurred, try to recover
ClearCommError( idComDev, &dwErrorFlags, &ComStat );
break;
}
}
dwBytesSent += dwBytesWritten;
}
else {
// some other error occurred
ClearCommError( idComDev, &dwErrorFlags, &ComStat );
return 0;
}
}
return 1;
##else
int n;
n = write(td, lpByte, dwBytesToWrite);
if (n != dwBytesToWrite) return 0;
return 1;
##endif
}
//----------------------------------------------------------------------
int serialPort::ReadCommBlock( char *lpszBlock, int nMaxLength )
{
##ifdef WIN32
int fReadStat;
COMSTAT ComStat;
DWORD dwErrorFlags;
DWORD dwLength;
DWORD dwError;
if ( !serialConnected ) return 0;
// only try to read number of bytes in queue
ClearCommError( idComDev, &dwErrorFlags, &ComStat );
dwLength = min( (DWORD) nMaxLength, ComStat.cbInQue );
if (dwLength > 0) {
fReadStat = ReadFile( idComDev,
(LPSTR)lpszBlock,
dwLength,
&dwLength,
&osRead );
if ( !fReadStat ) {
if ( GetLastError() == ERROR_IO_PENDING ) {
// We have to wait for read to complete.
// This function will timeout according to the
// CommTimeOuts.ReadTotalTimeoutConstant variable
// Every time it times out, check for port errors
while ( !GetOverlappedResult( idComDev, &osRead, &dwLength, 1 ) )
{
dwError = GetLastError();
if (dwError == ERROR_IO_INCOMPLETE) {
// normal result if not finished
continue;
}
else {
// an error occurred, try to recover
ClearCommError( idComDev, &dwErrorFlags, &ComStat );
break;
}
}
}
else {
// some other error occurred
dwLength = 0;
ClearCommError( idComDev, &dwErrorFlags, &ComStat );
}
}
}
return ( dwLength );
##else
int dwLength;
dwLength = read( td, lpszBlock, nMaxLength );
return ( dwLength );
##endif
}
//----------------------------------------------------------------------
--- End code ---
Navigation
[0] Message Index
Go to full version