Dynamixel  2.9.5
RoadNarrows Robotics Dynamixel Package
dxlhal.cxx
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // Package: Dynamixel
4 //
5 // Library: libdxl
6 //
7 // File: dxl_hal.c
8 //
9 /*! \file
10  *
11  * \brief Dynamixel Hardware Abstraction Layer implementation.
12  *
13  * Based on Robotis Inc. dxl_sdk-1.01
14  *
15  * \author Robotis
16  * \author Robin Knight (robin.knight@roadnarrows.com)
17  */
18 /*
19  * This file is a modified version of the file freely provided by Robotis Inc.
20  * No restrictions by Robotis Inc. nor RoadNarrows LLC are made.
21  */
22 ////////////////////////////////////////////////////////////////////////////////
23 
24 #include <sys/ioctl.h>
25 #include <sys/time.h>
26 #include <sys/types.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include <time.h>
31 #include <fcntl.h>
32 #include <termios.h>
33 #include <linux/serial.h>
34 
35 #include <string>
36 
37 #include "rnr/rnrconfig.h"
38 #include "rnr/log.h"
39 #include "rnr/serdev.h"
40 
41 #include "dxlhal.h"
42 
43 using namespace std;
44 using namespace libdxl;
45 
46 dxlhal::dxlhal()
47 {
48  m_nBaudRate = 0;
49  m_fd = -1;
50  m_fSecPerByte = 0.0;
51  m_fStartTime = 0;
52  m_fRcvWaitTime = 0.0;
53 }
54 
55 dxlhal::~dxlhal()
56 {
57  close();
58 }
59 
60 int dxlhal::open(const char *deviceName, int baudrate)
61 {
62  close();
63 
64  m_strDeviceName = deviceName;
65  m_nBaudRate = baudrate;
66 
67  m_fd = SerDevOpen(m_strDeviceName.c_str(), baudrate, 8, 'N', 1, false, false);
68 
69  if( m_fd >= 0 )
70  {
71  m_fSecPerByte = calcSecPerByte(baudrate);
72 
73  return 1;
74  }
75  else
76  {
77  LOGSYSERROR("%s: Failed to open.", m_strDeviceName.c_str());
78 
79  m_strDeviceName.clear();
80  m_nBaudRate = 0;
81 
82  return 0;
83  }
84 }
85 
86 int dxlhal::dxl_hal_open(int deviceIndex, float baudrate)
87 {
88  char buf[256];
89  struct termios newtio;
90  struct serial_struct serinfo;
91 
92  close();
93 
94  snprintf(buf, sizeof(buf), "/dev/ttyUSB%d", deviceIndex);
95 
96  buf[sizeof(buf)-1] = 0;
97 
98  m_strDeviceName = buf;
99  m_nBaudRate = baudrate;
100 
101  memset(&newtio, 0, sizeof(newtio));
102 
103  if( (m_fd = open(m_strDeviceName.c_str(), O_RDWR|O_NOCTTY|O_NONBLOCK)) < 0 )
104  {
105  LOGSYSERROR("%s: Device open error.", m_strDeviceName.c_str());
106  goto DXL_HAL_OPEN_ERROR;
107  }
108 
109  newtio.c_cflag = B38400|CS8|CLOCAL|CREAD;
110  newtio.c_iflag = IGNPAR;
111  newtio.c_oflag = 0;
112  newtio.c_lflag = 0;
113  newtio.c_cc[VTIME] = 0; // time-out 값 (TIME * 0.1초) 0 : disable
114  newtio.c_cc[VMIN] = 0; // MIN 은 read 가 return 되기 위한 최소 문자 개수
115 
116  tcflush(m_fd, TCIFLUSH);
117  tcsetattr(m_fd, TCSANOW, &newtio);
118 
119  if(ioctl(m_fd, TIOCGSERIAL, &serinfo) < 0)
120  {
121  LOGSYSERROR("%s(fd=%d): Cannot get serial info.",
122  m_strDeviceName.c_str(), m_fd);
123  return 0;
124  }
125 
126  serinfo.flags &= (int)(~ASYNC_SPD_MASK);
127  serinfo.flags |= (int)ASYNC_SPD_CUST;
128  serinfo.custom_divisor = (int)((float)serinfo.baud_base / baudrate);
129 
130  if(ioctl(m_fd, TIOCSSERIAL, &serinfo) < 0)
131  {
132  LOGSYSERROR("%s(fd=%d): Cannot set serial info.",
133  m_strDeviceName.c_str(), m_fd);
134  goto DXL_HAL_OPEN_ERROR;
135  }
136 
137  m_fSecPerByte = calcSecPerByte(baudrate);
138 
139  return 1;
140 
141 DXL_HAL_OPEN_ERROR:
142  close();
143  return 0;
144 }
145 
146 void dxlhal::close()
147 {
148  if( m_fd != -1 )
149  {
150  ::close(m_fd);
151  }
152 
153  m_strDeviceName.clear();
154  m_nBaudRate = 0;
155  m_fd = -1;
156 }
157 
158 string dxlhal::getDeviceName()
159 {
160  return m_strDeviceName;
161 }
162 
163 int dxlhal::getBaudRate()
164 {
165  return m_nBaudRate;
166 }
167 
168 int dxlhal::getFd()
169 {
170  return m_fd;
171 }
172 
173 int dxlhal::setBaudRate(int baudrate)
174 {
175  struct serial_struct serinfo;
176 
177  if( m_fd == -1 )
178  {
179  return 0;
180  }
181 
182  if(ioctl(m_fd, TIOCGSERIAL, &serinfo) < 0)
183  {
184  LOGERROR("%s(fd=%d): Cannot get serial info.",
185  m_strDeviceName.c_str(), m_fd);
186  return 0;
187  }
188 
189  serinfo.flags &= (int)(~ASYNC_SPD_MASK);
190  serinfo.flags |= (int)ASYNC_SPD_CUST;
191  serinfo.custom_divisor = (int)((float)serinfo.baud_base / (float)baudrate);
192 
193  if(ioctl(m_fd, TIOCSSERIAL, &serinfo) < 0)
194  {
195  LOGERROR("%s(fd=%d): Cannot set serial info.",
196  m_strDeviceName.c_str(), m_fd);
197  return 0;
198  }
199 
200  m_fSecPerByte = calcSecPerByte(baudrate);
201 
202  m_nBaudRate = baudrate;
203 
204  return 1;
205 }
206 
207 void dxlhal::clear(void)
208 {
209  tcflush(m_fd, TCIFLUSH);
210 }
211 
212 int dxlhal::tx( unsigned char *pPacket, int numPacket )
213 {
214  ssize_t n;
215 
216  n = SerDevWrite(m_fd, pPacket, (size_t)numPacket, 0);
217 
218  if( n > 0 )
219  {
220  return (int)n;
221  }
222  else
223  {
224  LOGERROR("tx failed.");
225  return 0;
226  }
227 }
228 
229 int dxlhal::rx(unsigned char *pPacket, int numPacket)
230 {
231  static unsigned int Slop = 1000; // 1 millisecond slop
232 
233  unsigned int usec;
234  ssize_t n;
235 
236  memset(pPacket, 0, (size_t)numPacket);
237 
238  usec = (unsigned int)((double)numPacket * m_fSecPerByte * 1000000.0) + Slop;
239 
240  //fprintf(stderr, "DBG: rx wait time for %d bytes is %uus.\n",
241  // numPacket, usec);
242 
243  n = SerDevRead(m_fd, pPacket, (size_t)numPacket, usec);
244 
245  return n < 0? 0: (int)n;
246 }
247 
248 void dxlhal::setTimeout(int NumRcvByte)
249 {
250  static double Fudge = 0.010; // yea ol fudge factor
251 
252  m_fStartTime = now();
253 
254  m_fRcvWaitTime = m_fSecPerByte * (double)NumRcvByte + MAX_T_RTD + Fudge;
255 
256  //fprintf(stderr, "DBG: to wait time = %lfs from now = %lfs.\n",
257  // m_fRcvWaitTime, m_fStartTime);
258 }
259 
260 bool dxlhal::hasTimedOut()
261 {
262  double t1, t;
263 
264  t1 = now();
265  t = t1 - m_fStartTime;
266 
267  //fprintf(stderr, "DBG: st=%lf, now=%lf, elapse=%lf\n", m_fStartTime, t1, t);
268 
269  if( t > m_fRcvWaitTime )
270  {
271  return true;
272  }
273 
274  else
275  {
276  return false;
277  }
278 }
279 
280 double dxlhal::now()
281 {
282  struct timespec ts;
283 
284  clock_gettime(CLOCK_REALTIME, &ts);
285 
286  return (double)ts.tv_sec + (double)ts.tv_nsec / 1000000000.0;
287 }
288 
289 double dxlhal::calcSecPerByte(int baudrate)
290 {
291  if( baudrate > 0 )
292  {
293  return 10.0/(double)baudrate;
294  }
295  else
296  {
297  return 0.0;
298  }
299 }
Dynamixel Hardware Abstraction Layer implementation interface.
#define MAX_T_RTD
maximum time delay at maximum RTD
Definition: dxlhal.h:36
Definition: t.py:1
Definition: dxl.h:32