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