YARP
Yet Another Robot Platform
SerialDeviceDriver.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2006-2020 Istituto Italiano di Tecnologia (IIT)
3  * Copyright (C) 2007 Alexandre Bernardino
4  * Copyright (C) 2007 Carlos Beltran-Gonzalez
5  * All rights reserved.
6  *
7  * This software may be modified and distributed under the terms of the
8  * BSD-3-Clause license. See the accompanying LICENSE file for details.
9  */
10 
11 #include "SerialDeviceDriver.h"
12 
13 #include <yarp/os/Log.h>
14 #include <yarp/os/LogComponent.h>
15 
16 #include <cstdio>
17 #include <cstdlib>
18 
19 using namespace yarp::os;
20 using namespace yarp::dev;
21 
22 #define MAX_FLUSHED_BYTES 10000
23 
24 //inline SerialHandler& RES(void *res) { return *(SerialHandler *)res; }
25 
26 namespace {
27 YARP_LOG_COMPONENT(SERIALPORT, "yarp.device.serialport")
28 }
29 
31  //system_resources = (SerialHandler*) new SerialHandler();
32  verbose=false;
33  line_terminator_char1 = '\r';
34  line_terminator_char2 = '\n';
35 }
36 
38  close();
39 }
40 
42 {
43  //if(RES(system_resources).initialize(config.CommChannel, config.SerialParams) < 0)
44  // return false;
45  //RES(system_resources).setCommandSender(this);
46  //yCTrace(SERIALPORT, "SerialHandler::initialize");
47  yCInfo(SERIALPORT, "Starting Serial Port in %s \n", config.CommChannel);
48 
49  // Initialize serial port
50  if(_serialConnector.connect(_serial_dev, ACE_DEV_Addr(config.CommChannel)) == -1)
51  {
52  yCError(SERIALPORT, "Invalid communications port in %s: %s\n", config.CommChannel, strerror(errno));
53  return false;
54  }
55 
56 
57  // Set TTY_IO parameter into the ACE_TTY_IO device(_serial_dev)
58  if (_serial_dev.control (ACE_TTY_IO::SETPARAMS, &config.SerialParams) == -1)
59  {
60  yCError(SERIALPORT, "Can not control communications port %s \n", config.CommChannel);
61  return false;
62  }
63 
64  return true;
65 }
66 
67 
70  strcpy(config2.CommChannel, config.check("comport",Value("COM3"),"name of the serial channel").asString().c_str());
71  this->verbose = (config.check("verbose",Value(1),"Specifies if the device is in verbose mode (0/1).").asInt32())>0;
72  config2.SerialParams.baudrate = config.check("baudrate",Value(9600),"Specifies the baudrate at which the communication port operates.").asInt32();
73  config2.SerialParams.xonlim = config.check("xonlim",Value(0),"Specifies the minimum number of bytes in input buffer before XON char is sent. Negative value indicates that default value should be used (Win32)").asInt32();
74  config2.SerialParams.xofflim = config.check("xofflim",Value(0),"Specifies the maximum number of bytes in input buffer before XOFF char is sent. Negative value indicates that default value should be used (Win32). ").asInt32();
75  //RANDAZ: as far as I undesrood, the exit condition for recv() function is NOT readmincharacters || readtimeoutmsec. It is readmincharacters && readtimeoutmsec.
76  //On Linux. if readmincharacters params is set !=0, recv() may still block even if readtimeoutmsec is expired.
77  //On Win32, for unknown reason, readmincharacters seems to be ignored, so recv () returns after readtimeoutmsec. Maybe readmincharacters is used if readtimeoutmsec is set to -1?
78  config2.SerialParams.readmincharacters = config.check("readmincharacters",Value(1),"Specifies the minimum number of characters for non-canonical read (POSIX).").asInt32();
79  config2.SerialParams.readtimeoutmsec = config.check("readtimeoutmsec",Value(100),"Specifies the time to wait before returning from read. Negative value means infinite timeout.").asInt32();
80  // config2.SerialParams.parityenb = config.check("parityenb",Value(0),"Enable/disable parity checking.").asInt32();
81  std::string temp = config.check("paritymode",Value("EVEN"),"Specifies the parity mode (EVEN, ODD, NONE). POSIX supports even and odd parity. Additionally Win32 supports mark and space parity modes.").asString();
82  config2.SerialParams.paritymode = temp.c_str();
83  config2.SerialParams.ctsenb = config.check("ctsenb",Value(0),"Enable & set CTS mode. Note that RTS & CTS are enabled/disabled together on some systems (RTS/CTS is enabled if either <code>ctsenb</code> or <code>rtsenb</code> is set).").asInt32();
84  config2.SerialParams.rtsenb = config.check("rtsenb",Value(0),"Enable & set RTS mode. Note that RTS & CTS are enabled/disabled together on some systems (RTS/CTS is enabled if either <code>ctsenb</code> or <code>rtsenb</code> is set).\n- 0 = Disable RTS.\n- 1 = Enable RTS.\n- 2 = Enable RTS flow-control handshaking (Win32).\n- 3 = Specifies that RTS line will be high if bytes are available for transmission.\nAfter transmission RTS will be low (Win32).").asInt32();
85  config2.SerialParams.xinenb = config.check("xinenb",Value(0),"Enable/disable software flow control on input.").asInt32();
86  config2.SerialParams.xoutenb = config.check("xoutenb",Value(0),"Enable/disable software flow control on output.").asInt32();
87  config2.SerialParams.modem = config.check("modem",Value(0),"Specifies if device is a modem (POSIX). If not set modem status lines are ignored. ").asInt32();
88  config2.SerialParams.rcvenb = config.check("rcvenb",Value(0),"Enable/disable receiver (POSIX).").asInt32();
89  config2.SerialParams.dsrenb = config.check("dsrenb",Value(0),"Controls whether DSR is disabled or enabled (Win32).").asInt32();
90  config2.SerialParams.dtrdisable = config.check("dtrdisable",Value(0),"Controls whether DTR is disabled or enabled.").asInt32();
91  config2.SerialParams.databits = config.check("databits",Value(7),"Data bits. Valid values 5, 6, 7 and 8 data bits. Additionally Win32 supports 4 data bits.").asInt32();
92  config2.SerialParams.stopbits = config.check("stopbits",Value(1),"Stop bits. Valid values are 1 and 2.").asInt32();
93 
94  if (config.check("line_terminator_char1", "line terminator character for receiveLine(), default '\r'"))
95  line_terminator_char1 = config.find("line_terminator_char1").asInt32();
96 
97  if (config.check("line_terminator_char2", "line terminator character for receiveLine(), default '\n'"))
98  line_terminator_char2 = config.find("line_terminator_char2").asInt32();
99 
100  return open(config2);
101 }
102 
104  _serial_dev.close();
105  return true;
106 }
107 
108 bool SerialDeviceDriver::setDTR(bool value) {
109  ACE_TTY_IO::Serial_Params arg;
110  int ret = _serial_dev.control(_serial_dev.GETPARAMS, &arg);
111  if (ret == -1) return false;
112  arg.dtrdisable = !value;
113  ret = _serial_dev.control(_serial_dev.SETPARAMS, &arg);
114  if (ret == -1) return false;
115  return true;
116 }
117 
119 {
120  if (msg.size() > 0)
121  {
122  int message_size = msg.get(0).asString().length();
123 
124  if (message_size > 0)
125  {
126  if (verbose)
127  {
128  yCDebug(SERIALPORT, "Sending string: %s", msg.get(0).asString().c_str());
129  }
130 
131  // Write message to the serial device
132  ssize_t bytes_written = _serial_dev.send_n((void *) msg.get(0).asString().c_str(), message_size);
133 
134  if (bytes_written == -1)
135  {
136  yCError(SERIALPORT, "Unable to write to serial port");
137  return false;
138  }
139  }
140  else
141  {
142  if (verbose) yCDebug(SERIALPORT, "The input command bottle contains an empty string.");
143  return false;
144  }
145  }
146  else
147  {
148  if (verbose) yCDebug(SERIALPORT, "The input command bottle is empty. \n");
149  return false;
150  }
151 
152  return true;
153 }
154 
155 bool SerialDeviceDriver::send(char *msg, size_t size)
156 {
157  if (size > 0)
158  {
159  if (verbose)
160  {
161  yCDebug(SERIALPORT, "Sending string: %s", msg);
162  }
163 
164  // Write message in the serial device
165  ssize_t bytes_written = _serial_dev.send_n((void *)msg, size);
166 
167  if (bytes_written == -1)
168  {
169  yCError(SERIALPORT, "Unable to write to serial port");
170  return false;
171  }
172  }
173  else
174  {
175  if (verbose) yCDebug(SERIALPORT, "The input message is empty. \n");
176  return false;
177  }
178 
179  return true;
180 }
181 
183 {
184  char chr;
185 
186  //this function call blocks
187  ssize_t bytes_read = _serial_dev.recv ((void *) &chr, 1);
188 
189  if (bytes_read == -1)
190  {
191  yCError(SERIALPORT, "Error in SerialDeviceDriver::receive()");
192  return 0;
193  }
194 
195  if (bytes_read == 0)
196  {
197  return 0;
198  }
199 
200  c=chr;
201  return 1;
202 }
203 
205 {
206  char chr [100];
207  int count=0;
208  ssize_t bytes_read=0;
209  do
210  {
211  bytes_read = _serial_dev.recv((void *) &chr, 100);
212  count+=bytes_read;
213  if (count > MAX_FLUSHED_BYTES) break; //to prevent endless loop
214  }
215  while (bytes_read>0);
216  return count;
217 }
218 
219 int SerialDeviceDriver::receiveBytes(unsigned char* bytes, const int size)
220 {
221 #if 1
222  //this function call blocks
223  return _serial_dev.recv((void *)bytes, size);
224 #else
225  int i;
226  for (i = 0; i < size ; ++i)
227  {
228  char recv_ch;
229  int n = receiveChar(recv_ch);
230  if (n <= 0)
231  {
232  return i;
233  }
234  bytes[i] = recv_ch;
235  }
236  return i;
237 #endif
238 }
239 
240 int SerialDeviceDriver::receiveLine(char* buffer, const int MaxLineLength)
241 {
242  int i;
243  for (i = 0; i < MaxLineLength -1; ++i)
244  {
245  char recv_ch;
246  int n = receiveChar(recv_ch);
247  if (n <= 0)
248  {
249  //this invalidates the whole line, because no line terminator \n was found
250  return 0;
251 
252  //use this commented code here if you do NOT want to invalidate the line
253  //buffer[i] = '\0';
254  //return i;
255  }
256  if ((recv_ch == line_terminator_char1) || (recv_ch == line_terminator_char2))
257  {
258  buffer[i] = recv_ch;
259  i++;
260  break;
261  }
262  buffer[i] = recv_ch;
263  }
264  buffer[i] = '\0';
265  return i;
266 }
267 
269 {
270  const int msgSize = 1001;
271  char message[1001];
272 
273  //this function call blocks
274  ssize_t bytes_read = _serial_dev.recv ((void *) message, msgSize - 1);
275 
276  if (bytes_read == -1)
277  {
278  yCError(SERIALPORT, "Error in SerialDeviceDriver::receive()");
279  return false;
280  }
281 
282  if (bytes_read == 0) //nothing there
283  return true;
284 
285  message[bytes_read] = 0;
286 
287  if (verbose)
288  {
289  yCDebug(SERIALPORT, "Data received from serial device: %s", message);
290  }
291 
292 
293  // Put message in the bottle
294  msg.addString(message);
295 
296  return true;
297 }
SerialDeviceDriver.h
yarp::os::Bottle
A simple collection of objects that can be described and transmitted in a portable way.
Definition: Bottle.h:73
SerialDeviceDriver::send
bool send(const Bottle &msg) override
Sends a string of chars to the serial communications channel.
Definition: SerialDeviceDriver.cpp:118
yarp::os::Searchable
A base class for nested structures that can be searched.
Definition: Searchable.h:69
SerialDeviceDriver::open
bool open(yarp::os::Searchable &config) override
Open the DeviceDriver.
Definition: SerialDeviceDriver.cpp:68
yarp::os::Bottle::size
size_type size() const
Gets the number of elements in the bottle.
Definition: Bottle.cpp:254
SerialDeviceDriver::receiveChar
int receiveChar(char &chr) override
Gets one single char from the receive queue.
Definition: SerialDeviceDriver.cpp:182
YARP_LOG_COMPONENT
#define YARP_LOG_COMPONENT(name,...)
Definition: LogComponent.h:80
SerialDeviceDriverSettings::CommChannel
char CommChannel[100]
Definition: SerialDeviceDriver.h:34
ret
bool ret
Definition: ImplementAxisInfo.cpp:72
yarp::dev
An interface for the device drivers.
Definition: audioBufferSizeData.cpp:17
Log.h
SerialDeviceDriver::receiveLine
int receiveLine(char *line, const int MaxLineLength) override
Gets one line (a sequence of chars with a ending '\n' or '\r') from the receive queue.
Definition: SerialDeviceDriver.cpp:240
SerialDeviceDriver::receiveBytes
int receiveBytes(unsigned char *bytes, const int size) override
Gets an array of bytes (unsigned char) with size <= 'size' parameter.
Definition: SerialDeviceDriver.cpp:219
SerialDeviceDriver::setDTR
bool setDTR(bool value) override
Enable/Disable DTR protocol.
Definition: SerialDeviceDriver.cpp:108
yarp::os::Bottle::get
Value & get(size_type index) const
Reads a Value v from a certain part of the list.
Definition: Bottle.cpp:249
SerialDeviceDriver::receive
bool receive(Bottle &msg) override
Gets the existing chars in the receive queue.
Definition: SerialDeviceDriver.cpp:268
yarp::os::Value::asString
virtual std::string asString() const
Get string value.
Definition: Value.cpp:237
yarp::os::Searchable::check
virtual bool check(const std::string &key) const =0
Check if there exists a property of the given name.
buffer
Definition: V4L_camera.h:75
yarp::conf::ssize_t
::ssize_t ssize_t
Definition: numeric.h:60
yarp::os::Searchable::find
virtual Value & find(const std::string &key) const =0
Gets a value corresponding to a given keyword.
SerialDeviceDriver::SerialDeviceDriver
SerialDeviceDriver()
Definition: SerialDeviceDriver.cpp:30
yarp::os::Bottle::addString
void addString(const char *str)
Places a string in the bottle, at the end of the list.
Definition: Bottle.cpp:173
LogComponent.h
SerialDeviceDriver::~SerialDeviceDriver
virtual ~SerialDeviceDriver()
Definition: SerialDeviceDriver.cpp:37
SerialDeviceDriverSettings::SerialParams
ACE_TTY_IO::Serial_Params SerialParams
Definition: SerialDeviceDriver.h:35
yCError
#define yCError(component,...)
Definition: LogComponent.h:157
yarp::os::Value::asInt32
virtual std::int32_t asInt32() const
Get 32-bit integer value.
Definition: Value.cpp:207
SerialDeviceDriver::flush
int flush() override
Flushes the internal buffer.
Definition: SerialDeviceDriver.cpp:204
yCInfo
#define yCInfo(component,...)
Definition: LogComponent.h:135
yarp::os
An interface to the operating system, including Port based communication.
Definition: AbstractCarrier.h:17
yCDebug
#define yCDebug(component,...)
Definition: LogComponent.h:112
MAX_FLUSHED_BYTES
#define MAX_FLUSHED_BYTES
Definition: SerialDeviceDriver.cpp:22
SerialDeviceDriver::close
bool close() override
Close the DeviceDriver.
Definition: SerialDeviceDriver.cpp:103
SerialDeviceDriverSettings
Definition: SerialDeviceDriver.h:32
yarp::os::Value
A single value (typically within a Bottle).
Definition: Value.h:47