API
netSerial.cpp
Go to the documentation of this file.
1 /** \file netSerial.cpp
2  * \brief Managing a connection to a serial device over a network socket.
3  * \author Jared R. Males (jaredmales@gmail.com)
4  *
5  * This code is taken from the LBTAO/MagAO supervisor source code, modifications
6  * mainly for c++.
7  *
8  * \ingroup tty_files
9  */
10 
11 #include "netSerial.hpp"
12 
13 #include <thread>
14 #include <chrono>
15 
16 #include <cstring>
17 #include <cerrno>
18 #include <sys/time.h>
19 
20 #include <unistd.h>
21 #include <sys/types.h>
22 #include <sys/socket.h>
23 #include <netdb.h>
24 #include <netinet/in.h>
25 
26 
27 namespace MagAOX
28 {
29 namespace tty
30 {
31 
32 
33 
34 int netSerial::serialInit( const char *address,
35  int port
36  )
37 {
38  struct sockaddr_in servaddr;
39 
40  serialClose();
41 
42  m_sockfd = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP);
43 
44  if(m_sockfd == -1)
45  {
46  return NETSERIAL_E_NETWORK;
47  }
48 
49  struct hostent *h = gethostbyname(address);
50 
51  servaddr.sin_family=AF_INET;
52  servaddr.sin_port=htons(port);
53  memcpy( &servaddr.sin_addr, h->h_addr_list[0], h->h_length);
54 
55  if(connect( m_sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0)
56  {
57  return NETSERIAL_E_CONNECT;
58  }
59 
60  return NETSERIAL_E_NOERROR;
61 }
62 
64 {
65  shutdown( m_sockfd, 2);
66  close(m_sockfd);
67 
68  return NETSERIAL_E_NOERROR;
69 }
70 
71 
72 int netSerial::serialOut( const char *buf,
73  int len
74  )
75 {
76  int i=0;
77 
78  while (i<len)
79  {
80  int stat = send( m_sockfd, buf+i, len-i, 0);
81  if (stat >0)
82  {
83  i+= stat;
84  }
85  if ((stat<0) && (stat != EAGAIN))
86  {
87  return NETSERIAL_E_COMM;
88  }
89  }
90 
91  return NETSERIAL_E_NOERROR;
92 }
93 
94 int netSerial::serialIn( char *buffer,
95  int len,
96  int timeout
97  )
98 {
99  int res=0;
100 
101  memset( buffer, 0, len);
102 
103  while (res < len)
104  {
105  fd_set rdfs;
106  struct timeval tv;
107  int retval;
108 
109  memset( &tv, 0, sizeof( struct timeval));
110  FD_ZERO( &rdfs);
111  FD_SET( m_sockfd, &rdfs);
112  tv.tv_sec = timeout / 1000;
113  tv.tv_usec = (timeout-(timeout/1000)*1000)*1000;
114 
115  retval = select( m_sockfd+1, &rdfs, NULL, NULL, &tv);
116  if (!retval)
117  return res;
118 
119  res += recv( m_sockfd, buffer+res, len-res, 0);
120 
121  std::this_thread::sleep_for(std::chrono::milliseconds(3));
122  }
123 
124  return res;
125 }
126 
127 int netSerial::serialInString( char *buffer,
128  int len,
129  int timeout,
130  char terminator
131  )
132 {
133  int res=0;
134  struct timeval tv0, tv1;
135  double t0, t1;
136 
137  memset( buffer, 0, len);
138 
139  #ifdef DEBUG
140  printf("initial timeout = %i\n", timeout);
141  #endif
142 
143  gettimeofday(&tv0, 0);
144  t0 = ((double)tv0.tv_sec + (double)tv0.tv_usec/1e6);
145 
146  gettimeofday(&tv1, 0);
147  t1 = ((double)tv1.tv_sec + (double)tv1.tv_usec/1e6);
148 
149  while (res < len && ((t1-t0)*1000. < timeout))
150  {
151  fd_set rdfs;
152  struct timeval tv;
153  int retval;
154 
155  memset( &tv, 0, sizeof( struct timeval));
156  FD_ZERO( &rdfs);
157  FD_SET( m_sockfd, &rdfs);
158  tv.tv_sec = timeout / 1000;
159  tv.tv_usec = (timeout-(timeout/1000)*1000)*1000;
160 
161  #ifdef DEBUG
162  printf("Selecting . . .\n");
163  #endif
164 
165  /* Making this a signal-safe call to select*/
166  /*JRM: otherwise, signals will cause select to return
167  causing this loop to never timeout*/
168 
169  int signaled = 1;
170 
171  retval = 0;
172 
173  while(signaled && ((t1-t0)*1000. < timeout))
174  {
175  errno = 0;
176  signaled = 0;
177  retval = select(m_sockfd+1, &rdfs, NULL, NULL, &tv);
178  if(retval < 0)
179  {
180  //This means select was interrupted by a signal, so keep going.
181  if(errno == EINTR)
182  {
183  #ifdef DEBUG
184  printf("EINTR\n");
185  #endif
186 
187  signaled = 1;
188  gettimeofday(&tv1, 0);
189  t1 = ((double)tv1.tv_sec + (double)tv1.tv_usec/1e6) ;
190  //Reset for smaller timeout
191  timeout = timeout - (t1-t0)*1000.;
192 
193  #ifdef DEBUG
194  printf("t1-t0 = %f\n", (t1-t0)*1000);
195  printf("timeout = %i\n", timeout);
196  #endif
197 
198  tv.tv_sec = timeout / 1000;
199  tv.tv_usec = (timeout-(timeout/1000)*1000)*1000;
200  if(tv.tv_sec < 0) tv.tv_sec = 0;
201  if(tv.tv_usec < 0) tv.tv_usec = 0;
202 
203  }
204  }
205  }
206 
207  #ifdef DEBUG
208  printf("select returned %i . . .\n", retval);
209  #endif
210 
211  if (retval <= 0) //this means we timed out or had an error
212  return res;
213 
214  #ifdef DEBUG
215  printf("Starting read . . .\n");
216  #endif
217 
218  res += recv( m_sockfd, buffer+res, len-res, 0);
219 
220  #ifdef DEBUG
221  printf("Read %i bytes. . .\n", res);
222  #endif
223 
224  buffer[res] =0;
225 
226  #ifdef DEBUG
227  printf("SerialInString received %d bytes: %s\n", res, buffer);
228  #endif
229 
230  if (strchr( buffer, terminator)) return res;
231 
232  gettimeofday(&tv1, 0);
233  t1 = ((double)tv1.tv_sec + (double)tv1.tv_usec/1e6);
234 
235  #ifdef DEBUG
236  printf("t1-t0 = %f\n", (t1-t0)*1000.);
237  printf("timeout = %i\n", timeout);
238  #endif
239 
240  std::this_thread::sleep_for(std::chrono::milliseconds(3));
241  }
242 
243 
244  #ifdef DEBUG
245  int i;
246  printf("SerialIn(): received %d characters:\n", res);
247 
248  for ( i=0; i<res; i++) printf("0x%02X ", (unsigned char) buffer[i]);
249  printf("\n");
250  #endif
251 
252  return res;
253 }
254 
256 {
257  return m_sockfd;
258 }
259 
260 } // namespace tty
261 } // namespace MagAOX
262 
Definition: dm.hpp:24
Managing a connection to a serial device over a network socket.
#define NETSERIAL_E_NOERROR
Definition: netSerial.hpp:14
#define NETSERIAL_E_CONNECT
Definition: netSerial.hpp:16
#define NETSERIAL_E_NETWORK
Definition: netSerial.hpp:15
#define NETSERIAL_E_COMM
Definition: netSerial.hpp:17
int serialIn(char *buf, int len, int timeout)
Definition: netSerial.cpp:94
int serialOut(const char *buf, int len)
Definition: netSerial.cpp:72
int serialInString(char *buf, int len, int timeout, char terminator)
Definition: netSerial.cpp:127
int serialInit(const char *address, int port)
Definition: netSerial.cpp:34