OpenCores
URL https://opencores.org/ocsvn/w11/w11/trunk

Subversion Repositories w11

[/] [w11/] [tags/] [w11a_V0.7/] [tools/] [src/] [librlink/] [RlinkPortTerm.cpp] - Blame information for rev 33

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 30 wfjm
// $Id: RlinkPortTerm.cpp 666 2015-04-12 21:17:54Z mueller $
2 10 wfjm
//
3 29 wfjm
// Copyright 2011-2015 by Walter F.J. Mueller <W.F.J.Mueller@gsi.de>
4 10 wfjm
//
5
// This program is free software; you may redistribute and/or modify it under
6
// the terms of the GNU General Public License as published by the Free
7
// Software Foundation, either version 2, or at your option any later version.
8
//
9
// This program is distributed in the hope that it will be useful, but
10
// WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
11
// or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12
// for complete details.
13
// 
14
// Revision History: 
15
// Date         Rev Version  Comment
16 30 wfjm
// 2015-04-12   666   1.3    drop xon/xoff excaping; add noinit attribute
17 29 wfjm
// 2015-02-01   641   1.2    support custom baud rates (5M,6M,10M,12M)
18 19 wfjm
// 2013-02-23   492   1.1    use RparseUrl
19 16 wfjm
// 2011-12-18   440   1.0.4  add kStatNPort stats; Open(): autoadd /dev/tty,
20
//                           BUGFIX: Open(): set VSTART, VSTOP
21
// 2011-12-11   438   1.0.3  Read(),Write(): added for xon handling, tcdrain();
22
//                           Open(): add more baud rates, support xon attribute
23 15 wfjm
// 2011-12-04   435   1.0.2  Open(): add cts attr, hw flow control now optional
24 12 wfjm
// 2011-07-04   388   1.0.1  add termios readback and verification
25 10 wfjm
// 2011-03-27   374   1.0    Initial version
26
// ---------------------------------------------------------------------------
27
 
28
/*!
29
  \file
30 30 wfjm
  \version $Id: RlinkPortTerm.cpp 666 2015-04-12 21:17:54Z mueller $
31 10 wfjm
  \brief   Implemenation of RlinkPortTerm.
32
*/
33
 
34
#include <sys/types.h>
35
#include <sys/stat.h>
36
#include <fcntl.h>
37
#include <errno.h>
38
#include <unistd.h>
39
#include <termios.h>
40 29 wfjm
#include <sys/ioctl.h>
41
#include <linux/serial.h>
42 10 wfjm
 
43
#include "RlinkPortTerm.hpp"
44
 
45
#include "librtools/RosFill.hpp"
46
#include "librtools/RosPrintf.hpp"
47
 
48
using namespace std;
49
 
50
/*!
51
  \class Retro::RlinkPortTerm
52 19 wfjm
  \brief FIXME_docs
53 10 wfjm
*/
54
 
55 19 wfjm
// all method definitions in namespace Retro
56
namespace Retro {
57
 
58 10 wfjm
//------------------------------------------+-----------------------------------
59 16 wfjm
// constants definitions
60
const uint8_t RlinkPortTerm::kc_xon;
61
const uint8_t RlinkPortTerm::kc_xoff;
62
 
63
//------------------------------------------+-----------------------------------
64 10 wfjm
//! Default constructor
65
 
66
RlinkPortTerm::RlinkPortTerm()
67
  : RlinkPort()
68 30 wfjm
{}
69 10 wfjm
 
70
//------------------------------------------+-----------------------------------
71
//! Destructor
72
 
73
RlinkPortTerm::~RlinkPortTerm()
74
{
75 19 wfjm
  RlinkPortTerm::Close();
76 10 wfjm
}
77
 
78
//------------------------------------------+-----------------------------------
79 19 wfjm
//! FIXME_docs
80 10 wfjm
 
81
bool RlinkPortTerm::Open(const std::string& url, RerrMsg& emsg)
82
{
83 19 wfjm
  Close();
84 10 wfjm
 
85 30 wfjm
  if (!fUrl.Set(url, "|baud=|break|cts|xon|noinit|", emsg)) return false;
86 10 wfjm
 
87 16 wfjm
  // if path doesn't start with a '/' prepend a '/dev/tty'
88 19 wfjm
  if (fUrl.Path().substr(0,1) != "/") {
89
    fUrl.SetPath(string("/dev/tty" + fUrl.Path()));
90 16 wfjm
  }
91
 
92 10 wfjm
  speed_t speed = B115200;
93 29 wfjm
  unsigned long nsbaud = 0;
94 10 wfjm
  string baud;
95 19 wfjm
  if (fUrl.FindOpt("baud", baud)) {
96 10 wfjm
    speed = B0;
97 16 wfjm
    if (baud=="2400")                     speed = B2400;
98
    if (baud=="4800")                     speed = B4800;
99 10 wfjm
    if (baud=="9600")                     speed = B9600;
100
    if (baud=="19200"   || baud=="19k")   speed = B19200;
101
    if (baud=="38400"   || baud=="38k")   speed = B38400;
102
    if (baud=="57600"   || baud=="57k")   speed = B57600;
103
    if (baud=="115200"  || baud=="115k")  speed = B115200;
104
    if (baud=="230400"  || baud=="230k")  speed = B230400;
105
    if (baud=="460800"  || baud=="460k")  speed = B460800;
106
    if (baud=="500000"  || baud=="500k")  speed = B500000;
107
    if (baud=="921600"  || baud=="921k")  speed = B921600;
108 16 wfjm
    if (baud=="1000000" || baud=="1000k" || baud=="1M") speed = B1000000;
109
    if (baud=="1152000" || baud=="1152k")               speed = B1152000;
110
    if (baud=="1500000" || baud=="1500k")               speed = B1500000;
111
    if (baud=="2000000" || baud=="2000k" || baud=="2M") speed = B2000000;
112
    if (baud=="2500000" || baud=="2500k")               speed = B2500000;
113
    if (baud=="3000000" || baud=="3000k" || baud=="3M") speed = B3000000;
114
    if (baud=="3500000" || baud=="3500k")               speed = B3500000;
115
    if (baud=="4000000" || baud=="4000k" || baud=="4M") speed = B4000000;
116 29 wfjm
 
117
    // now handle non-standart baud rates
118 10 wfjm
    if (speed == B0) {
119 29 wfjm
      if (baud== "5000000" || baud== "5000k" || baud== "5M") nsbaud =  5000000;
120
      if (baud== "6000000" || baud== "6000k" || baud== "6M") nsbaud =  6000000;
121
      if (baud== "6666666" || baud== "6666k")                nsbaud =  6666666;
122
      if (baud=="10000000" || baud=="10000k" || baud=="10M") nsbaud = 10000000;
123
      if (baud=="12000000" || baud=="12000k" || baud=="12M") nsbaud = 12000000;
124
      if (nsbaud == 0) {
125
        emsg.Init("RlinkPortTerm::Open()",
126
                  string("invalid baud rate '") + baud + "' specified");
127
        return false;
128
      }
129 10 wfjm
    }
130
  }
131
 
132
  int fd;
133
 
134 19 wfjm
  fd = open(fUrl.Path().c_str(), O_RDWR|O_NOCTTY);
135 10 wfjm
  if (fd < 0) {
136
    emsg.InitErrno("RlinkPortTerm::Open()",
137 21 wfjm
                   string("open() for '") + fUrl.Path() + "' failed: ",
138 10 wfjm
                   errno);
139
    return false;
140
  }
141
 
142
  if (!isatty(fd)) {
143
    emsg.Init("RlinkPortTerm::Open()",
144 21 wfjm
              string("isatty() check for '") + fUrl.Path() +
145
              "' failed: not a TTY");
146 10 wfjm
    close(fd);
147
    return false;
148
  }
149
 
150 27 wfjm
  if (::tcgetattr(fd, &fTiosOld) != 0) {
151 10 wfjm
    emsg.InitErrno("RlinkPortTerm::Open()",
152 21 wfjm
                   string("tcgetattr() for '") + fUrl.Path() + "' failed: ",
153 10 wfjm
                   errno);
154 27 wfjm
    ::close(fd);
155 10 wfjm
    return false;
156
  }
157
 
158 29 wfjm
  struct serial_struct sioctl;
159
  int cdivisor = 0;
160
 
161
  if (nsbaud != 0) {
162
    if (::ioctl(fd, TIOCGSERIAL, &sioctl) < 0) {
163
      emsg.InitErrno("RlinkPortTerm::Open()",
164
                     string("ioctl(TIOCGSERIAL) for '")+fUrl.Path()+"' failed: ",
165
                     errno);
166
      ::close(fd);
167
      return false;
168
    }
169
    double fcdivisor = double(sioctl.baud_base) / double(nsbaud);
170
    cdivisor = fcdivisor + 0.5;
171
    speed    = B38400;
172
  }
173
 
174 19 wfjm
  bool use_cts = fUrl.FindOpt("cts");
175
  bool use_xon = fUrl.FindOpt("xon");
176 30 wfjm
  fXon = use_xon;
177 16 wfjm
 
178 10 wfjm
  fTiosNew = fTiosOld;
179
 
180
  fTiosNew.c_iflag = IGNBRK |               // ignore breaks on input
181
                     IGNPAR;                // ignore parity errors
182 16 wfjm
  if (use_xon) {
183
    fTiosNew.c_iflag |= IXON|               // XON/XOFF flow control output
184
                        IXOFF;              // XON/XOFF flow control input
185
  }
186 15 wfjm
 
187 10 wfjm
  fTiosNew.c_oflag = 0;
188 15 wfjm
 
189 10 wfjm
  fTiosNew.c_cflag = CS8 |                  // 8 bit chars
190
                     CSTOPB |               // 2 stop bits
191
                     CREAD |                // enable receiver
192 15 wfjm
                     CLOCAL;                // ignore modem control
193 16 wfjm
  if (use_cts) {
194 15 wfjm
    fTiosNew.c_cflag |= CRTSCTS;            // enable hardware flow control
195
  }
196
 
197 10 wfjm
  fTiosNew.c_lflag = 0;
198
 
199 27 wfjm
  if (::cfsetspeed(&fTiosNew, speed) != 0) {
200 10 wfjm
    emsg.InitErrno("RlinkPortTerm::Open()",
201 21 wfjm
                   string("cfsetspeed() for '") + baud + "' failed: ",
202 10 wfjm
                   errno);
203
    close(fd);
204
    return false;
205
  }
206
 
207 29 wfjm
  if (cdivisor != 0) {
208
    sioctl.flags          |= ASYNC_SPD_CUST;
209
    sioctl.custom_divisor  = cdivisor;
210
    if (::ioctl(fd, TIOCSSERIAL, &sioctl) < 0) {
211
      emsg.InitErrno("RlinkPortTerm::Open()",
212
                     string("ioctl(TIOCSSERIAL) for '")+fUrl.Path()+"' failed: ",
213
                     errno);
214
      ::close(fd);
215
      return false;
216
    }
217
  }
218
 
219 10 wfjm
  fTiosNew.c_cc[VEOF]   = 0;                // undef
220
  fTiosNew.c_cc[VEOL]   = 0;                // undef
221
  fTiosNew.c_cc[VERASE] = 0;                // undef
222
  fTiosNew.c_cc[VINTR]  = 0;                // undef
223
  fTiosNew.c_cc[VKILL]  = 0;                // undef
224
  fTiosNew.c_cc[VQUIT]  = 0;                // undef
225
  fTiosNew.c_cc[VSUSP]  = 0;                // undef
226
  fTiosNew.c_cc[VSTART] = 0;                // undef
227
  fTiosNew.c_cc[VSTOP]  = 0;                // undef
228
  fTiosNew.c_cc[VMIN]   = 1;                // wait for 1 char
229
  fTiosNew.c_cc[VTIME]  = 0;                // 
230 16 wfjm
  if (use_xon) {
231
    fTiosNew.c_cc[VSTART] = kc_xon;         // setup XON  -> ^Q
232
    fTiosNew.c_cc[VSTOP]  = kc_xoff;        // setup XOFF -> ^S   
233
  }
234 10 wfjm
 
235 27 wfjm
  if (::tcsetattr(fd, TCSANOW, &fTiosNew) != 0) {
236 10 wfjm
    emsg.InitErrno("RlinkPortTerm::Open()",
237 21 wfjm
                   string("tcsetattr() for '") + fUrl.Path() + "' failed: ",
238 10 wfjm
                   errno);
239 27 wfjm
    ::close(fd);
240 10 wfjm
    return false;
241
  }
242
 
243 12 wfjm
  // tcsetattr() returns success if any of the requested changes could be
244
  // successfully carried out. Therefore the termios structure is read back
245
  // and verified.
246
 
247
  struct termios tios;
248 27 wfjm
  if (::tcgetattr(fd, &tios) != 0) {
249 12 wfjm
    emsg.InitErrno("RlinkPortTerm::Open()",
250 21 wfjm
                   string("2nd tcgetattr() for '") + fUrl.Path() +
251
                   "' failed: ", errno);
252 27 wfjm
    ::close(fd);
253 12 wfjm
    return false;
254
  }
255
 
256
  const char* pmsg = 0;
257
  if (tios.c_iflag != fTiosNew.c_iflag) pmsg = "c_iflag";
258
  if (tios.c_oflag != fTiosNew.c_oflag) pmsg = "c_oflag";
259
  if (tios.c_cflag != fTiosNew.c_cflag) pmsg = "c_cflag";
260
  if (tios.c_lflag != fTiosNew.c_lflag) pmsg = "c_lflag";
261 27 wfjm
  if (::cfgetispeed(&tios) != speed)      pmsg = "ispeed";
262
  if (::cfgetospeed(&tios) != speed)      pmsg = "ospeed";
263 12 wfjm
  for (int i=0; i<NCCS; i++) {
264
    if (tios.c_cc[i] != fTiosNew.c_cc[i]) pmsg = "c_cc char";
265
  }
266
 
267 29 wfjm
  // FIXME_code: why does readback fail for 38400 ?
268
  if (speed != B38400 && pmsg) {
269 12 wfjm
    emsg.Init("RlinkPortTerm::Open()",
270 21 wfjm
              string("tcsetattr() failed to set") + string(pmsg));
271 27 wfjm
    ::close(fd);
272 12 wfjm
    return false;
273
  }
274
 
275 10 wfjm
  fFdWrite = fd;
276
  fFdRead  = fd;
277
  fIsOpen  = true;
278
 
279 19 wfjm
  if (fUrl.FindOpt("break")) {
280 10 wfjm
    if (tcsendbreak(fd, 0) != 0) {
281
      emsg.InitErrno("RlinkPortTerm::Open()",
282 19 wfjm
                     string("tcsendbreak() for '") + fUrl.Path() +
283 21 wfjm
                     "' failed: ", errno);
284 10 wfjm
      Close();
285
      return false;
286
    }
287
    uint8_t buf[1];
288
    buf[0] = 0x80;
289
    if (Write(buf, 1, emsg) != 1) {
290
      Close();
291
      return false;
292
    }
293
  }
294
 
295
  return true;
296
}
297
 
298
//------------------------------------------+-----------------------------------
299 19 wfjm
//! FIXME_docs
300 10 wfjm
 
301
void RlinkPortTerm::Close()
302
{
303 17 wfjm
  if (!IsOpen()) return;
304
 
305
  if (fFdWrite >= 0) {
306 27 wfjm
    ::tcflush(fFdWrite, TCIOFLUSH);
307
    ::tcsetattr(fFdWrite, TCSANOW, &fTiosOld);
308 10 wfjm
  }
309 17 wfjm
  RlinkPort::Close();
310
 
311 10 wfjm
  return;
312
}
313
 
314
//------------------------------------------+-----------------------------------
315 16 wfjm
//! FIXME_docs
316
 
317 10 wfjm
void RlinkPortTerm::Dump(std::ostream& os, int ind, const char* text) const
318
{
319
  RosFill bl(ind);
320
  os << bl << (text?text:"--") << "RlinkPortTerm @ " << this << endl;
321
  DumpTios(os, ind, "fTiosOld", fTiosOld);
322
  DumpTios(os, ind, "fTiosNew", fTiosNew);
323 19 wfjm
  RlinkPort::Dump(os, ind, " ^");
324 10 wfjm
  return;
325 19 wfjm
}
326 10 wfjm
 
327
//------------------------------------------+-----------------------------------
328 19 wfjm
//! FIXME_docs
329 10 wfjm
 
330
void RlinkPortTerm::DumpTios(std::ostream& os, int ind, const std::string& name,
331
                             const struct termios& tios) const
332
{
333
  RosFill bl(ind+2);
334
  os << bl << name << ":" << endl;
335
  os << bl << "  c_iflag : " << RosPrintf(tios.c_iflag,"x0",8);
336
  if (tios.c_iflag & BRKINT) os << " BRKINT";
337
  if (tios.c_iflag & ICRNL)  os << " ICRNL ";
338
  if (tios.c_iflag & IGNBRK) os << " IGNBRK";
339
  if (tios.c_iflag & IGNCR)  os << " IGNCR ";
340
  if (tios.c_iflag & IGNPAR) os << " IGNPAR";
341
  if (tios.c_iflag & INLCR)  os << " INLCR ";
342
  if (tios.c_iflag & INPCK)  os << " INPCK ";
343
  if (tios.c_iflag & ISTRIP) os << " ISTRIP";
344
  if (tios.c_iflag & IXOFF)  os << " IXOFF ";
345
  if (tios.c_iflag & IXON)   os << " IXON  ";
346
  if (tios.c_iflag & PARMRK) os << " PARMRK";
347
  os << endl;
348
 
349
  os << bl << "  c_oflag : " << RosPrintf(tios.c_oflag,"x0",8);
350
  if (tios.c_oflag & OPOST)  os << " OPOST ";
351
  os << endl;
352
 
353
  os << bl << "  c_cflag : " << RosPrintf(tios.c_cflag,"x0",8);
354
  if (tios.c_cflag & CLOCAL) os << " CLOCAL";
355
  if (tios.c_cflag & CREAD)  os << " CREAD ";
356
  if ((tios.c_cflag & CSIZE) == CS5)  os << " CS5   ";
357
  if ((tios.c_cflag & CSIZE) == CS6)  os << " CS6   ";
358
  if ((tios.c_cflag & CSIZE) == CS7)  os << " CS7   ";
359
  if ((tios.c_cflag & CSIZE) == CS8)  os << " CS8   ";
360
  if (tios.c_cflag & CSTOPB) os << " CSTOPB";
361
  if (tios.c_cflag & HUPCL)  os << " HUPCL ";
362
  if (tios.c_cflag & PARENB) os << " PARENB";
363
  if (tios.c_cflag & PARODD) os << " PARODD";
364
  speed_t speed = cfgetispeed(&tios);
365
  int baud = 0;
366 16 wfjm
  if (speed == B2400)    baud =    2400;
367
  if (speed == B4800)    baud =    4800;
368 10 wfjm
  if (speed == B9600)    baud =    9600;
369
  if (speed == B19200)   baud =   19200;
370
  if (speed == B38400)   baud =   38400;
371
  if (speed == B57600)   baud =   57600;
372
  if (speed == B115200)  baud =  115200;
373
  if (speed == B230400)  baud =  230400;
374
  if (speed == B460800)  baud =  460800;
375
  if (speed == B500000)  baud =  500000;
376
  if (speed == B921600)  baud =  921600;
377
  if (speed == B1000000) baud = 1000000;
378 16 wfjm
  if (speed == B1152000) baud = 1152000;
379
  if (speed == B1500000) baud = 1500000;
380 10 wfjm
  if (speed == B2000000) baud = 2000000;
381 16 wfjm
  if (speed == B2500000) baud = 2500000;
382 10 wfjm
  if (speed == B3000000) baud = 3000000;
383 16 wfjm
  if (speed == B3500000) baud = 3500000;
384
  if (speed == B4000000) baud = 4000000;
385 10 wfjm
  os << " speed: " << RosPrintf(baud, "d", 7);
386
  os << endl;
387
 
388
  os << bl << "  c_lflag : " << RosPrintf(tios.c_lflag,"x0",8);
389
  if (tios.c_lflag & ECHO)   os << " ECHO  ";
390
  if (tios.c_lflag & ECHOE)  os << " ECHOE ";
391
  if (tios.c_lflag & ECHOK)  os << " ECHOK ";
392
  if (tios.c_lflag & ECHONL) os << " ECHONL";
393
  if (tios.c_lflag & ICANON) os << " ICANON";
394
  if (tios.c_lflag & IEXTEN) os << " IEXTEN";
395
  if (tios.c_lflag & ISIG)   os << " ISIG  ";
396
  if (tios.c_lflag & NOFLSH) os << " NOFLSH";
397
  if (tios.c_lflag & TOSTOP) os << " TOSTOP";
398
  os << endl;
399
 
400
  os << bl << "  c_cc    : " << endl;
401
  os << bl << "    [VEOF]  : " << RosPrintf(tios.c_cc[VEOF],"o",3);
402
  os       << "    [VEOL]  : " << RosPrintf(tios.c_cc[VEOL],"o",3);
403
  os       << "    [VERASE]: " << RosPrintf(tios.c_cc[VERASE],"o",3);
404
  os       << "    [VINTR] : " << RosPrintf(tios.c_cc[VINTR],"o",3)  << endl;
405
  os << bl << "    [VKILL] : " << RosPrintf(tios.c_cc[VKILL],"o",3);
406
  os       << "    [VQUIT] : " << RosPrintf(tios.c_cc[VQUIT],"o",3);
407
  os       << "    [VSUSP] : " << RosPrintf(tios.c_cc[VSUSP],"o",3);
408
  os       << "    [VSTART]: " << RosPrintf(tios.c_cc[VSTART],"o",3) << endl;
409
  os << bl << "    [VSTOP] : " << RosPrintf(tios.c_cc[VSTOP],"o",3);
410
  os       << "    [VMIN]  : " << RosPrintf(tios.c_cc[VMIN],"o",3);
411
  os       << "    [VTIME] : " << RosPrintf(tios.c_cc[VTIME],"o",3)  << endl;
412
 
413
  return;
414
}
415
 
416 19 wfjm
} // end namespace Retro

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.