MRPT  1.9.9
serialinterface.cpp
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | http://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2018, Individual contributors, see AUTHORS file |
6  | See: http://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See details in http://www.mrpt.org/License |
8  +------------------------------------------------------------------------+ */
9 #include "serialinterface.h"
10 #include <xsens/xsportinfo.h>
11 #include <xsens/xscontrolline.h>
12 
13 #include <errno.h>
14 #ifndef _WIN32
15 #include <unistd.h> // close
16 #include <sys/ioctl.h> // ioctl
17 #include <fcntl.h> // open, O_RDWR
18 #include <string.h> // strcpy
19 #include <sys/param.h>
20 #include <sys/file.h>
21 #include <stdarg.h>
22 #else
23 #include <winbase.h>
24 #include <io.h>
25 #endif
26 
27 #ifndef _CRT_SECURE_NO_DEPRECATE
28 #define _CRT_SECURE_NO_DEPRECATE
29 #ifdef _WIN32
30 #pragma warning(disable : 4996)
31 #endif
32 #endif
33 
34 // lint -emacro(534, FSEEK, FSEEK_R)
35 // lint -emacro({534}, FSEEK, FSEEK_R)
36 #ifdef _WIN32
37 #define FSEEK(x) _fseeki64(m_handle, x, SEEK_SET)
38 #define FSEEK_R(x) _fseeki64(m_handle, x, SEEK_END)
39 #define FTELL() _ftelli64(m_handle)
40 #else
41 #define FSEEK(x) fseeko(m_handle, x, SEEK_SET)
42 #define FSEEK_R(x) fseeko(m_handle, x, SEEK_END)
43 #define FTELL() ftello(m_handle)
44 #endif
45 
46 // maybe log to nothing at this level
47 #ifdef LOG_CMT1
48 #include "xslog.h"
49 #define XDA1LOG_OBSOLETE XSENSLOG
50 #else
51 #define XDA1LOG_OBSOLETE(...) (void)0
52 #endif
53 
54 //////////////////////////////////////////////////////////////////////////////////////////
55 ///////////////////////////////////////// SerialInterface
56 ////////////////////////////////////////////
57 //////////////////////////////////////////////////////////////////////////////////////////
58 
59 //! \brief Default constructor, initializes all members to their default values.
61 {
62  m_port = 0;
64  m_timeout = 0;
65  m_endTime = 0;
67  m_portname[0] = 0;
68 #ifdef _WIN32
69  m_handle = INVALID_HANDLE_VALUE;
70 #else
71  m_handle = -1;
72  memset(&m_commState, 0, sizeof(m_commState));
73 #endif
74 
75  rx_log = nullptr;
76  tx_log = nullptr;
77 }
78 
79 //! Destructor, de-initializes, frees memory allocated for buffers, etc.
81 {
82  try
83  {
84  closeLive(); // lint !e534
85  }
86  catch (...)
87  {
88  }
89 }
90 
91 //! \brief Close the serial communication port.
93 //! \brief Close the serial communication port.
95 {
96 #ifdef LOG_RX_TX
97  if (rx_log != nullptr) fclose(rx_log);
98  if (tx_log != nullptr) fclose(tx_log);
99  rx_log = nullptr;
100  tx_log = nullptr;
101 #endif
102  if (!isOpen()) return m_lastResult = XRV_NOPORTOPEN;
103 
105 #ifdef _WIN32
106  if (::FlushFileBuffers(m_handle))
107  {
108  // read all data before closing the handle, a Flush is not enough for
109  // FTDI devices unfortunately
110  // we first need to set the COMM timeouts to instantly return when no
111  // more data is available
112  COMMTIMEOUTS cto;
113  if (::GetCommTimeouts(m_handle, &cto))
114  {
115  cto.ReadIntervalTimeout = MAXDWORD;
116  cto.ReadTotalTimeoutConstant = 0;
117  cto.ReadTotalTimeoutMultiplier = 0;
118  if (::SetCommTimeouts(m_handle, &cto))
119  {
120  char buffer[1024];
121  DWORD length;
122  do
123  {
124  if (!::ReadFile(m_handle, buffer, 1024, &length, nullptr))
125  break;
126  } while (length > 0);
127  }
128  else
130  }
131  else
133  }
134  if (!::CloseHandle(m_handle)) m_lastResult = XRV_ERROR;
135  m_handle = INVALID_HANDLE_VALUE;
136 #else
137  flushData();
138  ::close(m_handle);
139  m_handle = -1;
140 #endif
141  m_endTime = 0;
142 
143  return m_lastResult;
144 }
145 
146 /*! \brief Manipulate the Serial control lines
147 
148  The function manipulates the serial control lines that are indicated by the
149  mask parameter. Note that only the DTR and RTS lines can be set by win32.
150  \param mask Indicates which lines are to be manipulated and which
151  should be
152  left alone.
153  \param state Contains the new state of the control lines.
154  \returns XRV_OK if the function succeeded
155 */
157  const XsControlLine mask, const XsControlLine state)
158 {
159  // lint --e{655} bitwise operations are intended on these enums
160  if (!isOpen()) return (m_lastResult = XRV_NOPORTOPEN);
161 #ifdef _WIN32
162  BOOL rv = 0;
163  if (mask & XCL_DTR)
164  {
165  if (state & XCL_DTR)
166  rv = EscapeCommFunction(m_handle, SETDTR);
167  else
168  rv = EscapeCommFunction(m_handle, CLRDTR);
169  }
170 
171  if (mask & XCL_RTS)
172  {
173  if (state & XCL_RTS)
174  rv = EscapeCommFunction(m_handle, SETRTS);
175  else
176  rv = EscapeCommFunction(m_handle, CLRRTS);
177  }
178  if (rv)
179  return m_lastResult = XRV_OK;
180  else
181  return m_lastResult = XRV_ERROR;
182 #else
183  bool rv = true;
184  int32_t status;
185  if (mask & XCL_DTR)
186  {
187  if (ioctl(m_handle, TIOCMGET, &status) == -1)
188  {
189  if (state & XCL_DTR)
190  status |= TIOCM_DTR;
191  else
192  status &= ~TIOCM_DTR;
193  rv = (ioctl(m_handle, TIOCMSET, &status) == -1);
194  }
195  else
196  rv = false;
197  }
198  if (rv && (mask & XCL_RTS))
199  {
200  if (ioctl(m_handle, TIOCMGET, &status) == -1)
201  {
202  if (state & XCL_RTS)
203  status |= TIOCM_RTS;
204  else
205  status &= ~TIOCM_RTS;
206  rv = (ioctl(m_handle, TIOCMSET, &status) == -1);
207  }
208  else
209  rv = false;
210  }
211  if (rv)
212  return m_lastResult = XRV_OK;
213  else
214  return m_lastResult = XRV_ERROR;
215 #endif
216 }
217 
218 /*! \copydoc IoInterface::flushData
219  \note This function tries to send and receive any remaining data immediately
220  and does not return until the buffers are empty.
221 */
223 {
225 #ifdef _WIN32
226  // Remove any 'old' data in buffer
227  if (!PurgeComm(m_handle, PURGE_TXCLEAR | PURGE_RXCLEAR))
229 #else
230  tcflush(m_handle, TCIOFLUSH);
231 #endif
232  m_endTime = 0;
233  return m_lastResult;
234 }
235 
236 //! Return the baudrate that is currently being used by the port
238 {
239  if (isOpen()) return m_baudrate;
240  return XBR_Invalid;
241 }
242 //! Return the handle of the port
244 //! Retrieve the port number that was last successfully opened.
246 //! Retrieve the port name that was last successfully opened.
248 {
249  portname = m_portname;
250 }
251 //! Return the error code of the last operation.
253 {
254  return m_lastResult;
255 }
256 //! Return the current timeout value
258 //! Return whether the communication port is open or not.
259 bool SerialInterface::isOpen(void) const
260 {
261 #ifdef _WIN32
262  return m_handle != INVALID_HANDLE_VALUE;
263 #else
264  return m_handle >= 0;
265 #endif
266 }
267 
268 /*! \brief Open a communication channel to the given port info.
269  \details If the baudrate in \a portInfo is set to XBR_Invalid, the baud rate
270  is automatically
271  detected if possible.
272  \param portInfo The details of the port that should be opened. Depending on
273  the type of interface,
274  parts of this parameter may be ignored.
275  \param readBufSize The size of the read buffer in bytes (if appliccable to
276  the device)
277  \param writeBufSize The size of the write buffer in bytes (if appliccable to
278  the device)
279  \returns XRV_OK if the device was opened successfully
280 */
282  const XsPortInfo& portInfo, uint32_t readBufSize, uint32_t writeBufSize)
283 {
284  m_endTime = 0;
285 
286  JLDEBUG(
287  gJournal, "port " << portInfo.portName().toStdString() << " at "
288  << portInfo.baudrate() << " baud");
289 
290  if (isOpen())
291  {
292  JLALERT(
293  gJournal, "Port " << portInfo.portName().toStdString()
294  << " is already open");
295  return (m_lastResult = XRV_ALREADYOPEN);
296  }
297  m_baudrate = portInfo.baudrate();
298 
299 #ifdef _WIN32
300  XsResultValue fail = XRV_OK;
301  char winPortName[256];
302 
303  // Open port
304  sprintf(winPortName, "\\\\.\\%s", portInfo.portName().c_str());
305  m_handle = CreateFileA(
306  winPortName, GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0,
307  nullptr);
308  if (m_handle == INVALID_HANDLE_VALUE)
309  {
310  JLDEBUG(
311  gJournal, "Port " << portInfo.portName().toStdString()
312  << " cannot be opened");
314  }
315 
316  /** Stored settings about the serial port */
317  DCB commState;
318 
319  commState.DCBlength = sizeof(DCB);
320 
321  // Get the current state & then change it
322  if (!GetCommState(m_handle, &commState)) // Get current state
323  fail = XRV_ERROR;
324 
325  commState.BaudRate = (int)portInfo.baudrate(); // Setup the baud rate
326  commState.Parity = NOPARITY; // Setup the Parity
327  commState.ByteSize = 8; // Setup the data bits
328  commState.StopBits = TWOSTOPBITS; // Setup the stop bits
329  commState.fDsrSensitivity = FALSE; // Setup the flow control
330  commState.fOutxCtsFlow = FALSE; // NoFlowControl:
331  commState.fOutxDsrFlow = FALSE;
332  commState.fOutX = FALSE;
333  commState.fInX = FALSE;
334  commState.fRtsControl = RTS_CONTROL_ENABLE;
335  if (!SetCommState(m_handle, (LPDCB)&commState)) // Set new state
336  {
337  // Bluetooth ports cannot always be opened with 2 stopbits
338  // Now try to open port with 1 stopbit.
339  commState.StopBits = ONESTOPBIT;
340  if (!SetCommState(m_handle, (LPDCB)&commState))
342  }
343  std::string tmp = portInfo.portName().toStdString();
344  m_port = atoi(&tmp.c_str()[3]);
345  sprintf(m_portname, "%s", tmp.c_str());
346 
347  if (setTimeout(20)) fail = m_lastResult;
348 
349  // Other initialization functions
350  if (!EscapeCommFunction(m_handle, SETDTR)) // Set DTR (Calibration sensors
351  // need DTR to startup, won't
352  // hurt otherwise
353  fail = XRV_ERROR;
354  if (!SetupComm(m_handle, readBufSize, writeBufSize)) // Set queue size
355  fail = XRV_ERROR;
356 
357  // Remove any 'old' data in buffer
358  // PurgeComm(m_handle, PURGE_TXCLEAR | PURGE_RXCLEAR);
359  if (!PurgeComm(
360  m_handle,
361  PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR))
362  fail = XRV_ERROR;
363 
364  if (fail != XRV_OK)
365  {
366  CloseHandle(m_handle); // lint !e534
367  m_handle = INVALID_HANDLE_VALUE;
368  return (m_lastResult = fail);
369  }
370 
371 #else // !_WIN32
372  (void)readBufSize;
373  (void)writeBufSize;
374  // Open port
375  std::string pn = portInfo.portName().toStdString();
376  m_handle = ::open(pn.c_str(), O_RDWR | O_NOCTTY);
377 
378  // O_RDWR: Read+Write
379  // O_NOCTTY: Raw input, no "controlling terminal"
380  // O_NDELAY: Don't care about DCD signal
381 
382  if (m_handle < 0)
383  {
384  // Port not open
386  }
387 
388  // Check if the file is already opened by someome else (other
389  // thread/process)
390  if (flock(m_handle, LOCK_EX | LOCK_NB))
391  {
392  closeLive();
394  }
395 
396  /* Start configuring of port for non-canonical transfer mode */
397  // Get current options for the port
398  if (tcgetattr(m_handle, &m_commState) != 0) return XRV_ERROR;
399 
400  // Set baudrate.
401  if (cfsetispeed(&m_commState, portInfo.baudrate()) != 0) return XRV_ERROR;
402 
403  if (cfsetospeed(&m_commState, portInfo.baudrate()) != 0) return XRV_ERROR;
404 
405  // Enable the receiver and set local mode
406  m_commState.c_cflag |= (CLOCAL | CREAD);
407  // Set character size to data bits and set no parity Mask the characte size
408  // bits
409  m_commState.c_cflag &= ~(CSIZE | PARENB);
410  m_commState.c_cflag |= CS8; // Select 8 data bits
411  m_commState.c_cflag |= CSTOPB; // send 2 stop bits
412  // Disable hardware flow control
413  m_commState.c_cflag &= ~CRTSCTS;
414  m_commState.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
415  // Disable software flow control
416  m_commState.c_iflag &=
417  ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
418  // Set Raw output
419  m_commState.c_oflag &= ~OPOST;
420  // Timeout 0.001 sec for first byte, read minimum of 0 bytes
421  m_commState.c_cc[VMIN] = 0;
422  m_commState.c_cc[VTIME] = (m_timeout + 99) / 100; // 1
423 
424  // Set the new options for the port
425  if (tcsetattr(m_handle, TCSANOW, &m_commState) != 0)
427 
428  termios checkCommState;
429  if (tcgetattr(m_handle, &checkCommState) != 0) return XRV_ERROR;
430 
431  if ((m_commState.c_cflag != checkCommState.c_cflag) ||
432  (m_commState.c_iflag != checkCommState.c_iflag) ||
433  (m_commState.c_oflag != checkCommState.c_oflag) ||
434  (m_commState.c_cc[VMIN] != checkCommState.c_cc[VMIN]) ||
435  (m_commState.c_cc[VTIME] != checkCommState.c_cc[VTIME]))
436  {
437  JLDEBUG(
438  gJournal,
439  "commstates do not match, which is OK for USB connected MkIV "
440  "devices");
441  }
442 
443  m_port = 1;
444  sprintf(m_portname, "%s", pn.c_str());
445 
446  tcflush(m_handle, TCIOFLUSH);
447 
448  // setting RTS and DTR; RTS for Xbus Master, DTR for calibration sensors
449  int cmbits;
450  if (ioctl(m_handle, TIOCMGET, &cmbits) < 0)
451  {
452  JLDEBUG(
453  gJournal,
454  "TIOCMGET failed, which is OK for USB connected MkIV devices");
455  }
456 
457  cmbits |= TIOCM_RTS | TIOCM_DTR;
458 
459  if (ioctl(m_handle, TIOCMSET, &cmbits) < 0)
460  {
461  JLDEBUG(
462  gJournal,
463  "TIOCMSET failed, which is OK for USB connected MkIV devices");
464  }
465 #endif // !_WIN32
466 
467  JLDEBUG(
468  gJournal, "Port " << portInfo.portName().toStdString() << " opened");
469  return (m_lastResult = XRV_OK);
470 }
471 
472 /*! \brief Helper function for making filename of log file unique
473 */
474 bool doesFileExist(char* filename)
475 {
476  FILE* pf = fopen(filename, "r");
477  if (pf == nullptr) return false;
478  fclose(pf);
479  return true;
480 }
481 
482 /*! \brief Helper function for making filename of log file unique
483 */
484 void makeFilenameUnique(char* filename)
485 {
486  if (doesFileExist(filename)) // if a file already exist with the same name,
487  {
488  // create a unique filename by adding a counter:
489  char filename2[XS_MAX_FILENAME_LENGTH];
490  char basename[XS_MAX_FILENAME_LENGTH];
491  strcpy(basename, filename);
492  basename[strlen(basename) - 4] = 0; // remove .log extension
493  int counter = 1;
494  do
495  {
496  sprintf(filename2, "%s_%d.log", basename, counter++);
497  if (counter > 10) // don't count further than 10
498  {
499  sprintf(filename2, "%s_n.log", basename);
500  break;
501  }
502  } while (doesFileExist(filename2));
503  strcpy(filename, filename2);
504  }
505 }
506 
507 /*! \brief Read data from the serial port and put it into the data buffer.
508  \details This function reads up to \a maxLength bytes from the port
509  (non-blocking) and
510  puts it into the \a data buffer.
511  \param maxLength The maximum amount of data read.
512  \param data The buffer that will store the received data.
513  \returns XRV_OK if no error occurred. It can be that no data is available
514  and XRV_OK will be
515  returned. Check data.size() for the number of bytes that were read.
516 */
518 {
519  if (!isOpen()) return (m_lastResult = XRV_NOPORTOPEN);
520 
521 #ifdef _WIN32
522  DWORD length;
523  data.setSize(maxLength);
524  BOOL rres =
525  ::ReadFile(m_handle, data.data(), (DWORD)maxLength, &length, nullptr);
526  data.pop_back(maxLength - length);
527  JLTRACE(gJournal, "ReadFile result " << rres << ", length " << length);
528 
529  if (!rres)
530  {
531  DWORD wErr = ::GetLastError();
532  JLALERT(gJournal, "ReadFile returned windows error " << wErr);
533  if (wErr >= ERROR_INVALID_FUNCTION && wErr <= ERROR_INVALID_HANDLE)
535  return (m_lastResult = XRV_ERROR);
536  }
537 
538  if (length == 0) return (m_lastResult = XRV_TIMEOUT);
539 #else
540  fd_set fd;
541  fd_set err;
542  timeval timeout;
543  FD_ZERO(&fd);
544  FD_ZERO(&err);
545  FD_SET(m_handle, &fd);
546  FD_SET(m_handle, &err);
547 
548  timeout.tv_sec = m_timeout / 1000;
549  timeout.tv_usec = (m_timeout - (timeout.tv_sec * 1000)) * 1000;
550 
551  int res = select(FD_SETSIZE, &fd, nullptr, &err, &timeout);
552  if (res < 0 || FD_ISSET(m_handle, &err))
553  {
554  data.clear();
555  return (m_lastResult = XRV_ERROR);
556  }
557  else if (res == 0)
558  {
559  data.clear();
560  return (m_lastResult = XRV_TIMEOUT);
561  }
562 
563  data.setSize(maxLength);
564  int length = read(m_handle, (void*)data.data(), maxLength);
565  data.pop_back(maxLength - length);
566 #endif
567 
568 #ifdef LOG_RX_TX
569  if (length > 0)
570  {
571  if (rx_log == nullptr)
572  {
573  char fname[XS_MAX_FILENAME_LENGTH];
574 #ifdef _WIN32
575  sprintf(fname, "rx_%03d_%d.log", (int32_t)m_port, m_baudrate);
576 #else
577  char* devname = strrchr(m_portname, '/');
578  sprintf(
579  fname, "rx_%s_%d.log", devname + 1,
580  XsBaud::rateToNumeric(m_baudrate));
581 #endif
582  makeFilenameUnique(fname);
583 
584  rx_log = fopen(fname, "wb");
585  }
586  fwrite(data.data(), 1, length, rx_log);
587 #ifdef LOG_RX_TX_FLUSH
588  fflush(rx_log);
589 #endif
590  }
591 #endif
592 
593  JLTRACE(
594  gJournal, "returned success, read "
595  << length << " of " << maxLength
596  << " bytes, first: " << JLHEXLOG(data[0]));
597  return (m_lastResult = XRV_OK);
598 }
599 
600 /*! \brief Set the default timeout value to use in blocking operations.
601  \details This function sets the value of m_timeout. There is no infinity
602  value. The value 0
603  means that all blocking operations now become polling (non-blocking)
604  operations.
605  If the value is set to or from 0, the low-level serial port settings may be
606  changed in addition to the m_timeout value.
607  \param ms The new timeout in milliseconds
608  \returns XRV_OK if the function succeeded
609 */
611 {
612  JLDEBUG(gJournal, "Setting timeout to " << ms << " ms");
613 
614  m_timeout = ms;
615 #ifdef _WIN32
616  // Set COM timeouts
617  COMMTIMEOUTS commTimeouts;
618 
619  if (!GetCommTimeouts(
620  m_handle, &commTimeouts)) // Fill CommTimeouts structure
621  return m_lastResult = XRV_ERROR;
622 
623  // immediate return if data is available, wait 1ms otherwise
624  if (m_timeout > 0)
625  {
626  commTimeouts.ReadIntervalTimeout = 0;
627  commTimeouts.ReadTotalTimeoutConstant = m_timeout; // ms time
628  commTimeouts.ReadTotalTimeoutMultiplier = 0;
629  commTimeouts.WriteTotalTimeoutConstant = m_timeout;
630  commTimeouts.WriteTotalTimeoutMultiplier = 0;
631  }
632  else
633  {
634  // immediate return whether data is available or not
635  commTimeouts.ReadIntervalTimeout = MAXDWORD;
636  commTimeouts.ReadTotalTimeoutConstant = 0;
637  commTimeouts.ReadTotalTimeoutMultiplier = 0;
638  commTimeouts.WriteTotalTimeoutConstant = 0;
639  commTimeouts.WriteTotalTimeoutMultiplier = 0;
640  }
641 
642  if (!SetCommTimeouts(
643  m_handle, &commTimeouts)) // Set CommTimeouts structure
644  return m_lastResult = XRV_ERROR;
645 #else
646  // Timeout 0.1 sec for first byte, read minimum of 0 bytes
647  m_commState.c_cc[VMIN] = 0;
648  m_commState.c_cc[VTIME] = (m_timeout + 99) / 100; // ds time
649 
650  // Set the new options for the port if it is open
651  if (isOpen()) tcsetattr(m_handle, TCSANOW, &m_commState);
652 #endif
653  return (m_lastResult = XRV_OK);
654 }
655 
656 /*! \brief Wait for data to arrive or a timeout to occur.
657  \details The function waits until \c maxLength data is available or until a
658  timeout occurs.
659  The function returns success if data is available or XsResultValue::TIMEOUT
660  if a
661  timeout occurred. A timeout value of 0 indicates that the default timeout
662  stored
663  in the class should be used.
664  \param maxLength The maximum number of bytes to read before returning
665  \param data The buffer to put the read data in.
666  \returns XRV_OK if \a maxLength bytes were read, XRV_TIMEOUT if less was
667  read, XRV_TIMEOUTNODATA if nothing was read
668 */
670 {
671  data.clear();
672  data.reserve(maxLength);
673 
674  // char *data = (char *)&_data[0];
675  JLTRACE(gJournal, "timeout=" << m_timeout << ", maxLength=" << maxLength);
676  uint32_t timeout = m_timeout;
677 
678  uint32_t eTime = XsTime_getTimeOfDay(nullptr, nullptr) + timeout;
679  // uint32_t newLength = 0;
680 
681  while ((data.size() < maxLength) &&
682  (XsTime_getTimeOfDay(nullptr, nullptr) <= eTime))
683  {
684  XsByteArray raw;
685 
686  if (readData(maxLength - data.size(), raw) != XRV_OK)
687  return m_lastResult;
688  data.append(raw);
689  }
690  JLTRACE(
691  gJournal, "Read " << data.size() << " of " << maxLength << " bytes");
692 
693  if (data.size() < maxLength)
694  return (m_lastResult = XRV_TIMEOUT);
695  else
696  return (m_lastResult = XRV_OK);
697 }
698 
699 /*! \copydoc IoInterface::writeData
700  \note The default timeout is respected in this operation.
701 */
703  const XsByteArray& data, XsSize* written)
704 {
705  XsSize bytes;
706  if (written == nullptr) written = &bytes;
707 
708  if (!isOpen()) return (m_lastResult = XRV_NOPORTOPEN);
709 
710  *written = 0;
711 
712 #ifdef _WIN32
713  DWORD lwritten = 0;
714  if (WriteFile(
715  m_handle, data.data(), (DWORD)data.size(), &lwritten, nullptr) == 0)
716  return (m_lastResult = XRV_ERROR);
717 
718  *written = lwritten;
719 #else
720  ssize_t result = write(m_handle, (const void*)data.data(), data.size());
721  if (result < 0) return (m_lastResult = XRV_ERROR);
722 
723  *written = result;
724 #endif
725 
726 #ifdef LOG_RX_TX
727  if (written[0] > 0)
728  {
729  if (tx_log == nullptr)
730  {
731  char fname[XS_MAX_FILENAME_LENGTH];
732 #ifdef _WIN32
733  sprintf(fname, "tx_%03d_%d.log", (int32_t)m_port, m_baudrate);
734 #else
735  char* devname = strrchr(m_portname, '/');
736  sprintf(
737  fname, "tx_%s_%d.log", devname + 1,
738  XsBaud::rateToNumeric(m_baudrate));
739 #endif
740  makeFilenameUnique(fname);
741 
742  tx_log = fopen(fname, "wb");
743  }
744  fwrite(data.data(), 1, *written, tx_log);
745 #ifdef LOG_RX_TX_FLUSH
746  fflush(tx_log);
747 #endif
748  }
749 #endif
750 
751  return (m_lastResult = XRV_OK);
752 }
753 
754 /*! \brief Cancel any pending io requests */
756 {
757 #ifdef _WIN32
758 /* This function is only available on Windows Vista and higher.
759  When a read action hangs, this function can cancel IO operations from another
760  thread.
761 */
762 // CancelIoEx(m_handle, nullptr);
763 #endif
764 }
Operation was performed successfully.
Definition: xsens_std.h:34
XsIoHandle m_handle
The serial port handle, also indicates if the port is open or not.
uint16_t getPortNumber(void) const
Retrieve the port number that was last successfully opened.
GLenum GLint GLuint mask
Definition: glext.h:4050
#define XS_MAX_FILENAME_LENGTH
Definition: iointerface.h:30
unsigned __int16 uint16_t
Definition: rptypes.h:44
uint16_t m_port
The opened COM port nr.
int void fclose(FILE *f)
An OS-independent version of fclose.
Definition: os.cpp:273
GLuint buffer
Definition: glext.h:3917
XsFileHandle * rx_log
bool isOpen(void) const
Return whether the communication port is open or not.
pin 4: Data Terminal Ready
Definition: xscontrolline.h:25
HANDLE XsIoHandle
Definition: xsfilepos.h:38
struct XsByteArray XsByteArray
Definition: xsbytearray.h:25
XsControlLine
Serial control lines.
Definition: xscontrolline.h:16
size_t XsSize
XsSize must be unsigned number!
Definition: xstypedefs.h:19
XSTYPES_DLL_API uint32_t XsTime_getTimeOfDay(struct tm *date_, time_t *secs_)
int BOOL
Definition: xstypedefs.h:76
int counter
XsResultValue readData(XsSize maxLength, XsByteArray &data)
Read data from the serial port and put it into the data buffer.
XsBaudRate getBaudrate(void) const
Return the baudrate that is currently being used by the port.
Not a valid baud rate.
Definition: xsbaudrate.h:30
XsResultValue
Xsens result values.
Definition: xsresultvalue.h:27
XsBaudRate m_baudrate
The baudrate that was last set to be used by the port.
char m_portname[32]
The name of the open serial port.
XsResultValue escape(XsControlLine mask, XsControlLine state)
Manipulate the Serial control lines.
XsResultValue closeLive(void)
Close the serial communication port.
void cancelIo(void) const
Cancel any pending io requests.
XsResultValue open(const XsPortInfo &portInfo, uint32_t readBufSize=XS_DEFAULT_READ_BUFFER_SIZE, uint32_t writeBufSize=XS_DEFAULT_WRITE_BUFFER_SIZE)
Open a communication channel to the given port info.
XsResultValue m_lastResult
The last result of an operation.
virtual ~SerialInterface()
Destructor, de-initializes, frees memory allocated for buffers, etc.
GLsizei const GLchar ** string
Definition: glext.h:4101
void makeFilenameUnique(char *filename)
Helper function for making filename of log file unique.
XsResultValue getLastResult(void) const
Return the error code of the last operation.
__int32 int32_t
Definition: rptypes.h:46
XsIoHandle getHandle(void) const
Return the handle of the port.
XsResultValue flushData(void)
Flush all data in the buffers to and from the device.
#define JLDEBUG(...)
XsFileHandle * tx_log
XsResultValue setTimeout(uint32_t ms)
Set the default timeout value to use in blocking operations.
#define FALSE
Definition: xmlParser.h:231
GLuint GLsizei GLsizei * length
Definition: glext.h:4064
uint32_t getTimeout(void) const
Return the current timeout value.
uint32_t m_endTime
The time at which an operation will end in ms, used by several functions.
_u8 status
Definition: rplidar_cmd.h:19
pin 7: Request To Send
Definition: xscontrolline.h:31
FILE * fopen(const char *fileName, const char *mode) noexcept
An OS-independent version of fopen.
Definition: os.cpp:255
typedef void(APIENTRYP PFNGLBLENDCOLORPROC)(GLclampf red
GLsizei maxLength
Definition: glext.h:4932
#define JLTRACE(...)
void getPortName(XsString &portname) const
Retrieve the port name that was last successfully opened.
GLuint res
Definition: glext.h:7268
XsResultValue waitForData(XsSize maxLength, XsByteArray &data)
Wait for data to arrive or a timeout to occur.
struct XsString XsString
Definition: xsstring.h:34
char * strcpy(char *dest, size_t destSize, const char *source) noexcept
An OS-independent version of strcpy.
Definition: os.cpp:297
XsResultValue close(void)
Close the serial communication port.
unsigned __int32 uint32_t
Definition: rptypes.h:47
XsResultValue writeData(const XsByteArray &data, XsSize *written=0)
Write the data contained in data to the device.
XsBaudRate
Communication speed.
Definition: xsbaudrate.h:27
GLsizei GLsizei GLenum GLenum const GLvoid * data
Definition: glext.h:3546
#define JLALERT(...)
SerialInterface()
Default constructor, initializes all members to their default values.
int sprintf(char *buf, size_t bufSize, const char *format,...) noexcept MRPT_printf_format_check(3
An OS-independent version of sprintf (Notice the bufSize param, which may be ignored in some compiler...
Definition: os.cpp:189
bool doesFileExist(char *filename)
Helper function for making filename of log file unique.



Page generated by Doxygen 1.8.14 for MRPT 1.9.9 Git: 7d5e6d718 Fri Aug 24 01:51:28 2018 +0200 at lun nov 2 08:35:50 CET 2020