vrpn  07.33
Virtual Reality Peripheral Network
vrpn_5DT16.C
Go to the documentation of this file.
1 // This is a driver for the 5dt Data Glove 16 sensors
2 // Look at www.5dt.com for more informations about this product
3 // Manuals are avalaible freely from this site
4 // The original code for 5dt was written by Philippe DAVID with the help of Yves GAUVIN
5 // This version for the 16 sensor version was written by Tom De Weyer
6 // naming convention used in this file:
7 // l_ is the prefixe for local variables
8 // g_ is the prefixe for global variables
9 // p_ is the prefixe for parameters
10 
11 #include <stdio.h> // for sprintf, fprintf, stderr
12 
13 #include "vrpn_5DT16.h"
14 #include "vrpn_BaseClass.h" // for ::vrpn_TEXT_ERROR, etc
15 #include "vrpn_Serial.h"
16 #include "vrpn_Shared.h" // for timeval, vrpn_SleepMsecs, etc
17 #include "vrpn_MessageMacros.h" // for VRPN_MSG_INFO, VRPN_MSG_WARNING, VRPN_MSG_ERROR
18 
19 #undef VERBOSE
20 
21 // Defines the modes in which the device can find itself.
22 #define STATUS_RESETTING (-1) // Resetting the device
23 #define STATUS_SYNCING (0) // Looking for the first character of report
24 #define STATUS_READING (1) // Looking for the rest of the report
25 
26 #define MAX_TIME_INTERVAL (2000000) // max time between reports (usec)
27 
28 
29 /******************************************************************************
30  * NAME : vrpn_5dt16::vrpn_5dt16
31  * ROLE : This creates a vrpn_5dt16 and sets it to reset mode. It opens
32  * the serial device using the code in the vrpn_Serial_Analog constructor.
33  * ARGUMENTS :
34  * RETURN :
35  ******************************************************************************/
36 vrpn_5dt16::vrpn_5dt16 (const char * p_name, vrpn_Connection * p_c, const char * p_port, int p_baud):
37  vrpn_Serial_Analog (p_name, p_c, p_port, p_baud, 8, vrpn_SER_PARITY_NONE),
38  _numchannels (17) // This is an estimate; will change when reports come
39 {
40  // Set the parameters in the parent classes
42 
43  // Set the status of the buttons and analogs to 0 to start
44  clear_values();
45 
46  // Set the mode to reset
48 }
49 
50 
51 /******************************************************************************
52  * NAME : vrpn_5dt16::clear_values
53  * ROLE :
54  * ARGUMENTS :
55  * RETURN :
56  ******************************************************************************/
58 {
59  int i;
60 
61  for (i = 0; i < _numchannels; i++) {
63  }
64 }
65 
66 
67 /******************************************************************************
68  * NAME : vrpn_5dt16::reset
69  * ROLE : This routine will reset the 5DT
70  * ARGUMENTS :
71  * RETURN : 0 else -1 in case of error
72  ******************************************************************************/
74 {
75  unsigned char l_inbuf [45];
76  int l_ret;
77  bool found=false;
78  struct timeval start, now;
79 
80  vrpn_gettimeofday(&start, NULL);
81  while(!found) // read the begin sequence of an info packet "<I"
82  {
83  l_ret = vrpn_read_available_characters (serial_fd, l_inbuf, 1);
84  if(l_ret!=1) {
85  vrpn_SleepMsecs (100); //Give it time to send data
86  } else if(l_inbuf[0] == '<' ) {
87  while(!vrpn_read_available_characters (serial_fd, l_inbuf, 1)) {
88  vrpn_SleepMsecs (100); //Give it time to send data
89  }
90  if(l_inbuf[0]=='I') {
91  found=true;
92  }
93  }
94  // See if we've timed out on the reset
95  vrpn_gettimeofday(&now, NULL);
96  if (now.tv_sec > start.tv_sec + 2) {
97  fprintf(stderr,"vrpn_5dt16::reset(): Timeout during reset\n");
98  return -1;
99  }
100  }
101  vrpn_SleepMsecs (100); //Give it time to send data
102  l_ret=vrpn_read_available_characters (serial_fd, l_inbuf, 5); // read the rest of the data
103  char text[50];
104  sprintf(text,"Hardware Version %i.0%i",l_inbuf[0],l_inbuf[1]); // hardware version
105  VRPN_MSG_WARNING(text);
106  if (l_inbuf[2] | 1) //right or left glove
107  {
108  VRPN_MSG_WARNING ("A right glove is ready");
109  } else {
110  VRPN_MSG_WARNING ("A left glove is ready");
111  }
112  if (l_inbuf[3] | 1) //wireless glove or wired
113  {
114  VRPN_MSG_WARNING ("no wireless glove");
115  } else {
116  VRPN_MSG_WARNING ("wireless glove");
117  }
118 
119  // We're now entering the syncing mode which send the read command to the glove
121  _bufcount = 0;
122 
123  vrpn_gettimeofday (&timestamp, NULL); // Set watchdog now
124  return 0;
125 }
126 
127 /******************************************************************************
128  * NAME : vrpn_5dt16::get_report
129  * ROLE : This function will read characters until it has a full report, then
130  * put that report into analog fields and call the report methods on these.
131  * ARGUMENTS : void
132  * RETURN : void
133  ******************************************************************************/
135 {
136  int l_ret; // Return value from function call to be checked
137 
138  // The official doc (http://www.5dt.com/downloads/5DTDataGlove5Manual.pdf)
139  // says we should get 36 bytes, but once in a while an info packet arrives and we should
140  // ignore that packet.
141  _expected_chars = 36;
142 
143  //--------------------------------------------------------------------
144  // Read as many bytes of this report as we can, storing them
145  // in the buffer. We keep track of how many have been read so far
146  // and only try to read the rest.
147  //--------------------------------------------------------------------
148 
151  if (l_ret == -1) {
152  VRPN_MSG_ERROR ("Error reading the glove");
154  return;
155  }
156 #ifdef VERBOSE
157  if (l_ret != 0) printf("... got %d characters (%d total)\n",l_ret, _bufcount);
158 #endif
159 
160  //--------------------------------------------------------------------
161  // The time of the report is the time at which the first character for
162  // the report is read.
163  //--------------------------------------------------------------------
164 
165  if ( (l_ret > 0) && (_bufcount == 0) ) {
167  }
168 
169  //--------------------------------------------------------------------
170  // We keep track of how many characters we have received and keep
171  // going back until we get as many as we expect.
172  //--------------------------------------------------------------------
173 
174  _bufcount += l_ret;
175  if (_bufcount < _expected_chars) { // Not done -- go back for more
176  return;
177  }
178 
179  //--------------------------------------------------------------------
180  // We now have enough characters to make a full report. First check to
181  // make sure that the first one is what we expect.
182 
183  if (!( (_buffer[0] == '<') && (_buffer[1] == 'D') ) ) //first characters need to be <D
184  {
185  VRPN_MSG_INFO ("Unexpected first character in report, probably info packet (recovering)");
186  for(int i=0;i<29;i++) {
187  _buffer[i]=_buffer[i+7];
188  }
189  _bufcount=29;
190  return;
191  }
192 
193 #ifdef VERBOSE
194  printf ("Got a complete report (%d of %d)!\n", _bufcount, _expected_chars);
195 #endif
196 
197  //--------------------------------------------------------------------
198  // Decode the report and store the values in it into the analog values
199  // if appropriate.
200  //--------------------------------------------------------------------
201 
202  for(int i=0;i<16;i++) {
203  channel[i]=_buffer[i*2+2]*256+_buffer[i*2+3];
204  }
205  char text[512];
206 
207  sprintf(text,"original %f|%f|%f|%f|%f|%f|%f|%f|%f|%f|%f|%f|%f|%f|%f|%f\n",channel[0],channel[1],channel[2],channel[3],channel[4],
208  channel[5],channel[6],channel[7],channel[8],channel[9],
209  channel[10],channel[11],channel[12],channel[13],channel[14],
210  channel[15]);
211  VRPN_MSG_ERROR(text);
212 
213  //--------------------------------------------------------------------
214  // Done with the decoding, send the reports and go back to syncing
215  //--------------------------------------------------------------------
216 
217  report_changes();
218  _bufcount =0;
219 }
220 
221 
222 /******************************************************************************
223  * NAME : vrpn_5dt16::report_changes
224  * ROLE :
225  * ARGUMENTS :
226  * RETURN : void
227  ******************************************************************************/
228 void vrpn_5dt16::report_changes (vrpn_uint32 class_of_service)
229 {
231  vrpn_Analog::report_changes(class_of_service);
232 }
233 
234 
235 /******************************************************************************
236  * NAME : vrpn_5dt16::report
237  * ROLE :
238  * ARGUMENTS :
239  * RETURN : void
240  ******************************************************************************/
241 void vrpn_5dt16::report (vrpn_uint32 class_of_service)
242 {
244  vrpn_Analog::report(class_of_service);
245 }
246 
247 
248 /******************************************************************************
249  * NAME : vrpn_5dt16::mainloop
250  * ROLE : This routine is called each time through the server's main loop. It will
251  * take a course of action depending on the current status of the device,
252  * either trying to reset it or trying to get a reading from it. It will
253  * try to reset the device if no data has come from it for a couple of
254  * seconds
255  * ARGUMENTS :
256  * RETURN : void
257  ******************************************************************************/
259 {
260  char l_errmsg[256];
261 
262  server_mainloop();
263 
264  switch (_status) {
265  case STATUS_RESETTING:
266  if (reset()== -1)
267  {
268  VRPN_MSG_ERROR ("vrpn_Analog_5dt: Cannot reset the glove!");
269  }
270  break;
271 
272  case STATUS_READING:
273  {
274  // It turns out to be important to get the report before checking
275  // to see if it has been too long since the last report. This is
276  // because there is the possibility that some other device running
277  // in the same server may have taken a long time on its last pass
278  // through mainloop(). Trackers that are resetting do this. When
279  // this happens, you can get an infinite loop -- where one tracker
280  // resets and causes the other to timeout, and then it returns the
281  // favor. By checking for the report here, we reset the timestamp
282  // if there is a report ready (ie, if THIS device is still operating).
283  get_report();
284  struct timeval current_time;
285  vrpn_gettimeofday(&current_time, NULL);
286  if ( vrpn_TimevalDuration(current_time,timestamp) > MAX_TIME_INTERVAL)
287  {
288  sprintf (l_errmsg, "vrpn_5dt16::mainloop: Timeout... current_time=%ld:%ld, timestamp=%ld:%ld",
289  current_time.tv_sec,
290  static_cast<long>(current_time.tv_usec),
291  timestamp.tv_sec,
292  static_cast<long>(timestamp.tv_usec));
293  VRPN_MSG_ERROR (l_errmsg);
295  }
296  }
297  break;
298 
299  default:
300  VRPN_MSG_ERROR ("vrpn_5dt16::mainloop: Unknown mode (internal error)");
301  break;
302  }
303 }
304 
305 vrpn_Button_5DT_Server::vrpn_Button_5DT_Server(const char *name, const char *deviceName,vrpn_Connection *c, double threshold[16]) : vrpn_Button_Filter(name, c)
306 {
307  num_buttons = 16;
308  for(int i=0;i<num_buttons;i++) {
309  m_threshold[i]=threshold[i];
310  }
312 #ifdef VERBOSE
313  printf("vrpn_Button_5DT_Server: Adding local analog %s\n",name);
314 #endif
315  // Set up the callback handler for the channel
317 }
318 
320 {
321 }
322 
323 // This routine handles updates of the analog values. The value coming in is
324 // adjusted per the parameters in the full axis description, and then used to
325 // update the value there. The value is used by the matrix-generation code in
326 // mainloop() to update the transformations; that work is not done here.
327 
329 {
331  for(int i=0;i<16;i++) { // adjust with range and center value
332  if(info.channel[i]>full->m_threshold[i] ) {
333  full->buttons[i]=true;
334  } else {
335  full->buttons[i]=false;
336  }
337  }
338 }
339 
341 {
342  struct timeval current_time;
343 
344  // Call the generic server mainloop, since we are a server
345  server_mainloop();
346 
348 
349  vrpn_gettimeofday(&current_time, NULL);
350  // Send reports. Stays the same in a real server.
351  report_changes();
352 }
353 
void server_mainloop(void)
Handles functions that all servers should provide in their mainloop() (ping/pong, for example) Should...
virtual void report_changes(vrpn_uint32 class_of_service=vrpn_CONNECTION_LOW_LATENCY, const struct timeval time=vrpn_ANALOG_NOW)
Send a report only if something has changed (for servers) Optionally, tell what time to stamp the val...
Definition: vrpn_Analog.C:71
void vrpn_SleepMsecs(double dMsecs)
Definition: vrpn_Shared.C:157
#define STATUS_RESETTING
Definition: vrpn_5DT16.C:22
static void VRPN_CALLBACK handle_analog_update(void *userdata, const vrpn_ANALOGCB info)
Definition: vrpn_5DT16.C:328
vrpn_int32 num_buttons
Definition: vrpn_Button.h:47
#define STATUS_READING
Definition: vrpn_5DT16.C:24
int _numchannels
Definition: vrpn_5DT16.h:29
Header containing macros formerly duplicated in a lot of implementation files.
vrpn_Serial: Pulls all the serial port routines into one file to make porting to new operating system...
vrpn_Button_5DT_Server(const char *name, const char *deviceName, vrpn_Connection *c, double threshold[16])
Definition: vrpn_5DT16.C:305
vrpn_Analog_Remote * d_5dt_button
Definition: vrpn_5DT16.h:71
virtual void mainloop()
Called once through each main loop iteration to handle updates.
Definition: vrpn_5DT16.C:258
vrpn_float64 channel[vrpn_CHANNEL_MAX]
Definition: vrpn_Analog.h:38
virtual void mainloop()
Called once through each main loop iteration to handle updates. Remote object mainloop() should call ...
Definition: vrpn_5DT16.C:340
virtual int reset(void)
Definition: vrpn_5DT16.C:73
Generic connection class not specific to the transport mechanism.
vrpn_5dt16(const char *name, vrpn_Connection *c, const char *port, int baud=19200)
Definition: vrpn_5DT16.C:36
virtual void report(vrpn_uint32 class_of_service=vrpn_CONNECTION_LOW_LATENCY, const struct timeval time=vrpn_ANALOG_NOW)
Send a report whether something has changed or not (for servers) Optionally, tell what time to stamp ...
Definition: vrpn_Analog.C:94
#define VRPN_MSG_WARNING(msg)
unsigned char _buffer[512]
Definition: vrpn_5DT16.h:32
struct timeval timestamp
Definition: vrpn_5DT16.h:36
All types of client/server/peer objects in VRPN should be derived from the vrpn_BaseClass type descri...
virtual void report_changes(void)
Definition: vrpn_Button.C:382
vrpn_int32 num_channel
Definition: vrpn_Analog.h:40
int vrpn_read_available_characters(int comm, unsigned char *buffer, size_t bytes)
Definition: vrpn_Serial.C:512
vrpn_Connection * d_connection
Connection that this object talks to.
vrpn_float64 channel[vrpn_CHANNEL_MAX]
Definition: vrpn_Analog.h:171
int _status
Definition: vrpn_5DT16.h:28
#define VRPN_MSG_INFO(msg)
virtual int register_change_handler(void *userdata, vrpn_ANALOGCHANGEHANDLER handler)
Definition: vrpn_Analog.h:192
#define MAX_TIME_INTERVAL
Definition: vrpn_5DT16.C:26
virtual void report_changes(vrpn_uint32 class_of_service=vrpn_CONNECTION_LOW_LATENCY)
send report iff changed
Definition: vrpn_5DT16.C:228
virtual void mainloop()
Called once through each main loop iteration to handle updates. Remote object mainloop() should call ...
Definition: vrpn_Analog.C:328
virtual void clear_values(void)
Definition: vrpn_5DT16.C:57
unsigned _bufcount
Definition: vrpn_5DT16.h:33
#define vrpn_gettimeofday
Definition: vrpn_Shared.h:89
virtual void report(vrpn_uint32 class_of_service=vrpn_CONNECTION_LOW_LATENCY)
send report whether or not changed
Definition: vrpn_5DT16.C:241
All button servers should derive from this class, which provides the ability to turn any of the butto...
Definition: vrpn_Button.h:65
double m_threshold[16]
Definition: vrpn_5DT16.h:72
unsigned char buttons[vrpn_BUTTON_MAX_BUTTONS]
Definition: vrpn_Button.h:44
unsigned long vrpn_TimevalDuration(struct timeval endT, struct timeval startT)
Return number of microseconds between startT and endT.
Definition: vrpn_Shared.C:129
virtual void get_report(void)
Definition: vrpn_5DT16.C:134
#define VRPN_MSG_ERROR(msg)
unsigned _expected_chars
Definition: vrpn_5DT16.h:31
struct timeval timestamp
Definition: vrpn_Analog.h:41
vrpn_float64 last[vrpn_CHANNEL_MAX]
Definition: vrpn_Analog.h:39