1
//-----------------------------------------------------------------------------
5
// copyright Dave Freese 2006, w1hkj@w1hkj.com
7
//-----------------------------------------------------------------------------
14
LOG_FILE_SOURCE(debug::LOG_RIGCONTROL);
20
#include <sys/types.h>
23
#include <sys/ioctl.h>
31
device = "/dev/ttyS0";
36
rtsptt = dtrptt = false;
49
///////////////////////////////////////////////////////
50
// Function name : Cserial::OpenPort
51
// Description : Opens the port specified by strPortName
53
// Argument : c_string strPortName
54
///////////////////////////////////////////////////////
55
bool Cserial::CheckPort(string dev) {
56
int testfd = open( dev.c_str(), O_RDWR | O_NOCTTY | O_NDELAY);
63
///////////////////////////////////////////////////////
64
// Function name : Cserial::OpenPort
65
// Description : Opens the port specified by strPortName
67
// Argument : c_string strPortName
68
///////////////////////////////////////////////////////
69
bool Cserial::OpenPort() {
71
if ((fd = open( device.c_str(), O_RDWR | O_NOCTTY | O_NDELAY )) < 0)
73
// save current port settings
74
tcflush (fd, TCIFLUSH);
76
tcgetattr (fd, &oldtio);
80
newtio.c_cflag &= ~CSIZE;
81
newtio.c_cflag |= CS8;
82
// enable receiver, set local mode
83
newtio.c_cflag |= (CLOCAL | CREAD);
85
newtio.c_cflag &= ~PARENB;
89
newtio.c_cflag &= ~CSTOPB;
92
newtio.c_cflag |= CSTOPB;
96
newtio.c_cflag |= CRTSCTS;
99
newtio.c_cflag &= ~CRTSCTS;
102
newtio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
104
newtio.c_oflag &= ~OPOST;
105
// software flow control disabled
106
newtio.c_iflag &= ~IXON;
107
// do not translate CR to NL
108
newtio.c_iflag &= ~ICRNL;
141
cfsetispeed(&newtio, speed);
142
cfsetospeed(&newtio, speed);
144
tcsetattr (fd, TCSANOW, &newtio);
146
ioctl(fd, TIOCMGET, &status);
150
status |= TIOCM_DTR; // set the DTR bit
152
status &= ~TIOCM_DTR; // clear the DTR bit
154
if (rtscts == false) { // rts OK for ptt if RTSCTS not used
156
status |= TIOCM_RTS; // set the RTS bit
158
status &= ~TIOCM_RTS; // clear the RTS bit
160
ioctl(fd, TIOCMSET, &status);
167
///////////////////////////////////////////////////////
168
// Function name : Cserial::setPTT
169
// Return type : void
170
///////////////////////////////////////////////////////
171
void Cserial::SetPTT(bool ON)
174
LOG_DEBUG("ptt fd < 0");
177
if (dtrptt || rtsptt) {
178
ioctl(fd, TIOCMGET, &status);
179
if (ON) { // ptt enabled
180
if (dtrptt && dtr) status &= ~TIOCM_DTR; // toggle low
181
if (dtrptt && !dtr) status |= TIOCM_DTR; // toggle high
183
if (rtsptt && rts) status &= ~TIOCM_RTS; // toggle low
184
if (rtsptt && !rts) status |= TIOCM_RTS; // toggle high
186
} else { // ptt disabled
187
if (dtrptt && dtr) status |= TIOCM_DTR; // toggle high
188
if (dtrptt && !dtr) status &= ~TIOCM_DTR; // toggle low
190
if (rtsptt && rts) status |= TIOCM_RTS; // toggle high
191
if (rtsptt && !rts) status &= ~TIOCM_RTS; // toggle low
194
LOG_INFO("PTT %d, DTRptt %d, DTR %d, RTSptt %d, RTS %d, RTSCTS %d, status %2X",
195
ON, dtrptt, dtr, rtsptt, rts, rtscts, status);
196
ioctl(fd, TIOCMSET, &status);
198
// LOG_DEBUG("No ptt specified");
201
void Cserial::setRTS(bool b)
206
ioctl(fd, TIOCMGET, &status);
208
status |= TIOCM_RTS; // toggle high
210
status &= ~TIOCM_RTS; // toggle low
211
ioctl(fd, TIOCMSET, &status);
215
void Cserial::setDTR(bool b)
220
ioctl(fd, TIOCMGET, &status);
222
status |= TIOCM_DTR; // toggle high
224
status &= ~TIOCM_DTR; // toggle low
225
ioctl(fd, TIOCMSET, &status);
229
///////////////////////////////////////////////////////
230
// Function name : Cserial::ClosePort
231
// Description : Closes the Port
232
// Return type : void
233
///////////////////////////////////////////////////////
234
void Cserial::ClosePort()
239
// LOG_INFO("Serial port closed, fd = %d", myfd);
240
ioctl(myfd, TIOCMSET, &origstatus);
241
tcsetattr (myfd, TCSANOW, &oldtio);
247
bool Cserial::IOselect ()
255
tv.tv_sec = timeout/1000;
256
tv.tv_usec = (timeout % 1000) * 1000;
257
retval = select (FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv);
258
if (retval <= 0) // no response from serial port or error returned
264
///////////////////////////////////////////////////////
265
// Function name : Cserial::ReadBuffer
266
// Description : Reads upto nchars from the selected port
267
// Return type : # characters received
268
// Argument : pointer to buffer; # chars to read
269
///////////////////////////////////////////////////////
270
int Cserial::ReadBuffer (char *buf, int nchars)
272
if (fd < 0) return 0;
273
int retnum, nread = 0;
278
retnum = read (fd, (char *)(buf + nread), nchars);
289
///////////////////////////////////////////////////////
290
// Function name : Cserial::WriteBuffer
291
// Description : Writes a string to the selected port
292
// Return type : bool
293
// Argument : BYTE by
294
///////////////////////////////////////////////////////
295
int Cserial::WriteBuffer(const char *buff, int n)
297
if (fd < 0) return 0;
298
int ret = write (fd, buff, n);
302
///////////////////////////////////////////////////////
303
// Function name : Cserial::WriteByte
304
// Description : Writes a Byte to the selected port
305
// Return type : bool
306
// Argument : BYTE by
307
///////////////////////////////////////////////////////
308
bool Cserial::WriteByte(char by)
310
if (fd < 0) return false;
312
buff[0] = by; buff[1] = 0;
313
return (write(fd, buff, 1) == 1);
316
///////////////////////////////////////////////////////
317
// Function name : Cserial::FlushBuffer
318
// Description : flushes the pending rx chars
319
// Return type : void
320
///////////////////////////////////////////////////////
321
void Cserial::FlushBuffer()
325
tcflush (fd, TCIFLUSH);
328
//=============================================================================
329
// WIN32 serial implementation
330
//=============================================================================
336
///////////////////////////////////////////////////////
337
// Function name : Cserial::CheckPort
338
// Description : Checks the port specified by strPortName
339
// Return type : bool
340
// Argument : c_string strPortName
341
///////////////////////////////////////////////////////
342
bool Cserial::CheckPort(string dev) {
344
string COMportname = "//./";
346
COMportname.append(dev);
348
hTest = CreateFile(COMportname.c_str(),
349
GENERIC_READ | GENERIC_WRITE,
356
if(hTest == INVALID_HANDLE_VALUE)
362
///////////////////////////////////////////////////////
363
// Function name : Cserial::OpenPort
364
// Description : Opens the port specified by strPortName
365
// Return type : bool
366
// Argument : CString strPortName
367
///////////////////////////////////////////////////////
368
bool Cserial::OpenPort()
370
string COMportname = "//./";
371
COMportname.append(device);
373
hComm = CreateFile(COMportname.c_str(),
374
GENERIC_READ | GENERIC_WRITE,
384
ConfigurePort( baud, 8, false, NOPARITY, stopbits);
385
//LOG_INFO("Comm port %s open; handle = %d", device.c_str(), hComm);
391
///////////////////////////////////////////////////////
392
// Function name : Cserial::ClosePort
393
// Description : Closes the Port
394
// Return type : void
395
///////////////////////////////////////////////////////
396
void Cserial::ClosePort()
399
bPortReady = SetCommTimeouts (hComm, &CommTimeoutsSaved);
406
bool Cserial::IsOpen()
408
if (!hComm) return false;
412
///////////////////////////////////////////////////////
413
// Function name : Cserial::GetBytesRead
415
// Return type : DWORD
416
///////////////////////////////////////////////////////
417
DWORD Cserial::GetBytesRead()
422
///////////////////////////////////////////////////////
423
// Function name : Cserial::GetBytesWritten
424
// Description : returns total number of bytes written to port
425
// Return type : DWORD
426
///////////////////////////////////////////////////////
427
DWORD Cserial::GetBytesWritten()
429
return nBytesWritten;
433
///////////////////////////////////////////////////////
434
// Function name : Cserial::ReadByte
435
// Description : Reads a byte from the selected port
436
// Return type : bool
437
// Argument : BYTE& by
438
///////////////////////////////////////////////////////
439
bool Cserial::ReadByte(char & by)
441
static BYTE byResByte[1024];
442
static DWORD dwBytesTxD=0;
444
if (!hComm) return false;
445
if (ReadFile (hComm, &byResByte[0], 1, &dwBytesTxD, 0)) {
446
if (dwBytesTxD == 1) {
447
by = (UCHAR)byResByte[0];
455
int Cserial::ReadData (char *buf, int nchars)
458
if (!ReadFile(hComm, buf, nchars, &dwRead, NULL))
463
int Cserial::ReadChars (char *buf, int nchars, int msec)
465
if (msec) Sleep(msec);
466
return ReadData (buf, nchars);
469
void Cserial::FlushBuffer()
471
#define TX_CLEAR 0x0004L
472
#define RX_CLEAR 0x0008L
474
PurgeComm(hComm, RX_CLEAR);
477
///////////////////////////////////////////////////////
478
// Function name : Cserial::WriteByte
479
// Description : Writes a Byte to teh selected port
480
// Return type : bool
481
// Argument : BYTE by
482
///////////////////////////////////////////////////////
483
bool Cserial::WriteByte(char by)
485
if (!hComm) return false;
487
if (WriteFile(hComm,&by,1,&nBytesWritten,NULL)==0)
492
///////////////////////////////////////////////////////
493
// Function name : Cserial::WriteBuffer
494
// Description : Writes a string to the selected port
495
// Return type : bool
496
// Argument : BYTE by
497
///////////////////////////////////////////////////////
498
int Cserial::WriteBuffer(const char *buff, int n)
502
WriteFile (hComm, buff, n, &nBytesWritten, NULL);
503
return nBytesWritten;
507
///////////////////////////////////////////////////////
508
// Function name : Cserial::SetCommunicationTimeouts
509
// Description : Sets the timeout for the selected port
510
// Return type : bool
511
// Argument : DWORD ReadIntervalTimeout
512
// Argument : DWORD ReadTotalTimeoutMultiplier
513
// Argument : DWORD ReadTotalTimeoutConstant
514
// Argument : DWORD WriteTotalTimeoutMultiplier
515
// Argument : DWORD WriteTotalTimeoutConstant
516
///////////////////////////////////////////////////////
517
bool Cserial::SetCommunicationTimeouts(
518
DWORD ReadIntervalTimeout, // msec
519
DWORD ReadTotalTimeoutMultiplier,
520
DWORD ReadTotalTimeoutConstant,
521
DWORD WriteTotalTimeoutMultiplier,
522
DWORD WriteTotalTimeoutConstant
525
if((bPortReady = GetCommTimeouts (hComm, &CommTimeoutsSaved))==0) {
529
Read Interval Timeout............... %ld\n\
530
Read Total Timeout Multiplier....... %ld\n\
531
Read Total Timeout Constant Timeout. %ld\n\
532
Write Total Timeout Constant........ %ld\n\
533
Write Total Timeout Multiplier...... %ld",
534
CommTimeoutsSaved.ReadIntervalTimeout,
535
CommTimeoutsSaved.ReadTotalTimeoutMultiplier,
536
CommTimeoutsSaved.ReadTotalTimeoutConstant,
537
CommTimeoutsSaved.WriteTotalTimeoutConstant,
538
CommTimeoutsSaved.WriteTotalTimeoutMultiplier);
540
CommTimeouts.ReadIntervalTimeout = ReadIntervalTimeout;
541
CommTimeouts.ReadTotalTimeoutMultiplier = ReadTotalTimeoutMultiplier;
542
CommTimeouts.ReadTotalTimeoutConstant = ReadTotalTimeoutConstant;
543
CommTimeouts.WriteTotalTimeoutConstant = WriteTotalTimeoutConstant;
544
CommTimeouts.WriteTotalTimeoutMultiplier = WriteTotalTimeoutMultiplier;
546
bPortReady = SetCommTimeouts (hComm, &CommTimeouts);
559
* WriteTotalTimeoutMultiplier
561
* The multiplier used to calculate the total time-out period for write
562
* operations, in milliseconds. For each write operation, this value is
563
* multiplied by the number of bytes to be written.
565
* WriteTotalTimeoutConstant
567
* A constant used to calculate the total time-out period for write operations,
568
* in milliseconds. For each write operation, this value is added to the product
569
* of the WriteTotalTimeoutMultiplier member and the number of bytes to be
572
* A value of zero for both the WriteTotalTimeoutMultiplier and
573
* WriteTotalTimeoutConstant members indicates that total time-outs are not
574
* used for write operations.
577
* If an application sets ReadIntervalTimeout and ReadTotalTimeoutMultiplier to
578
* MAXDWORD and sets ReadTotalTimeoutConstant to a value greater than zero and
579
* less than MAXDWORD, one of the following occurs when the ReadFile function
582
* If there are any bytes in the input buffer, ReadFile returns immediately
583
* with the bytes in the buffer.
585
* If there are no bytes in the input buffer, ReadFile waits until a byte
586
* arrives and then returns immediately.
588
* *********************************************************************
590
* If no bytes arrive within the time specified by ReadTotalTimeoutConstant,
591
* ReadFile times out.
593
* ReadIntervalTimeout
595
* The maximum time allowed to elapse between the arrival of two bytes on the
596
* communications line, in milliseconds. During a ReadFile operation, the time
597
* period begins when the first byte is received. If the interval between the
598
* arrival of any two bytes exceeds this amount, the ReadFile operation is
599
* completed and any buffered data is returned. A value of zero indicates that
600
* interval time-outs are not used.
602
* A value of MAXDWORD, combined with zero values for both the
603
* ReadTotalTimeoutConstant and ReadTotalTimeoutMultiplier members, specifies
604
* that the read operation is to return immediately with the bytes that have
605
* already been received, even if no bytes have been received.
607
* ReadTotalTimeoutMultiplier
609
* The multiplier used to calculate the total time-out period for read
610
* operations, in milliseconds. For each read operation, this value is
611
* multiplied by the requested number of bytes to be read.
613
* ReadTotalTimeoutConstant
615
* A constant used to calculate the total time-out period for read operations,
616
* in milliseconds. For each read operation, this value is added to the product
617
* of the ReadTotalTimeoutMultiplier member and the requested number of bytes.
619
* A value of zero for both the ReadTotalTimeoutMultiplier and
620
* ReadTotalTimeoutConstant members indicates that total time-outs are not
621
* used for read operations.
625
bool Cserial::SetCommTimeout() {
626
return SetCommunicationTimeouts (
627
0, // Read Interval Timeout
628
0, // Read Total Timeout Multiplier
629
50, // Read Total Timeout Constant
630
50, // Write Total Timeout Constant
631
0 // Write Total Timeout Multiplier
635
///////////////////////////////////////////////////////
636
// Function name : ConfigurePort
637
// Description : Configures the Port
638
// Return type : bool
639
// Argument : DWORD BaudRate
640
// Argument : BYTE ByteSize
641
// Argument : DWORD fParity
642
// Argument : BYTE Parity
643
// Argument : BYTE StopBits
644
///////////////////////////////////////////////////////
645
bool Cserial::ConfigurePort(
652
if((bPortReady = GetCommState(hComm, &dcb))==0) {
653
// LOG_ERROR("GetCommState Error on %s", device.c_str());
658
dcb.BaudRate = BaudRate;
659
dcb.ByteSize = ByteSize;
660
dcb.Parity = Parity ;
661
dcb.StopBits = (StopBits == 1 ? ONESTOPBIT : TWOSTOPBITS);
663
dcb.fDsrSensitivity = false;
664
dcb.fParity = dwParity;
668
dcb.fAbortOnError = true;
669
dcb.fOutxCtsFlow = false;
670
dcb.fOutxDsrFlow = false;
673
dcb.fDtrControl = DTR_CONTROL_ENABLE;
675
dcb.fDtrControl = DTR_CONTROL_DISABLE;
677
dcb.fDsrSensitivity = false;
679
if (rtscts) dcb.fRtsControl = RTS_CONTROL_ENABLE;
682
dcb.fRtsControl = RTS_CONTROL_ENABLE;
684
dcb.fRtsControl = RTS_CONTROL_DISABLE;
687
bPortReady = SetCommState(hComm, &dcb);
688
if(bPortReady == 0) {
692
return SetCommTimeout();
695
///////////////////////////////////////////////////////
696
// Function name : Cserial::setPTT
697
// Return type : void
698
///////////////////////////////////////////////////////
699
void Cserial::SetPTT(bool ON)
702
LOG_ERROR("Invalid handle");
705
if ( !(dtrptt || rtsptt) )
710
dcb.fDtrControl = DTR_CONTROL_DISABLE;
712
dcb.fDtrControl = DTR_CONTROL_ENABLE;
715
dcb.fRtsControl = RTS_CONTROL_DISABLE;
717
dcb.fRtsControl = RTS_CONTROL_ENABLE;
721
dcb.fDtrControl = DTR_CONTROL_ENABLE;
723
dcb.fDtrControl = DTR_CONTROL_DISABLE;
726
dcb.fRtsControl = RTS_CONTROL_ENABLE;
728
dcb.fRtsControl = RTS_CONTROL_DISABLE;
732
LOG_INFO("PTT %d, DTRptt %d, DTR %d, RTSptt %d, RTS %d, RTSCTS %d, %2x %2x",
733
ON, dtrptt, dtr, rtsptt, rts, rtscts,
734
static_cast<unsigned int>(dcb.fDtrControl),
735
static_cast<unsigned int>(dcb.fRtsControl) );
737
SetCommState(hComm, &dcb);
740
void Cserial::setRTS(bool b)
746
dcb.fRtsControl = RTS_CONTROL_ENABLE;
748
dcb.fRtsControl = RTS_CONTROL_DISABLE;
750
SetCommState(hComm, &dcb);
753
void Cserial::setDTR(bool b)
759
dcb.fDtrControl = DTR_CONTROL_ENABLE;
761
dcb.fDtrControl = DTR_CONTROL_DISABLE;
763
SetCommState(hComm, &dcb);