Windows Com port control C++ - Page 1
Forum section: electronics / general

author: TeddyPython
author_rank: Contributor
timestamp: September 26, 2019, 04:31:29 pm
content: 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 herehttps://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 withCode:dcbSerialParams.fOutxCtsFlow = TRUE; // CTS used for output flow controldcbSerialParams.fRtsControl = RTS_CONTROL_HANDSHAKE; // Enable RTSbefore 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 (herehttp://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 portBOOL Status; // StatusDCB dcbSerialParams = { 0 }; // Initializing DCB structureCOMMTIMEOUTS timeouts = { 0 }; //Initializing timeouts structurechar SerialBuffer = { 0 }; //Buffer to send and receive dataDWORD BytesWritten = 0; // No of bytes written to the portDWORD dwEventMask; // Event mask to triggerchar ReadData; //temperory CharacterDWORD NoBytesRead; // Bytes read by ReadFile()unsigned char loop = 0;wchar_t pszPortName = { 0 }; //com port idwchar_t PortNo = { 0 }; //contain friendly name//Enter the com port idprintf_s("Enter the Com Port: ");wscanf_s(L"%s", pszPortName, (unsigned)_countof(pszPortName));swprintf_s(PortNo, 20, L"%s", pszPortName);//Open the serial com porthComm = CreateFile(PortNo, //friendly nameGENERIC_READ | GENERIC_WRITE, // Read/Write Access0, // No Sharing, ports cant be sharedNULL, // No SecurityOPEN_EXISTING, // Open existing port only0, // Non Overlapped I/ONULL); // Null for Comm Devicesif (hComm == INVALID_HANDLE_VALUE){printf_s("\n Port can't be opened\n\n");}//Setting the Parameters for the SerialPortdcbSerialParams.DCBlength = sizeof(dcbSerialParams);Status = GetCommState(hComm, &dcbSerialParams); //retreives the current settingsif (Status == FALSE){printf_s("\nError to Get the Com state\n\n");}dcbSerialParams.BaudRate = CBR_9600; //BaudRate = 9600dcbSerialParams.ByteSize = 8; //ByteSize = 8dcbSerialParams.StopBits = TWOSTOPBITS; //StopBits = 1dcbSerialParams.Parity = NOPARITY; //Parity = None// Enable RTS/CTS handshakingdcbSerialParams.fOutxCtsFlow = TRUE; // CTS used for output flow controldcbSerialParams.fRtsControl = RTS_CONTROL_HANDSHAKE; // Enable RTS// Disable DTR/DSR handshakingdcbSerialParams.fOutxDsrFlow = FALSE; // DSR not used for output flow controldcbSerialParams.fDsrSensitivity = FALSE; // Ignore DSRdcbSerialParams.fDtrControl = DTR_CONTROL_ENABLE; // Turn on DTR upon device open// Disable XON/XOFF handshakingdcbSerialParams.fOutX = FALSE; // No outbound XON/XOFF flow controldcbSerialParams.fInX = FALSE; // No inbound XON/XOFF flow control// Error handlingdcbSerialParams.fErrorChar = FALSE; // No replacement of bytes with parity errordcbSerialParams.fNull = FALSE; // Don't discard NULL bytesdcbSerialParams.fAbortOnError = FALSE;Status = SetCommState(hComm, &dcbSerialParams);if (Status == FALSE){printf_s("\nError to Setting DCB Structure\n\n");}//Setting Timeoutstimeouts.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 PortEscapeCommFunction(hComm, SETRTS);GetCommModemStatus(hComm, MS_CTS_ON);Status = WriteFile(hComm,// Handle to the SerialportSerialBuffer, // Data to be written to the portsizeof(SerialBuffer), // No of bytes to write into the port&BytesWritten, // No of bytes written to the portNULL);if (Status == FALSE){printf_s("\nFail to Written");}//print numbers of byte written to the serial portprintf_s("\nNumber of bytes written to the serial port = %d\n\n", BytesWritten);//Setting Receive MaskStatus = SetCommMask(hComm, EV_RXCHAR);if (Status == FALSE){printf_s("\nError to in Setting CommMask\n\n");}//Setting WaitComm() EventStatus = WaitCommEvent(hComm, &dwEventMask, NULL); //Wait for the character to be receivedif (Status == FALSE){printf_s("\nError! in Setting WaitCommEvent()\n\n");}//Read data and store in a bufferdo{Status = ReadFile(hComm, &ReadData, sizeof(ReadData), &NoBytesRead, NULL);SerialBuffer = ReadData;++loop;} while (NoBytesRead > 0);--loop; //Get Actual length of received dataprintf_s("\nNumber of bytes received = %d\n\n", loop);//print receive data on consoleprintf_s("\n\n");int index = 0;for (index = 0; index < loop; ++index){printf_s("%c", SerialBuffer);}printf_s("\n\n");CloseHandle(hComm);//Closing the Serial Portprintf_s("Port Closed.\n\n");return 0;}

author: MarkF
author_rank: Super Contributor
timestamp: September 26, 2019, 11:36:40 pm
content: 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 0x13class 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 WIN32HANDLE idComDev;OVERLAPPED osWrite;OVERLAPPED osRead;##endifint SetupCommConnection( void );};##endifCode: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 WIN32int fRetVal;// create I/O event used for overlapped reads / writesosRead.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 deviceidComDev = 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 notificationsSetCommMask( idComDev, EV_RXCHAR );// setup device buffersSetupComm( idComDev, 4096, 4096 );// purge any information in the bufferPurgeComm( idComDev, PURGE_TXABORT | PURGE_RXABORT |PURGE_TXCLEAR | PURGE_RXCLEAR );}fRetVal = SetupCommConnection();if (fRetVal) {// assert DTREscapeCommFunction( idComDev, SETDTR );// set connected flag to 1serialConnected = 1;}else {CloseHandle( idComDev );}return ( fRetVal );##else// Open Serial Portif ( (td = open(port,O_RDWR)) == -1) {printf("ERROR - Unable to open serial port: %s\n", port);exit(0);}SetupCommConnection();// Clear input and output queuestcflush(td,TCIOFLUSH);return (1);##endif}//----------------------------------------------------------------------int serialPort::SetupCommConnection( void ){##ifdef WIN32int 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/OCommTimeOuts.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 controlswitch ( flowControlIdx ) {case 1: // Xon/Xoff controldcb.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 controldcb.fInX = dcb.fOutX = 0;dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;dcb.fDtrControl = DTR_CONTROL_ENABLE;break;case 3: // Dtr/Dsr controldcb.fInX = dcb.fOutX = 0;dcb.fRtsControl = RTS_CONTROL_ENABLE;dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;break;default: // Nonedcb.fInX = dcb.fOutX = 0;dcb.fRtsControl = RTS_CONTROL_ENABLE;dcb.fDtrControl = DTR_CONTROL_ENABLE;break;}// other various settingsdcb.fNull = 0;dcb.fBinary = 1;dcb.fParity = 1;fRetVal = SetCommState( idComDev, &dcb );return ( fRetVal );##elsestruct 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 Parameterstcgetattr(td,&t);t.c_iflag = 0; // input modest.c_oflag = 0; // output modest.c_lflag = 0; // local modest.c_cc = 0;t.c_cc = 0;t.c_cflag = CREAD; // control modest.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);cfsetospeed(&t, baudRateTable);tcsetattr(td,0,&t);return 1;##endif}//----------------------------------------------------------------------int serialPort::CloseCommConnection( void ){##ifdef WIN32// set connected flag to 0serialConnected = 0;// disable event notification and wait for thread to haltSetCommMask( idComDev, 0 );// drop DTREscapeCommFunction( idComDev, CLRDTR );// purge any outstanding reads/writes and close device handlePurgeComm( idComDev, PURGE_TXABORT | PURGE_RXABORT |PURGE_TXCLEAR | PURGE_RXCLEAR );CloseHandle( idComDev );CloseHandle( osRead.hEvent );CloseHandle( osWrite.hEvent );return 1;##elseif (td != -1) {close(td);}return 1;##endif}//----------------------------------------------------------------------int serialPort::WriteCommBlock( char *lpByte , int dwBytesToWrite ){##ifdef WIN32int 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 specifiedif ( !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 finisheddwBytesSent += dwBytesWritten;continue;}else {// an error occurred, try to recoverClearCommError( idComDev, &dwErrorFlags, &ComStat );break;}}dwBytesSent += dwBytesWritten;}else {// some other error occurredClearCommError( idComDev, &dwErrorFlags, &ComStat );return 0;}}return 1;##elseint n;n = write(td, lpByte, dwBytesToWrite);if (n != dwBytesToWrite) return 0;return 1;##endif}//----------------------------------------------------------------------int serialPort::ReadCommBlock( char *lpszBlock, int nMaxLength ){##ifdef WIN32int fReadStat;COMSTAT ComStat;DWORD dwErrorFlags;DWORD dwLength;DWORD dwError;if ( !serialConnected ) return 0;// only try to read number of bytes in queueClearCommError( 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 errorswhile ( !GetOverlappedResult( idComDev, &osRead, &dwLength, 1 ) ){dwError = GetLastError();if (dwError == ERROR_IO_INCOMPLETE) {// normal result if not finishedcontinue;}else {// an error occurred, try to recoverClearCommError( idComDev, &dwErrorFlags, &ComStat );break;}}}else {// some other error occurreddwLength = 0;ClearCommError( idComDev, &dwErrorFlags, &ComStat );}}}return ( dwLength );##elseint dwLength;dwLength = read( td, lpszBlock, nMaxLength );return ( dwLength );##endif}//----------------------------------------------------------------------