1
// ----------------------------------------------------------------------------
5
// This file is part of flrig.
7
// flrig is free software; you can redistribute it and/or modify
8
// it under the terms of the GNU General Public License as published by
9
// the Free Software Foundation; either version 3 of the License, or
10
// (at your option) any later version.
12
// flrig is distributed in the hope that it will be useful,
13
// but WITHOUT ANY WARRANTY; without even the implied warranty of
14
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
// GNU General Public License for more details.
17
// You should have received a copy of the GNU General Public License
18
// along with this program. If not, see <http://www.gnu.org/licenses/>.
19
// ----------------------------------------------------------------------------
26
LOG_FILE_SOURCE(debug::LOG_RIGCONTROL);
32
#include <sys/types.h>
35
#include <sys/ioctl.h>
43
device = "/dev/ttyS0";
48
rtsptt = dtrptt = false;
61
///////////////////////////////////////////////////////
62
// Function name : Cserial::OpenPort
63
// Description : Opens the port specified by strPortName
65
// Argument : c_string strPortName
66
///////////////////////////////////////////////////////
67
bool Cserial::CheckPort(string dev) {
68
int testfd = open( dev.c_str(), O_RDWR | O_NOCTTY | O_NDELAY);
75
///////////////////////////////////////////////////////
76
// Function name : Cserial::OpenPort
77
// Description : Opens the port specified by strPortName
79
// Argument : c_string strPortName
80
///////////////////////////////////////////////////////
81
bool Cserial::OpenPort() {
83
if ((fd = open( device.c_str(), O_RDWR | O_NOCTTY | O_NDELAY )) < 0)
85
// save current port settings
86
tcflush (fd, TCIFLUSH);
88
tcgetattr (fd, &oldtio);
92
newtio.c_cflag &= ~CSIZE;
93
newtio.c_cflag |= CS8;
94
// enable receiver, set local mode
95
newtio.c_cflag |= (CLOCAL | CREAD);
97
newtio.c_cflag &= ~PARENB;
101
newtio.c_cflag &= ~CSTOPB;
104
newtio.c_cflag |= CSTOPB;
108
newtio.c_cflag |= CRTSCTS;
111
newtio.c_cflag &= ~CRTSCTS;
114
newtio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
116
newtio.c_oflag &= ~OPOST;
117
// software flow control disabled
118
newtio.c_iflag &= ~IXON;
119
// do not translate CR to NL
120
newtio.c_iflag &= ~ICRNL;
153
cfsetispeed(&newtio, speed);
154
cfsetospeed(&newtio, speed);
156
tcsetattr (fd, TCSANOW, &newtio);
158
ioctl(fd, TIOCMGET, &status);
162
status |= TIOCM_DTR; // set the DTR bit
164
status &= ~TIOCM_DTR; // clear the DTR bit
166
if (rtscts == false) { // rts OK for ptt if RTSCTS not used
168
status |= TIOCM_RTS; // set the RTS bit
170
status &= ~TIOCM_RTS; // clear the RTS bit
172
ioctl(fd, TIOCMSET, &status);
179
///////////////////////////////////////////////////////
180
// Function name : Cserial::setPTT
181
// Return type : void
182
///////////////////////////////////////////////////////
183
void Cserial::SetPTT(bool ON)
186
LOG_DEBUG("ptt fd < 0");
189
if (dtrptt || rtsptt) {
190
ioctl(fd, TIOCMGET, &status);
191
if (ON) { // ptt enabled
192
if (dtrptt && dtr) status &= ~TIOCM_DTR; // toggle low
193
if (dtrptt && !dtr) status |= TIOCM_DTR; // toggle high
195
if (rtsptt && rts) status &= ~TIOCM_RTS; // toggle low
196
if (rtsptt && !rts) status |= TIOCM_RTS; // toggle high
198
} else { // ptt disabled
199
if (dtrptt && dtr) status |= TIOCM_DTR; // toggle high
200
if (dtrptt && !dtr) status &= ~TIOCM_DTR; // toggle low
202
if (rtsptt && rts) status |= TIOCM_RTS; // toggle high
203
if (rtsptt && !rts) status &= ~TIOCM_RTS; // toggle low
206
LOG_INFO("PTT %d, DTRptt %d, DTR %d, RTSptt %d, RTS %d, RTSCTS %d, status %2X",
207
ON, dtrptt, dtr, rtsptt, rts, rtscts, status);
208
ioctl(fd, TIOCMSET, &status);
210
// LOG_DEBUG("No ptt specified");
213
void Cserial::setRTS(bool b)
218
ioctl(fd, TIOCMGET, &status);
220
status |= TIOCM_RTS; // toggle high
222
status &= ~TIOCM_RTS; // toggle low
223
ioctl(fd, TIOCMSET, &status);
227
void Cserial::setDTR(bool b)
232
ioctl(fd, TIOCMGET, &status);
234
status |= TIOCM_DTR; // toggle high
236
status &= ~TIOCM_DTR; // toggle low
237
ioctl(fd, TIOCMSET, &status);
241
///////////////////////////////////////////////////////
242
// Function name : Cserial::ClosePort
243
// Description : Closes the Port
244
// Return type : void
245
///////////////////////////////////////////////////////
246
void Cserial::ClosePort()
251
// LOG_INFO("Serial port closed, fd = %d", myfd);
252
ioctl(myfd, TIOCMSET, &origstatus);
253
tcsetattr (myfd, TCSANOW, &oldtio);
259
bool Cserial::IOselect ()
267
tv.tv_sec = timeout/1000;
268
tv.tv_usec = (timeout % 1000) * 1000;
269
retval = select (FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv);
270
if (retval <= 0) // no response from serial port or error returned
276
///////////////////////////////////////////////////////
277
// Function name : Cserial::ReadBuffer
278
// Description : Reads upto nchars from the selected port
279
// Return type : # characters received
280
// Argument : pointer to buffer; # chars to read
281
///////////////////////////////////////////////////////
282
int Cserial::ReadBuffer (char *buf, int nchars)
284
if (fd < 0) return 0;
285
int retnum, nread = 0;
290
retnum = read (fd, (char *)(buf + nread), nchars);
301
///////////////////////////////////////////////////////
302
// Function name : Cserial::WriteBuffer
303
// Description : Writes a string to the selected port
304
// Return type : bool
305
// Argument : BYTE by
306
///////////////////////////////////////////////////////
307
int Cserial::WriteBuffer(const char *buff, int n)
309
if (fd < 0) return 0;
310
int ret = write (fd, buff, n);
314
///////////////////////////////////////////////////////
315
// Function name : Cserial::WriteByte
316
// Description : Writes a Byte to the selected port
317
// Return type : bool
318
// Argument : BYTE by
319
///////////////////////////////////////////////////////
320
bool Cserial::WriteByte(char by)
322
if (fd < 0) return false;
324
buff[0] = by; buff[1] = 0;
325
return (write(fd, buff, 1) == 1);
328
///////////////////////////////////////////////////////
329
// Function name : Cserial::FlushBuffer
330
// Description : flushes the pending rx chars
331
// Return type : void
332
///////////////////////////////////////////////////////
333
void Cserial::FlushBuffer()
337
tcflush (fd, TCIFLUSH);
340
//=============================================================================
341
// WIN32 serial implementation
342
//=============================================================================
348
///////////////////////////////////////////////////////
349
// Function name : Cserial::CheckPort
350
// Description : Checks the port specified by strPortName
351
// Return type : bool
352
// Argument : c_string strPortName
353
///////////////////////////////////////////////////////
354
bool Cserial::CheckPort(string dev) {
356
string COMportname = "//./";
358
COMportname.append(dev);
360
hTest = CreateFile(COMportname.c_str(),
361
GENERIC_READ | GENERIC_WRITE,
368
if(hTest == INVALID_HANDLE_VALUE)
374
///////////////////////////////////////////////////////
375
// Function name : Cserial::OpenPort
376
// Description : Opens the port specified by strPortName
377
// Return type : bool
378
// Argument : CString strPortName
379
///////////////////////////////////////////////////////
380
bool Cserial::OpenPort()
382
string COMportname = "//./";
383
COMportname.append(device);
385
hComm = CreateFile(COMportname.c_str(),
386
GENERIC_READ | GENERIC_WRITE,
396
ConfigurePort( baud, 8, false, NOPARITY, stopbits);
397
//LOG_INFO("Comm port %s open; handle = %d", device.c_str(), hComm);
403
///////////////////////////////////////////////////////
404
// Function name : Cserial::ClosePort
405
// Description : Closes the Port
406
// Return type : void
407
///////////////////////////////////////////////////////
408
void Cserial::ClosePort()
411
bPortReady = SetCommTimeouts (hComm, &CommTimeoutsSaved);
418
bool Cserial::IsOpen()
420
if (!hComm) return false;
424
///////////////////////////////////////////////////////
425
// Function name : Cserial::GetBytesRead
427
// Return type : DWORD
428
///////////////////////////////////////////////////////
429
DWORD Cserial::GetBytesRead()
434
///////////////////////////////////////////////////////
435
// Function name : Cserial::GetBytesWritten
436
// Description : returns total number of bytes written to port
437
// Return type : DWORD
438
///////////////////////////////////////////////////////
439
DWORD Cserial::GetBytesWritten()
441
return nBytesWritten;
445
///////////////////////////////////////////////////////
446
// Function name : Cserial::ReadByte
447
// Description : Reads a byte from the selected port
448
// Return type : bool
449
// Argument : BYTE& by
450
///////////////////////////////////////////////////////
451
bool Cserial::ReadByte(char & by)
453
static BYTE byResByte[1024];
454
static DWORD dwBytesTxD=0;
456
if (!hComm) return false;
457
if (ReadFile (hComm, &byResByte[0], 1, &dwBytesTxD, 0)) {
458
if (dwBytesTxD == 1) {
459
by = (UCHAR)byResByte[0];
467
int Cserial::ReadData (char *buf, int nchars)
470
if (!ReadFile(hComm, buf, nchars, &dwRead, NULL))
475
int Cserial::ReadChars (char *buf, int nchars, int msec)
477
if (msec) Sleep(msec);
478
return ReadData (buf, nchars);
481
void Cserial::FlushBuffer()
483
#define TX_CLEAR 0x0004L
484
#define RX_CLEAR 0x0008L
486
PurgeComm(hComm, RX_CLEAR);
489
///////////////////////////////////////////////////////
490
// Function name : Cserial::WriteByte
491
// Description : Writes a Byte to teh selected port
492
// Return type : bool
493
// Argument : BYTE by
494
///////////////////////////////////////////////////////
495
bool Cserial::WriteByte(char by)
497
if (!hComm) return false;
499
if (WriteFile(hComm,&by,1,&nBytesWritten,NULL)==0)
504
///////////////////////////////////////////////////////
505
// Function name : Cserial::WriteBuffer
506
// Description : Writes a string to the selected port
507
// Return type : bool
508
// Argument : BYTE by
509
///////////////////////////////////////////////////////
510
int Cserial::WriteBuffer(const char *buff, int n)
514
WriteFile (hComm, buff, n, &nBytesWritten, NULL);
515
return nBytesWritten;
519
///////////////////////////////////////////////////////
520
// Function name : Cserial::SetCommunicationTimeouts
521
// Description : Sets the timeout for the selected port
522
// Return type : bool
523
// Argument : DWORD ReadIntervalTimeout
524
// Argument : DWORD ReadTotalTimeoutMultiplier
525
// Argument : DWORD ReadTotalTimeoutConstant
526
// Argument : DWORD WriteTotalTimeoutMultiplier
527
// Argument : DWORD WriteTotalTimeoutConstant
528
///////////////////////////////////////////////////////
529
bool Cserial::SetCommunicationTimeouts(
530
DWORD ReadIntervalTimeout, // msec
531
DWORD ReadTotalTimeoutMultiplier,
532
DWORD ReadTotalTimeoutConstant,
533
DWORD WriteTotalTimeoutMultiplier,
534
DWORD WriteTotalTimeoutConstant
537
if((bPortReady = GetCommTimeouts (hComm, &CommTimeoutsSaved))==0) {
541
Read Interval Timeout............... %ld\n\
542
Read Total Timeout Multiplier....... %ld\n\
543
Read Total Timeout Constant Timeout. %ld\n\
544
Write Total Timeout Constant........ %ld\n\
545
Write Total Timeout Multiplier...... %ld",
546
CommTimeoutsSaved.ReadIntervalTimeout,
547
CommTimeoutsSaved.ReadTotalTimeoutMultiplier,
548
CommTimeoutsSaved.ReadTotalTimeoutConstant,
549
CommTimeoutsSaved.WriteTotalTimeoutConstant,
550
CommTimeoutsSaved.WriteTotalTimeoutMultiplier);
552
CommTimeouts.ReadIntervalTimeout = ReadIntervalTimeout;
553
CommTimeouts.ReadTotalTimeoutMultiplier = ReadTotalTimeoutMultiplier;
554
CommTimeouts.ReadTotalTimeoutConstant = ReadTotalTimeoutConstant;
555
CommTimeouts.WriteTotalTimeoutConstant = WriteTotalTimeoutConstant;
556
CommTimeouts.WriteTotalTimeoutMultiplier = WriteTotalTimeoutMultiplier;
558
bPortReady = SetCommTimeouts (hComm, &CommTimeouts);
571
* WriteTotalTimeoutMultiplier
573
* The multiplier used to calculate the total time-out period for write
574
* operations, in milliseconds. For each write operation, this value is
575
* multiplied by the number of bytes to be written.
577
* WriteTotalTimeoutConstant
579
* A constant used to calculate the total time-out period for write operations,
580
* in milliseconds. For each write operation, this value is added to the product
581
* of the WriteTotalTimeoutMultiplier member and the number of bytes to be
584
* A value of zero for both the WriteTotalTimeoutMultiplier and
585
* WriteTotalTimeoutConstant members indicates that total time-outs are not
586
* used for write operations.
589
* If an application sets ReadIntervalTimeout and ReadTotalTimeoutMultiplier to
590
* MAXDWORD and sets ReadTotalTimeoutConstant to a value greater than zero and
591
* less than MAXDWORD, one of the following occurs when the ReadFile function
594
* If there are any bytes in the input buffer, ReadFile returns immediately
595
* with the bytes in the buffer.
597
* If there are no bytes in the input buffer, ReadFile waits until a byte
598
* arrives and then returns immediately.
600
* *********************************************************************
602
* If no bytes arrive within the time specified by ReadTotalTimeoutConstant,
603
* ReadFile times out.
605
* ReadIntervalTimeout
607
* The maximum time allowed to elapse between the arrival of two bytes on the
608
* communications line, in milliseconds. During a ReadFile operation, the time
609
* period begins when the first byte is received. If the interval between the
610
* arrival of any two bytes exceeds this amount, the ReadFile operation is
611
* completed and any buffered data is returned. A value of zero indicates that
612
* interval time-outs are not used.
614
* A value of MAXDWORD, combined with zero values for both the
615
* ReadTotalTimeoutConstant and ReadTotalTimeoutMultiplier members, specifies
616
* that the read operation is to return immediately with the bytes that have
617
* already been received, even if no bytes have been received.
619
* ReadTotalTimeoutMultiplier
621
* The multiplier used to calculate the total time-out period for read
622
* operations, in milliseconds. For each read operation, this value is
623
* multiplied by the requested number of bytes to be read.
625
* ReadTotalTimeoutConstant
627
* A constant used to calculate the total time-out period for read operations,
628
* in milliseconds. For each read operation, this value is added to the product
629
* of the ReadTotalTimeoutMultiplier member and the requested number of bytes.
631
* A value of zero for both the ReadTotalTimeoutMultiplier and
632
* ReadTotalTimeoutConstant members indicates that total time-outs are not
633
* used for read operations.
637
bool Cserial::SetCommTimeout() {
638
return SetCommunicationTimeouts (
639
0, // Read Interval Timeout
640
0, // Read Total Timeout Multiplier
641
50, // Read Total Timeout Constant
642
50, // Write Total Timeout Constant
643
0 // Write Total Timeout Multiplier
647
///////////////////////////////////////////////////////
648
// Function name : ConfigurePort
649
// Description : Configures the Port
650
// Return type : bool
651
// Argument : DWORD BaudRate
652
// Argument : BYTE ByteSize
653
// Argument : DWORD fParity
654
// Argument : BYTE Parity
655
// Argument : BYTE StopBits
656
///////////////////////////////////////////////////////
657
bool Cserial::ConfigurePort(
664
if((bPortReady = GetCommState(hComm, &dcb))==0) {
665
// LOG_ERROR("GetCommState Error on %s", device.c_str());
670
dcb.BaudRate = BaudRate;
671
dcb.ByteSize = ByteSize;
672
dcb.Parity = Parity ;
673
dcb.StopBits = (StopBits == 1 ? ONESTOPBIT : TWOSTOPBITS);
675
dcb.fDsrSensitivity = false;
676
dcb.fParity = dwParity;
680
dcb.fAbortOnError = true;
681
dcb.fOutxCtsFlow = false;
682
dcb.fOutxDsrFlow = false;
685
dcb.fDtrControl = DTR_CONTROL_ENABLE;
687
dcb.fDtrControl = DTR_CONTROL_DISABLE;
689
dcb.fDsrSensitivity = false;
691
if (rtscts) dcb.fRtsControl = RTS_CONTROL_ENABLE;
694
dcb.fRtsControl = RTS_CONTROL_ENABLE;
696
dcb.fRtsControl = RTS_CONTROL_DISABLE;
699
bPortReady = SetCommState(hComm, &dcb);
700
if(bPortReady == 0) {
704
return SetCommTimeout();
707
///////////////////////////////////////////////////////
708
// Function name : Cserial::setPTT
709
// Return type : void
710
///////////////////////////////////////////////////////
711
void Cserial::SetPTT(bool ON)
714
LOG_ERROR("Invalid handle");
717
if ( !(dtrptt || rtsptt) )
722
dcb.fDtrControl = DTR_CONTROL_DISABLE;
724
dcb.fDtrControl = DTR_CONTROL_ENABLE;
727
dcb.fRtsControl = RTS_CONTROL_DISABLE;
729
dcb.fRtsControl = RTS_CONTROL_ENABLE;
733
dcb.fDtrControl = DTR_CONTROL_ENABLE;
735
dcb.fDtrControl = DTR_CONTROL_DISABLE;
738
dcb.fRtsControl = RTS_CONTROL_ENABLE;
740
dcb.fRtsControl = RTS_CONTROL_DISABLE;
744
LOG_INFO("PTT %d, DTRptt %d, DTR %d, RTSptt %d, RTS %d, RTSCTS %d, %2x %2x",
745
ON, dtrptt, dtr, rtsptt, rts, rtscts,
746
static_cast<unsigned int>(dcb.fDtrControl),
747
static_cast<unsigned int>(dcb.fRtsControl) );
749
SetCommState(hComm, &dcb);
752
void Cserial::setRTS(bool b)
758
dcb.fRtsControl = RTS_CONTROL_ENABLE;
760
dcb.fRtsControl = RTS_CONTROL_DISABLE;
762
SetCommState(hComm, &dcb);
765
void Cserial::setDTR(bool b)
771
dcb.fDtrControl = DTR_CONTROL_ENABLE;
773
dcb.fDtrControl = DTR_CONTROL_DISABLE;
775
SetCommState(hComm, &dcb);