h4r_x52_joyext
LED and MFD Control for Saitek X52 Pro
 All Classes Files Functions Variables Enumerator Macros Pages
mfd_writer.cpp
Go to the documentation of this file.
1 /*
2  * Mfd Writer Node
3  * by Christian Holl (www.rad-lab.net)
4  * License: BSD
5  *
6  * Have Fun! :-)
7  */
8 
143 #include <ros/ros.h>
144 #include <string>
145 #include <vector>
146 #include <set>
147 #include <limits>
148 #include <iostream>
149 #include <sstream>
150 #include <std_msgs/Float32.h>
151 #include <std_msgs/Float64.h>
152 #include <std_msgs/Int8.h>
153 #include <std_msgs/Int16.h>
154 #include <std_msgs/Int32.h>
155 #include <std_msgs/Int64.h>
156 #include <std_msgs/UInt8.h>
157 #include <std_msgs/UInt16.h>
158 #include <std_msgs/UInt32.h>
159 #include <std_msgs/UInt64.h>
160 
161 
162 
163 #include <std_msgs/Bool.h>
164 #include <boost/algorithm/string.hpp>
165 #include <sensor_msgs/Joy.h>
166 #include <h4r_x52_joyext/x52_mfd.h>
167 
168 enum
169 {
182 };
183 
184 template<typename T>
186 {
187  enum
188  {
190  };
191 
192 private:
193  class PairSortMod: public std::pair<std::string, T>
194  {
195  public:
196  bool operator<(const PairSortMod& other) const
197  {
198  return this->second < other.second;
199  }
200 
201  };
202  std::set<PairSortMod> ranges;
203  ros::NodeHandle *n;
204  ros::Publisher pub;
205  ros::Subscriber sub;
206 
207  int line;
208  int pos;
210  int align;
211  std::string positive_oversize;
212  std::string negative_oversize;
215  bool stringprint;
216  std::string stringprint_setup;
218 
219 public:
220  PublishMFD(ros::NodeHandle *n) :
221  n(n)
222  {
223  //Get the parameters
224  n->param<int>("line", line, 0);
225  n->param<int>("pos", pos, 0);
226  n->param<int>("field_length", field_length, 16);
227  n->param<int>("align", align, 0);
228  n->param<std::string>("positive_oversize", positive_oversize, "#");
229  n->param<std::string>("negative_oversize", negative_oversize, "#");
230  n->param<bool>("axis_or_button", axis_or_button, 0);
231  n->param<int>("axis_button", axis_button, 0);
232  n->param<bool>("stringprint", stringprint, 0);
233  n->param<std::string>("stringprint_setup", stringprint_setup, "");
234  n->param<int>("char_as_int", char_as_int, 0);
235 
236  if(char_as_int!=0)
237  ROS_WARN("%s: char_as_int = %i (assuming 0 -> interpred as char)",ros::this_node::getName().c_str(), char_as_int);
238 
239 
240  if (field_length + pos > 16)
241  {
242  ROS_ERROR("%s: Field does not fit into display, will be cut!",
243  ros::this_node::getName().c_str());
244  field_length -= (field_length + pos) - 16;
245  }
246 
247  if (field_length == 0)
248  {
249  ROS_ERROR("%s: Field length is zero!",
250  ros::this_node::getName().c_str());
251  }
252 
253 
254  if (stringprint)
255  {
256  std::vector<std::string> separatedSetup;
257  boost::split(separatedSetup, stringprint_setup,
258  boost::is_any_of("|"));
259  ROS_INFO("%s",stringprint_setup.c_str());
260  PairSortMod pair;
261  unsigned int i;
262 
263  for (i = 0; i < separatedSetup.size(); ++i)
264  {
265  if ((i + 1) % 2)
266  {
267  if (separatedSetup[i].size() > field_length)
268  {
269  ROS_ERROR("%s: String: %s too big for field!",
270  ros::this_node::getName().c_str(),
271  separatedSetup[i].c_str());
272  separatedSetup[i].erase(field_length,
273  separatedSetup[i].size() - field_length);
274  }
275  pair.first = separatedSetup[i];
276  ROS_INFO("%s",separatedSetup[i].c_str());
277  }
278  else
279  {
280  std::istringstream ss(separatedSetup[i]);
281  T value;
282  ss>>value;
283  if(ss.bad() || ss.fail() || !ss.eof())
284  {
285  ROS_ERROR("Error in setup string: %s",separatedSetup[i].c_str());
286  exit(1);
287  }
288  pair.second=value;
289  this->ranges.insert(pair);
290  }
291  }
292 
293  if (!i % 2 || i == 0)
294  {
295  ROS_ERROR("Error in setup string, missing string for upper end!");
296  exit(1);
297  }
298  //Get last one
299  pair.second = std::numeric_limits<T>::max();
300  this->ranges.insert(pair);
301 
302  }
303 
304  pub = n->advertise<h4r_x52_joyext::x52_mfd>("mfd_text", 1,1);
305  h4r_x52_joyext::x52_mfd init_msg;
306  init_msg.clearDisplay=false;
307  init_msg.line=line;
308  init_msg.pos=pos;
309  for (int i = 0; i < field_length; ++i) {
310  init_msg.data+="-";
311  }
312  pub.publish(init_msg);
313  }
315  {
316  }
317 
318 
319  template <typename V>
320  std::string get_value_string(V value)
321  {
322 
323  h4r_x52_joyext::x52_mfd msg;
324  std::ostringstream ss;
325  std::string value_string;
326  ss<<value;
327 
328 
329  return ss.str();
330 
331  }
332 
333  std::string get_value_string(char value)
334  {
335  h4r_x52_joyext::x52_mfd msg;
336  std::ostringstream ss;
337  std::string value_string;
338 
339  //std::cout<<"::"<<value<<"\n";
340  {
341  ROS_ERROR("%s: Error in creating (char) value string",ros::this_node::getName().c_str());
342 
343  ss.clear();
344 
345  for(int c = 0; c < field_length; ++c)
346  {
347  ss<<'E';
348  }
349  }
350 
351  if(char_as_int==1)
352  {
353  if(value!=0)
354  ss<<(signed int)value;
355  }
356  else if(char_as_int==2)
357  {
358  ss<<(unsigned int)value;
359  }
360  else
361  {
362  ss<<value;
363  }
364 
365  return ss.str();
366  }
367 
368 
369 
370 
371 
372  template <typename V>
373  void progressValue(V value)
374  {
375  h4r_x52_joyext::x52_mfd msg;
376  msg.clearDisplay = false;
377  if (stringprint)
378  {
379  //Get the right value
380  for (typename std::set<PairSortMod>::iterator it = ranges.begin();
381  it != ranges.end(); ++it)
382  {
383  if (it->second > value)
384  {
385  msg.pos = pos;
386  msg.line = line;
387  msg.data = it->first;
388  break;
389  }
390  }
391  }
392  else
393  {
394  msg.clearDisplay = false;
395  msg.pos = pos;
396  msg.line = line;
397  msg.data=get_value_string(value);
398 
399  }
400 
401 
402 
403 
404  if (msg.data.length() < field_length)
405  {
406  switch (align)
407  {
408  default:
409  case LEFT: //filling up the field to overwrite chars not needed
410  for (int s = 0; s < (msg.data.length() - field_length); ++s)
411  {
412  msg.data.push_back(' ');
413  }
414  break;
415 
416  case CENTER: //shift string the size difference devided by two to the right
417  for (int s = 0; s < ((msg.data.length() - field_length) / 2); ++s)
418  {
419  if(s%2)
420  msg.data.insert(0, " ");
421  else
422  msg.data.push_back(' ');
423  }
424  ;
425  break;
426 
427  case RIGHT: //shift string the size difference to the right
428  for (int s = 0; s < (msg.data.length() - field_length); ++s)
429  {
430  msg.data.insert(0, " ");
431  }
432  ;
433  break;
434  }
435  }
436  else if(msg.data.length()>field_length)
437  {
438  //Decimal point position
439  int dec_pos=msg.data.find('.');
440 
441  std::cout<<msg.data<<std::endl;
442  if(dec_pos >= 0 && dec_pos==field_length-1) //decimal is the last what fits into field
443  {
444  msg.data.erase(dec_pos,field_length-dec_pos);//erase everything after dec_pos including dec_pos
445  }
446  else if(dec_pos >= 0 && dec_pos<field_length-1)//decimal point is not the last what fits into field
447  {
448  msg.data.erase(field_length-1,msg.data.length()-field_length);//cut off everything whats longer than field
449  }
450  else //The string is over size for that field!
451  {
452  if(value>0)
453  {
454  msg.data=positive_oversize;
455  }
456  else
457  {
458  msg.data=negative_oversize;
459  }
460  }
461  }
462  pub.publish(msg);
463  }
464 
465  void JoyCallback(const sensor_msgs::JoyConstPtr &msg)
466  {
467  if (axis_or_button == false) //Axis
468  {
469  if (axis_button < (int) msg->axes.size() && axis_button >= 0)
470  {
471  progressValue<double>(msg->axes[axis_button]);
472  }
473  else
474  {
475  ROS_ERROR("Axis %i not available for that Joystick!",
476  axis_button);
477  }
478  }
479  else
480  {
481  if (axis_button < (int) msg->buttons.size() && axis_button >= 0)
482  {
483  progressValue<bool>(msg->buttons[axis_button]);
484  }
485  else
486  {
487  ROS_ERROR("Button %i not available for that Joystick!",
488  axis_button);
489  }
490  }
491  }
492 
493  template<class MSGPTR>
494  void Callback(const MSGPTR& msg)
495  {
496  progressValue(msg->data);
497  }
498 
499  template<class MSG, class MSGPTR>
500  void start()
501  {
502  sub = n->subscribe<MSG>("in", 1000, &PublishMFD<T>::Callback<MSGPTR>,
503  this);
504  ros::spin();
505  }
506 
507  void startJoy()
508  {
509  sub = n->subscribe<sensor_msgs::Joy>("in", 1000,
511  ros::spin();
512  }
513 
514 };
515 
522 int main(int argc, char **argv)
523 {
524  ros::init(argc, argv, "mfd_writer");
525  ros::NodeHandle n("~");
526 
527 #define casem(CASE,TYPE,TYPEROS)\
528  case CASE:\
529  {\
530  PublishMFD< TYPE > obj(&n);\
531  obj.start<std_msgs::TYPEROS, std_msgs:: TYPEROS## ConstPtr>();\
532  break;\
533  }\
534 
535  int type=0;
536  n.param<int>("input_type", type, INPUT_FLOAT64);
537  switch (type)
538  {
539  casem(INPUT_FLOAT64, double_t, Float64)
540  casem(INPUT_FLOAT32, float_t, Float32)
541  casem(INPUT_INT64, int64_t, Int64)
542  casem(INPUT_INT32, int32_t, Int32)
543  casem(INPUT_INT16, int16_t, Int16)
544  casem(INPUT_INT8, int8_t, Int8)
545  casem(INPUT_UINT64, uint64_t, UInt64)
546  casem(INPUT_UINT32, uint32_t, UInt32)
547  casem(INPUT_UINT16, uint16_t, UInt16)
548  casem(INPUT_UINT8, uint8_t, UInt8)
549  casem(INPUT_BOOL, bool, Bool)
550  case INPUT_JOY:
551  {
552  PublishMFD<double> obj(&n);
553  obj.startJoy();
554  break;
555  }
556  default:
557  ROS_ERROR("Unkown Input Type %i!",type);
558  break;
559  }
560 
561  return 0;
562 }
std::string positive_oversize
String to show if the integer part of a value is bigger then the size (positiv)
Definition: mfd_writer.cpp:211
ros::Publisher pub
The publisher.
Definition: mfd_writer.cpp:204
int line
The line where the string will be placed.
Definition: mfd_writer.cpp:207
void startJoy()
Definition: mfd_writer.cpp:507
void start()
Definition: mfd_writer.cpp:500
bool operator<(const PairSortMod &other) const
Definition: mfd_writer.cpp:196
ros::NodeHandle * n
The node handler.
Definition: mfd_writer.cpp:203
std::string get_value_string(char value)
Definition: mfd_writer.cpp:333
bool axis_or_button
Joy topic addition.
Definition: mfd_writer.cpp:213
PublishMFD(ros::NodeHandle *n)
A char is interpreted as integer if this is 1 or as unsigned integer if this is 2 and as char on any ...
Definition: mfd_writer.cpp:220
bool stringprint
If this is true, there will be strings instead of values.
Definition: mfd_writer.cpp:215
#define casem(CASE, TYPE, TYPEROS)
std::string negative_oversize
String to show if the integer part of a value is bigger then the size (negative)
Definition: mfd_writer.cpp:212
int pos
Position from the beginning of the line.
Definition: mfd_writer.cpp:208
std::set< PairSortMod > ranges
Definition: mfd_writer.cpp:202
void Callback(const MSGPTR &msg)
Definition: mfd_writer.cpp:494
int align
Align of the text in the field, 0=Left, 1=Center, 2 (or anything else)=Right.
Definition: mfd_writer.cpp:210
std::string stringprint_setup
if stringprint is enabled, this will store the strings to be displayed
Definition: mfd_writer.cpp:216
ros::Subscriber sub
The subscriber.
Definition: mfd_writer.cpp:205
void progressValue(V value)
Definition: mfd_writer.cpp:373
int main(int argc, char **argv)
Definition: mfd_writer.cpp:522
std::string get_value_string(V value)
Definition: mfd_writer.cpp:320
int field_length
Field length.
Definition: mfd_writer.cpp:209
void JoyCallback(const sensor_msgs::JoyConstPtr &msg)
Definition: mfd_writer.cpp:465
int axis_button
The button or axis number if using Joy topic.
Definition: mfd_writer.cpp:214