node_handle.h
Go to the documentation of this file.
1 /*
2  * Copyright 2017 Fraunhofer Institute for Manufacturing Engineering and Automation (IPA)
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9 
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 
18 #ifndef ROS_NODE_HANDLE_H_
19 #define ROS_NODE_HANDLE_H_
20 
21 #include <stdint.h>
22 
23 #include "std_msgs/Time.h"
25 #include "rosserial_msgs/Log.h"
27 
28 #define SYNC_SECONDS 5
29 
30 #define MODE_FIRST_FF 0
31 /*
32  * The second sync byte is a protocol version. It's value is 0xff for the first
33  * version of the rosserial protocol (used up to hydro), 0xfe for the second version
34  * (introduced in hydro), 0xfd for the next, and so on. Its purpose is to enable
35  * detection of mismatched protocol versions (e.g. hydro rosserial_python with groovy
36  * rosserial_arduino. It must be changed in both this file and in
37  * rosserial_python/src/rosserial_python/SerialClient.py
38  */
39 #define MODE_PROTOCOL_VER 1
40 #define PROTOCOL_VER1 0xff // through groovy
41 #define PROTOCOL_VER2 0xfe // in hydro
42 #define PROTOCOL_VER PROTOCOL_VER2
43 #define MODE_SIZE_L 2
44 #define MODE_SIZE_H 3
45 #define MODE_SIZE_CHECKSUM 4 // checksum for msg size received from size L and H
46 #define MODE_TOPIC_L 5 // waiting for topic id
47 #define MODE_TOPIC_H 6
48 #define MODE_MESSAGE 7
49 #define MODE_MSG_CHECKSUM 8 // checksum for msg and topic id
50 
51 
52 #define MSG_TIMEOUT 20 //20 milliseconds to recieve all of message data
53 
54 #include "msg.h"
55 
56 namespace ros {
57 
59  public:
60  virtual int publish(int id, const Msg* msg)=0;
61  virtual int spinOnce()=0;
62  virtual bool connected()=0;
63  };
64 }
65 
66 #include "publisher.h"
67 #include "subscriber.h"
68 #include "service_server.h"
69 #include "service_client.h"
70 
71 namespace ros {
72 
74 
75  /* Node Handle */
76  template<class Hardware,
77  int MAX_SUBSCRIBERS=25,
78  int MAX_PUBLISHERS=25,
79  int INPUT_SIZE=512,
80  int OUTPUT_SIZE=512>
82  {
83  protected:
84  Hardware hardware_;
85 
86  /* time used for syncing */
87  uint32_t rt_time;
88 
89  /* used for computing current time */
90  uint32_t sec_offset, nsec_offset;
91 
92  uint8_t message_in[INPUT_SIZE];
93  uint8_t message_out[OUTPUT_SIZE];
94 
95  Publisher * publishers[MAX_PUBLISHERS];
96  Subscriber_ * subscribers[MAX_SUBSCRIBERS];
97 
98  /*
99  * Setup Functions
100  */
101  public:
102  NodeHandle_() : configured_(false) {
103 
104  for(unsigned int i=0; i< MAX_PUBLISHERS; i++)
105  publishers[i] = 0;
106 
107  for(unsigned int i=0; i< MAX_SUBSCRIBERS; i++)
108  subscribers[i] = 0;
109 
110  for(unsigned int i=0; i< INPUT_SIZE; i++)
111  message_in[i] = 0;
112 
113  for(unsigned int i=0; i< OUTPUT_SIZE; i++)
114  message_out[i] = 0;
115 
116  req_param_resp.ints_length = 0;
117  req_param_resp.ints = NULL;
118  req_param_resp.floats_length = 0;
119  req_param_resp.floats = NULL;
120  req_param_resp.ints_length = 0;
121  req_param_resp.ints = NULL;
122  }
123 
124  Hardware* getHardware(){
125  return &hardware_;
126  }
127 
128  /* Start serial, initialize buffers */
129  void initNode(){
130  hardware_.init();
131  mode_ = 0;
132  bytes_ = 0;
133  index_ = 0;
134  topic_ = 0;
135  };
136 
137  /* Start a named port, which may be network server IP, initialize buffers */
138  void initNode(char *portName){
139  hardware_.init(portName);
140  mode_ = 0;
141  bytes_ = 0;
142  index_ = 0;
143  topic_ = 0;
144  };
145 
146  protected:
147  //State machine variables for spinOnce
148  int mode_;
149  int bytes_;
150  int topic_;
151  int index_;
153 
155 
156  /* used for syncing the time */
157  uint32_t last_sync_time;
160 
161  public:
162  /* This function goes in your loop() function, it handles
163  * serial input and callbacks for subscribers.
164  */
165 
166 
167  virtual int spinOnce(){
168 
169  /* restart if timed out */
170  uint32_t c_time = hardware_.time();
171  if( (c_time - last_sync_receive_time) > (SYNC_SECONDS*2200) ){
172  configured_ = false;
173  }
174 
175  /* reset if message has timed out */
176  if ( mode_ != MODE_FIRST_FF){
177  if (c_time > last_msg_timeout_time){
178  mode_ = MODE_FIRST_FF;
179  }
180  }
181 
182  /* while available buffer, read data */
183  while( true )
184  {
185  int data = hardware_.read();
186  if( data < 0 )
187  break;
188  checksum_ += data;
189  if( mode_ == MODE_MESSAGE ){ /* message data being recieved */
190  message_in[index_++] = data;
191  bytes_--;
192  if(bytes_ == 0) /* is message complete? if so, checksum */
193  mode_ = MODE_MSG_CHECKSUM;
194  }else if( mode_ == MODE_FIRST_FF ){
195  if(data == 0xff){
196  mode_++;
197  last_msg_timeout_time = c_time + MSG_TIMEOUT;
198  }
199  else if( hardware_.time() - c_time > (SYNC_SECONDS)){
200  /* We have been stuck in spinOnce too long, return error */
201  configured_=false;
202  return -2;
203  }
204  }else if( mode_ == MODE_PROTOCOL_VER ){
205  if(data == PROTOCOL_VER){
206  mode_++;
207  }else{
208  mode_ = MODE_FIRST_FF;
209  if (configured_ == false)
210  requestSyncTime(); /* send a msg back showing our protocol version */
211  }
212  }else if( mode_ == MODE_SIZE_L ){ /* bottom half of message size */
213  bytes_ = data;
214  index_ = 0;
215  mode_++;
216  checksum_ = data; /* first byte for calculating size checksum */
217  }else if( mode_ == MODE_SIZE_H ){ /* top half of message size */
218  bytes_ += data<<8;
219  mode_++;
220  }else if( mode_ == MODE_SIZE_CHECKSUM ){
221  if( (checksum_%256) == 255)
222  mode_++;
223  else
224  mode_ = MODE_FIRST_FF; /* Abandon the frame if the msg len is wrong */
225  }else if( mode_ == MODE_TOPIC_L ){ /* bottom half of topic id */
226  topic_ = data;
227  mode_++;
228  checksum_ = data; /* first byte included in checksum */
229  }else if( mode_ == MODE_TOPIC_H ){ /* top half of topic id */
230  topic_ += data<<8;
231  mode_ = MODE_MESSAGE;
232  if(bytes_ == 0)
233  mode_ = MODE_MSG_CHECKSUM;
234  }else if( mode_ == MODE_MSG_CHECKSUM ){ /* do checksum */
235  mode_ = MODE_FIRST_FF;
236  if( (checksum_%256) == 255){
237  if(topic_ == TopicInfo::ID_PUBLISHER){
238  requestSyncTime();
239  negotiateTopics();
240  last_sync_time = c_time;
241  last_sync_receive_time = c_time;
242  return -1;
243  }else if(topic_ == TopicInfo::ID_TIME){
244  syncTime(message_in);
245  }else if (topic_ == TopicInfo::ID_PARAMETER_REQUEST){
246  req_param_resp.deserialize(message_in);
247  param_recieved= true;
248  }else if(topic_ == TopicInfo::ID_TX_STOP){
249  configured_ = false;
250  }else{
251  if(subscribers[topic_-100])
252  subscribers[topic_-100]->callback( message_in );
253  }
254  }
255  }
256  }
257 
258  /* occasionally sync time */
259  if( configured_ && ((c_time-last_sync_time) > (SYNC_SECONDS*500) )){
260  requestSyncTime();
261  last_sync_time = c_time;
262  }
263 
264  return 0;
265  }
266 
267 
268  /* Are we connected to the PC? */
269  virtual bool connected() {
270  return configured_;
271  };
272 
273  /********************************************************************
274  * Time functions
275  */
276 
278  {
279  std_msgs::Time t;
281  rt_time = hardware_.time();
282  }
283 
284  void syncTime(uint8_t * data)
285  {
286  std_msgs::Time t;
287  uint32_t offset = hardware_.time() - rt_time;
288 
289  t.deserialize(data);
290  t.data.sec += offset/1000;
291  t.data.nsec += (offset%1000)*1000000UL;
292 
293  this->setNow(t.data);
294  last_sync_receive_time = hardware_.time();
295  }
296 
298  {
299  uint32_t ms = hardware_.time();
300  Time current_time;
301  current_time.sec = ms/1000 + sec_offset;
302  current_time.nsec = (ms%1000)*1000000UL + nsec_offset;
303  normalizeSecNSec(current_time.sec, current_time.nsec);
304  return current_time;
305  }
306 
307  void setNow( Time & new_now )
308  {
309  uint32_t ms = hardware_.time();
310  sec_offset = new_now.sec - ms/1000 - 1;
311  nsec_offset = new_now.nsec - (ms%1000)*1000000UL + 1000000000UL;
312  normalizeSecNSec(sec_offset, nsec_offset);
313  }
314 
315  /********************************************************************
316  * Topic Management
317  */
318 
319  /* Register a new publisher */
321  {
322  for(int i = 0; i < MAX_PUBLISHERS; i++){
323  if(publishers[i] == 0){ // empty slot
324  publishers[i] = &p;
325  p.id_ = i+100+MAX_SUBSCRIBERS;
326  p.nh_ = this;
327  return true;
328  }
329  }
330  return false;
331  }
332 
333  /* Register a new subscriber */
334  template<typename MsgT>
336  for(int i = 0; i < MAX_SUBSCRIBERS; i++){
337  if(subscribers[i] == 0){ // empty slot
338  subscribers[i] = (Subscriber_*) &s;
339  s.id_ = i+100;
340  return true;
341  }
342  }
343  return false;
344  }
345 
346  /* Register a new Service Server */
347  template<typename MReq, typename MRes>
349  bool v = advertise(srv.pub);
350  for(int i = 0; i < MAX_SUBSCRIBERS; i++){
351  if(subscribers[i] == 0){ // empty slot
352  subscribers[i] = (Subscriber_*) &srv;
353  srv.id_ = i+100;
354  return v;
355  }
356  }
357  return false;
358  }
359 
360  /* Register a new Service Client */
361  template<typename MReq, typename MRes>
363  bool v = advertise(srv.pub);
364  for(int i = 0; i < MAX_SUBSCRIBERS; i++){
365  if(subscribers[i] == 0){ // empty slot
366  subscribers[i] = (Subscriber_*) &srv;
367  srv.id_ = i+100;
368  return v;
369  }
370  }
371  return false;
372  }
373 
375  {
377  int i;
378  for(i = 0; i < MAX_PUBLISHERS; i++)
379  {
380  if(publishers[i] != 0) // non-empty slot
381  {
382  ti.topic_id = publishers[i]->id_;
383  ti.topic_name = (char *) publishers[i]->topic_;
384  ti.message_type = (char *) publishers[i]->msg_->getType();
385  ti.md5sum = (char *) publishers[i]->msg_->getMD5();
386  ti.buffer_size = OUTPUT_SIZE;
387  publish( publishers[i]->getEndpointType(), &ti );
388  }
389  }
390  for(i = 0; i < MAX_SUBSCRIBERS; i++)
391  {
392  if(subscribers[i] != 0) // non-empty slot
393  {
394  ti.topic_id = subscribers[i]->id_;
395  ti.topic_name = (char *) subscribers[i]->topic_;
396  ti.message_type = (char *) subscribers[i]->getMsgType();
397  ti.md5sum = (char *) subscribers[i]->getMsgMD5();
398  ti.buffer_size = INPUT_SIZE;
399  publish( subscribers[i]->getEndpointType(), &ti );
400  }
401  }
402  configured_ = true;
403  }
404 
405  virtual int publish(int id, const Msg * msg)
406  {
407  if(id >= 100 && !configured_)
408  return 0;
409 
410  /* serialize message */
411  uint16_t l = msg->serialize(message_out+7);
412 
413  /* setup the header */
414  message_out[0] = 0xff;
415  message_out[1] = PROTOCOL_VER;
416  message_out[2] = (uint8_t) ((uint16_t)l&255);
417  message_out[3] = (uint8_t) ((uint16_t)l>>8);
418  message_out[4] = 255 - ((message_out[2] + message_out[3])%256);
419  message_out[5] = (uint8_t) ((int16_t)id&255);
420  message_out[6] = (uint8_t) ((int16_t)id>>8);
421 
422  /* calculate checksum */
423  int chk = 0;
424  for(int i =5; i<l+7; i++)
425  chk += message_out[i];
426  l += 7;
427  message_out[l++] = 255 - (chk%256);
428 
429  if( l <= OUTPUT_SIZE ){
430  hardware_.write(message_out, l);
431  return l;
432  }else{
433  logerror("Message from device dropped: message larger than buffer.");
434  return -1;
435  }
436  }
437 
438  /********************************************************************
439  * Logging
440  */
441 
442  private:
443  void log(char byte, const char * msg){
445  l.level= byte;
446  l.msg = (char*)msg;
448  }
449 
450  public:
451  void logdebug(const char* msg){
453  }
454  void loginfo(const char * msg){
455  log(rosserial_msgs::Log::INFO, msg);
456  }
457  void logwarn(const char *msg){
458  log(rosserial_msgs::Log::WARN, msg);
459  }
460  void logerror(const char*msg){
461  log(rosserial_msgs::Log::ERROR, msg);
462  }
463  void logfatal(const char*msg){
464  log(rosserial_msgs::Log::FATAL, msg);
465  }
466 
467  /********************************************************************
468  * Parameters
469  */
470 
471  private:
474 
475  bool requestParam(const char * name, int time_out = 1000){
476  param_recieved = false;
478  req.name = (char*)name;
480  uint16_t end_time = hardware_.time() + time_out;
481  while(!param_recieved ){
482  spinOnce();
483  if (hardware_.time() > end_time) return false;
484  }
485  return true;
486  }
487 
488  public:
489  bool getParam(const char* name, int* param, int length =1){
490  if (requestParam(name) ){
491  if (length == req_param_resp.ints_length){
492  //copy it over
493  for(int i=0; i<length; i++)
494  param[i] = req_param_resp.ints[i];
495  return true;
496  }
497  }
498  return false;
499  }
500  bool getParam(const char* name, float* param, int length=1){
501  if (requestParam(name) ){
502  if (length == req_param_resp.floats_length){
503  //copy it over
504  for(int i=0; i<length; i++)
505  param[i] = req_param_resp.floats[i];
506  return true;
507  }
508  }
509  return false;
510  }
511  bool getParam(const char* name, char** param, int length=1){
512  if (requestParam(name) ){
513  if (length == req_param_resp.strings_length){
514  //copy it over
515  for(int i=0; i<length; i++)
516  strcpy(param[i],req_param_resp.strings[i]);
517  return true;
518  }
519  }
520  return false;
521  }
522  };
523 
524 }
525 
526 #endif
msg
s
Definition: DHT22.py:257
void logdebug(const char *msg)
Definition: node_handle.h:451
void logwarn(const char *msg)
Definition: node_handle.h:457
#define MODE_PROTOCOL_VER
Definition: node_handle.h:39
Definition: time.h:30
const char * topic_name
Definition: TopicInfo.h:33
ros::Time data
Definition: Time.h:33
void syncTime(uint8_t *data)
Definition: node_handle.h:284
void log(char byte, const char *msg)
Definition: node_handle.h:443
virtual bool connected()=0
bool subscribe(Subscriber< MsgT > &s)
Definition: node_handle.h:335
void logerror(const char *msg)
Definition: node_handle.h:460
data
uint32_t last_msg_timeout_time
Definition: node_handle.h:159
uint32_t last_sync_time
Definition: node_handle.h:157
name
Definition: setup.py:5
uint32_t rt_time
Definition: node_handle.h:87
void logfatal(const char *msg)
Definition: node_handle.h:463
void negotiateTopics()
Definition: node_handle.h:374
virtual void callback(unsigned char *data)=0
virtual int publish(int id, const Msg *msg)
Definition: node_handle.h:405
virtual int deserialize(unsigned char *inbuffer)
Definition: Time.h:56
#define MODE_SIZE_CHECKSUM
Definition: node_handle.h:45
uint8_t level
Definition: Log.h:32
void loginfo(const char *msg)
Definition: node_handle.h:454
#define SYNC_SECONDS
Definition: node_handle.h:28
#define MODE_TOPIC_H
Definition: node_handle.h:47
virtual int spinOnce()=0
bool requestParam(const char *name, int time_out=1000)
Definition: node_handle.h:475
uint32_t last_sync_receive_time
Definition: node_handle.h:158
#define MODE_MESSAGE
Definition: node_handle.h:48
void setNow(Time &new_now)
Definition: node_handle.h:307
virtual int publish(int id, const Msg *msg)=0
ROSTIME_DECL void normalizeSecNSec(uint32_t &sec, uint32_t &nsec)
Definition: time.cpp:22
Hardware hardware_
Definition: node_handle.h:84
#define MODE_SIZE_H
Definition: node_handle.h:44
virtual bool connected()
Definition: node_handle.h:269
bool getParam(const char *name, int *param, int length=1)
Definition: node_handle.h:489
#define MODE_MSG_CHECKSUM
Definition: node_handle.h:49
const char * message_type
Definition: TopicInfo.h:34
bool getParam(const char *name, float *param, int length=1)
Definition: node_handle.h:500
bool getParam(const char *name, char **param, int length=1)
Definition: node_handle.h:511
#define MSG_TIMEOUT
Definition: node_handle.h:52
bool advertise(Publisher &p)
Definition: node_handle.h:320
void initNode(char *portName)
Definition: node_handle.h:138
#define MODE_FIRST_FF
Definition: node_handle.h:30
Hardware * getHardware()
Definition: node_handle.h:124
virtual int serialize(unsigned char *outbuffer) const =0
void requestSyncTime()
Definition: node_handle.h:277
#define PROTOCOL_VER
Definition: node_handle.h:42
rosserial_msgs::RequestParamResponse req_param_resp
Definition: node_handle.h:473
#define MODE_TOPIC_L
Definition: node_handle.h:46
bool advertiseService(ServiceServer< MReq, MRes > &srv)
Definition: node_handle.h:348
uint32_t sec_offset
Definition: node_handle.h:90
Definition: msg.h:26
bool serviceClient(ServiceClient< MReq, MRes > &srv)
Definition: node_handle.h:362
#define MODE_SIZE_L
Definition: node_handle.h:43
virtual int spinOnce()
Definition: node_handle.h:167
const char * msg
Definition: Log.h:33


cob_hand_bridge
Author(s): Mathias Lüdtke
autogenerated on Tue Oct 20 2020 03:35:57