SoDaRadio-5.0.3-master:8901fb5
SerialDev.cxx
Go to the documentation of this file.
1 /*
2  Copyright (c) 2015, Matthew H. Reilly (kb1vc)
3  All rights reserved.
4 
5  Redistribution and use in source and binary forms, with or without
6  modification, are permitted provided that the following conditions are
7  met:
8 
9  Redistributions of source code must retain the above copyright
10  notice, this list of conditions and the following disclaimer.
11  Redistributions in binary form must reproduce the above copyright
12  notice, this list of conditions and the following disclaimer in
13  the documentation and/or other materials provided with the
14  distribution.
15 
16  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20  HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28 
29 #include "SerialDev.hxx"
30 #include <boost/format.hpp>
31 #include <boost/asio.hpp>
32 #include <math.h>
33 #include <stdexcept>
34 
35 
36 #include <stdio.h>
37 #include <unistd.h>
38 #include <fcntl.h>
39 #include <errno.h>
40 #include <termios.h>
41 #include <time.h>
42 
43 // Boost free implementation of serial IO.
44 
45 namespace SoDa
46 {
47 
48 
49  SerialDev::SerialDev(const std::string & devname,
50  unsigned int speed,
51  bool par_ena,
52  bool par_even)
53  {
54  port = open(devname.c_str(), O_RDWR | O_NOCTTY | O_NDELAY);
55 
56  if(port == -1) {
57  // failed to open the port. Throw an exception
58  throw std::runtime_error((boost::format("Failed to open serial port [%s]\n") % devname).str());
59  }
60 
61  // now set the speeds and such.
62  fcntl(port, F_SETFL, 0);
63 
64  struct termios port_settings;
65 
66  cfsetispeed(&port_settings, getSpeed(speed));
67  cfsetospeed(&port_settings, getSpeed(speed));
68 
69  cfmakeraw(&port_settings);
70 
71  if(par_ena) {
72  port_settings.c_cflag |= PARENB;
73  if(par_even) {
74  port_settings.c_cflag &= ~PARODD;
75  }
76  else {
77  port_settings.c_cflag |= PARODD;
78  }
79  }
80  else port_settings.c_cflag &= ~PARENB;
81 
82 
83 
84  port_settings.c_cflag &= ~CSTOPB;
85  port_settings.c_cflag &= ~CSIZE;
86  port_settings.c_cflag |= CS8;
87 
88  port_settings.c_lflag &= ~ECHO;
89  // port_settings.c_lflag &= ~ECHOK;
90  // port_settings.c_lflag &= ~ECHOE;
91  // port_settings.c_lflag &= ~ECHONL;
92  // port_settings.c_lflag &= ~NOFLSH;
93  // port_settings.c_lflag &= ~XCASE;
94  // port_settings.c_lflag &= ~TOSTOP;
95  // port_settings.c_lflag &= ~ECHOPRT;
96  // port_settings.c_lflag &= ~ECHOCTL;
97  // port_settings.c_lflag &= ~ECHOKE;
98 
99  port_settings.c_lflag &= ~ICANON;
100 
101  port_settings.c_cc[VMIN] = 0;
102  port_settings.c_cc[VTIME] = 0;
103 
104  tcsetattr(port, TCSANOW, &port_settings);
105  }
106 
107 
108  bool SerialDev::putString(const std::string & str)
109  {
110  if(!serial_port_open) return false;
111 
112  write(port, str.c_str(), str.size());
113 
114  return true;
115  }
116 
117  bool SerialDev::getString(std::string & str, unsigned int maxlen)
118  {
119  (void) maxlen;
120  if(!serial_port_open) return false;
121 
122  str = std::string("");
123  char c;
124  int itercount = 0;
125  while(1) {
126  int len;
127  c = '\000';
128  len = read(port, &c, 1);
129  if(len == 1) {
130  switch(c) {
131  case '\r': break;
132  case '\n': return true;
133  default: str += c;
134  }
135  itercount = 0;
136  }
137  else if(len < 0) {
138  std::cerr << boost::format("read returned %d errno = %d\n")
139  % len % errno;
140  }
141  else if(len == 0) {
142  usleep(1000);
143  itercount++;
144  if (itercount > 100000) {
145  std::cerr << itercount << std::endl;
146  return false;
147  }
148  }
149  }
150  }
151 
152  int SerialDev::getSpeed(int sp)
153  {
154  switch(sp) {
155  case 9600: return B9600;
156  case 2400: return B2400;
157  case 4800: return B4800;
158  case 19200: return B19200;
159  case 38400: return B38400;
160  case 57600: return B57600;
161  case 115200: return B115200;
162  default: return B9600;
163  }
164  }
165 
166 
168  tcflush(port, TCIFLUSH);
169  return true;
170  }
171 
173  tcflush(port, TCOFLUSH);
174  return true;
175  }
176 
177 
178  bool SerialDev::palindromeCommand(std::string & str)
179  {
180  std::string resp;
181  int stlen = str.size();
182 
183  std::string exp = (boost::format("OK [%s]") % (str.substr(0, stlen-1))).str();
184 
185  putString(str);
186  int i;
187  for(i = 0; i < 10; i++) { // 10 retries
188  std::cerr << boost::format("loop %d start\n") % i;
189  while(!getString(resp, stlen + 5)) {
190  usleep(1000);
191  }
192  int v;
193  if((v = exp.compare(0, stlen + 3, resp)) == 0) {
194  std::cerr << "YAY!" << std::endl;
195  return true;
196  }
197  else {
198  std::cerr << boost::format("Expected [%s] got [%s]. stlen = %d compare = %d\n")
199  % exp % resp % stlen % v;
200  int j;
201  for(j = 0; j < stlen+5; j++) {
202  int cmp = (exp[i] == resp[i]);
203  std::cerr << boost::format("%c %c (%d %d) =? %d\n")
204  % exp[j] % resp[j] % ((int) exp[j]) % ((int) resp[j]) % cmp;
205  }
206  flushInput();
207  if(resp.compare(0, 3, "BAD") == 0) {
208  std::cerr << "flushing input buffer" << std::endl;
209  flushInput();
210  }
211  std::cerr << boost::format("Resend [%s]\n") % str;
212  putString(str);
213  std::cerr << boost::format("loop %d end\n") % i;
214  }
215  }
216 
217  return false;
218  }
219 }
bool getString(std::string &str, unsigned int maxlen)
Definition: SerialDev.cxx:117
SerialDev(const std::string &devname, unsigned int speed=9600, bool par_ena=false, bool par_even=true)
Definition: SerialDev.cxx:49
bool serial_port_open
Definition: SerialDev.hxx:55
bool flushOutput()
Definition: SerialDev.cxx:172
int getSpeed(int spd)
Definition: SerialDev.cxx:152
bool palindromeCommand(std::string &str)
Definition: SerialDev.cxx:178
bool putString(const std::string &str)
Definition: SerialDev.cxx:108