serial_controller.cpp
Go to the documentation of this file.
1 
32 
33 #include <regex>
34 
35 namespace roboteq {
36 
37 const std::string eol("\r");
38 const size_t max_line_length(128);
39 const std::regex rgx_query("(.+)=(.+)\r");
40 const std::regex rgx_cmd("(\\+|-)\r");
41 
42 serial_controller::serial_controller(string port, unsigned long baudrate)
43  : mSerialPort(port)
44  , mBaudrate(baudrate)
45 {
46  // Default timeout
47  mTimeout = 500;
48 }
49 
51 {
52  stop();
53 }
54 
56 {
57  try
58  {
60  mSerial.open();
62 
64  mSerial.setTimeout(to);
65  }
66  catch (serial::IOException& e)
67  {
68  ROS_ERROR_STREAM("Unable to open serial port " << mSerialPort << " - Error: " << e.what() );
69  return false;
70  }
71 
72  if(mSerial.isOpen()){
73  ROS_DEBUG_STREAM("Serial Port correctly initialized: " << mSerialPort );
74  }
75  else
76  {
77  ROS_ERROR_STREAM( "Serial port not opened: " << mSerialPort );
78  return false;
79  }
80  // Initialize stop function
81  mStopping = false;
82  // Launch async reader thread
83  first = std::thread(&serial_controller::async_reader, this);
84  ROS_DEBUG_STREAM( "Serial port ready" );
85 
86  /*
87  // Launch script and check version
88  script(true);
89  if(query("VAR", "1"))
90  {
91  _script_ver = get();
92  // Stop script
93  script(false);
94 
95  if(_script_ver.compare(script_ver) != 0)
96  {
97  ROS_WARN_STREAM("Script version mismatch. Updating V" << _script_ver << "->V"<< script_ver << " ...");
98  if(downloadScript())
99  {
100  ROS_WARN_STREAM("...Done!");
101  }
102  else
103  {
104  ROS_ERROR_STREAM("...ERROR to download the script!");
105  return false;
106  }
107  } else
108  {
109  ROS_DEBUG_STREAM("Script V" << _script_ver);
110  }
111  }
112  */
113  return true;
114 }
115 
117 {
118  // Stop script
119  script(false);
120  // Stop the reader
121  mStopping = true;
122  // Close the serial port
123  mSerial.close();
124  // Wait stop thread
125  first.join();
126 
127 }
128 
129 bool serial_controller::addCallback(const callback_data_t &callback, const string data)
130 {
131  if (hashmap.find(data) != hashmap.end())
132  {
133  return false;
134  } else
135  {
136  hashmap[data] = callback;
137  return true;
138  }
139 }
140 
142 {
143  mWriteMutex.lock();
144  // Send SLD.
145  ROS_INFO("Commanding driver to enter download mode.");
146  // Set fals HLD mode
147  isHLD = false;
148  // Send enable write mode
149  mSerial.write("%SLD 321654987" + eol);
150  // Set lock variable and wait a data to return
151  std::unique_lock<std::mutex> lck(mReaderMutex);
152  // TODO change timeout
153  cv.wait_for(lck, std::chrono::seconds(1));
154  // Look for special ack from SLD.
155  // ROS_INFO_STREAM("HLD=" << isHLD);
156  // Unlock mutex
157  mWriteMutex.unlock();
158  // If not received return false
159  if(!isHLD)
160  return false;
161 }
162 
164 {
165  if(enableDownload())
166  {
167  //ROS_DEBUG("Writing script...");
168  // Launch write script
169  int line_num = 0;
170  /*
171  while(script_lines[line_num]) {
172  // Build string
173  std::string line(script_lines[line_num]);
174  ROS_DEBUG_STREAM("write[" << line_num << "]" << line);
175  bool cmd = command(line, "", "");
176  // ROS_INFO_STREAM("cmd=" << (cmd ? "true" : "false"));
177  // Check data and received a "+"
178  if(!cmd)
179  return false;
180  // Go to second line
181  line_num++;
182  }
183  */
184  //ROS_DEBUG("...complete!");
185  return true;
186  }
187  return false;
188 }
189 
190 bool serial_controller::command(string msg, string params, string type)
191 {
192 
193  // Lock the write mutex
194  mWriteMutex.lock();
195  // Build the string
196  string msg2;
197  if(params.compare("") == 0) {
198  msg2 = type + msg + eol;
199  } else {
200  msg2 = type + msg + " " + params + eol;
201  }
202  unsigned int counter = 0;
203  while (counter < 5)
204  {
205  mSerial.write(msg2.c_str());
206  data = false;
207  // Set lock variable and wait a data to return
208  std::unique_lock<std::mutex> lck(mReaderMutex);
209  // TODO change timeout
210  cv.wait_for(lck, std::chrono::seconds(1));
211  if(data)
212  {
213  //ROS_DEBUG_STREAM("N:" << (counter+1) << " CMD:" << msg << " DATA:" << sub_data_cmd);
214  break;
215  } else
216  {
217  // Increase counter
218  counter++;
219  }
220  }
221  // Unlock mutex
222  mWriteMutex.unlock();
223  return sub_data_cmd;
224 }
225 
226 bool serial_controller::query(string msg, string params, string type) {
227  mWriteMutex.lock();
228  mMessage = msg;
229  string msg2;
230  if(params.compare("") == 0) {
231  msg2 = type + msg + eol;
232  } else {
233  msg2 = type + msg + " " + params + eol;
234  }
235 
236  unsigned int counter = 0;
237  while (counter < 5)
238  {
239  //ROS_DEBUG_STREAM("N:" << (counter+1) << " TX: " << msg);
240  mSerial.write(msg2.c_str());
241  data = false;
242  // Set lock variable and wait a data to return
243  std::unique_lock<std::mutex> lck(mReaderMutex);
244  cv.wait_for(lck, std::chrono::seconds(1));
245  if(data)
246  {
247  //ROS_DEBUG_STREAM("N:" << (counter+1) << " CMD:" << msg << " DATA:" << sub_data);
248  break;
249  } else
250  {
251  // Increase counter
252  counter++;
253  }
254  }
255  // Clear last query request
256  mMessage = "";
257  // Unlock mutex
258  mWriteMutex.unlock();
259  return data;
260 }
261 
263 {
264  while (!mStopping) {
265  // Read how many byte waiting to read
266  //ROS_DEBUG_STREAM_NAMED("serial", "Bytes waiting: " << mSerial.available());
267  // Read line
268  std::string msg = mSerial.readline(max_line_length, eol);
269  // Decode message
270  if (!msg.empty())
271  {
272  //ROS_DEBUG_STREAM_NAMED("serial", "RX: " << msg);
273  if (std::regex_match(msg, rgx_cmd))
274  {
275  // Decode if command return true
276  if(msg[0] == '+') sub_data_cmd = true;
277  else sub_data_cmd = false;
278  // Unlock command
279  data = true;
280  // Unlock query request
281  cv.notify_all();
282  }
283  else if(std::regex_match(msg, rgx_query))
284  {
285  // Get command
286  string sub_cmd = msg.substr(0, msg.find('='));
287  // Evaluate end position string
288  long end_string = (msg.size()-1) - (msg.find('=') + 1);
289  // Get data
290  sub_data = msg.substr(msg.find('=') + 1, end_string);
291  // ROS_INFO_STREAM("CMD=" << sub_cmd << " DATA=" << sub_data);
292  // Check first of all a message sent require a data to return
293  if(mMessage.compare("") != 0) {
294  if(mMessage.compare(sub_cmd) == 0) {
295  data = true;
296  // Unlock query request
297  cv.notify_all();
298  // Skip other request
299  continue;
300  }
301  }
302  // Find in all callback a data to send
303  if (hashmap.find(sub_cmd) != hashmap.end())
304  {
305  // Get callback from hashmap
306  callback_data_t callback = hashmap[sub_cmd];
307  // Launch callback with return query
308  callback(sub_data);
309  }
310  }
311  else if(msg.compare("HLD\r") == 0)
312  {
313  isHLD = true;
314  // Unlock query request
315  cv.notify_one();
316  }
317  else
318  {
319  //ROS_INFO_STREAM("Other message " << msg);
320  }
321  }
322  }
323  //ROS_INFO("Async serial reader closed");
324 }
325 
326 }
msg
bool script(bool status)
script Run and stop the script inside the Roboteq
size_t readline(std::string &buffer, size_t size=65536, std::string eol="\n")
bool addCallback(const callback_data_t &callback, const string data)
addCallback Add callback message
serial_controller(string port, unsigned long baudrate)
serial_controller Open the serial controller
bool downloadScript()
downloadScript Launch the script update for the Roboteq board
map< string, callback_data_t > hashmap
void setTimeout(Timeout &timeout)
void setBaudrate(uint32_t baudrate)
bool enableDownload()
enableDownload Enable writing script
const std::string eol("\r")
void async_reader()
async_reader Thread to read realtime all charachters sent from roboteq board
bool query(string msg, string params="", string type="?")
const size_t max_line_length(128)
const std::regex rgx_query("(.+)=(.+)\r")
function< void(string data) > callback_data_t
Read complete callback - Array of callback.
#define ROS_INFO(...)
virtual const char * what() const
static Timeout simpleTimeout(uint32_t timeout)
bool isOpen() const
#define ROS_DEBUG_STREAM(args)
bool command(string msg, string params="", string type="!")
void setPort(const std::string &port)
Definition: motor.h:51
const std::regex rgx_cmd("(\\+|-)\r")
#define ROS_ERROR_STREAM(args)
std::condition_variable cv
size_t write(const uint8_t *data, size_t size)
bool start()
start Initialize the serial communcation


roboteq_control
Author(s): Raffaello Bonghi
autogenerated on Wed Jan 3 2018 03:48:23