vrpn 07.36
Virtual Reality Peripheral Network
Loading...
Searching...
No Matches
vrpn_Tracker_Fastrak.C
Go to the documentation of this file.
1// vrpn_Tracker_Fastrak.C
2// This file contains the code to operate a Polhemus Fastrak Tracker.
3// This file is based on the vrpn_3Space.C file, with modifications made
4// to allow it to operate a Fastrak instead. The modifications are based
5// on the old version of the Fastrak driver, which had been mainly copied
6// from the Trackerlib driver and was very difficult to understand.
7// This version was written in the Summer of 1999 by Russ Taylor.
8// Modifications were made to this version to allow it to run the
9// Intersense IS600 tracker; basically, this involved allowing the user
10// to set extra things in the reset routine, and to pause to let the tracker
11// handle the parameter-setting commands.
12// Modifications were later made to support the IS-900 trackers,
13// including wands and styli.
14
15#include <ctype.h> // for isprint, isalpha
16#include <stdio.h> // for fprintf, snprintf, stderr, etc
17#include <stdlib.h> // for atoi
18#include <string.h> // for strlen, strtok
19
20#include "quat.h" // for Q_W, Q_X, Q_Y, Q_Z
21#include "vrpn_Analog.h" // for vrpn_Clipping_Analog_Server
22#include "vrpn_BaseClass.h" // for ::vrpn_TEXT_ERROR, etc
23#include "vrpn_Button.h" // for vrpn_Button_Server
24#include "vrpn_Connection.h" // for vrpn_Connection
25#include "vrpn_Serial.h" // for vrpn_write_characters, etc
26#include "vrpn_Shared.h" // for vrpn_SleepMsecs, timeval, etc
27#include "vrpn_Tracker.h" // for vrpn_TRACKER_FAIL, etc
28#include "vrpn_MessageMacros.h" // for VRPN_MSG_INFO, VRPN_MSG_WARNING, VRPN_MSG_ERROR
30
32 const char *port, long baud, int enable_filtering, int numstations,
33 const char *additional_reset_commands, int is900_timestamps) :
34 vrpn_Tracker_Serial(name,c,port,baud),
35 do_filter(enable_filtering),
37 num_resets(0),
38 do_is900_timestamps(is900_timestamps)
39{
40 int i;
41
42 reset_time.tv_sec = reset_time.tv_usec = 0;
43 if (additional_reset_commands == NULL) {
44 add_reset_cmd[0] = '\0';
45 } else {
46 vrpn_strcpy(add_reset_cmd, additional_reset_commands);
47 }
48
49 // Initially, set to no buttons or analogs on the stations. The
50 // methods to add buttons and analogs must be called to add them.
51 for (i = 0; i < num_stations; i++) {
52 is900_buttons[i] = NULL;
53 is900_analogs[i] = NULL;
54 }
55
56 // Let me assume I am an Intersense till proven false,
57 // by an instance of a fastrak-only command like "FTStylus"
58 // in the initialization strings.
59 really_fastrak = false;
60}
61
63{
64 int i;
65
66 // Delete any button and analog devices that were created
67 for (i = 0; i < num_stations; i++) {
68 try {
69 if (is900_buttons[i]) {
70 delete is900_buttons[i];
71 }
72 if (is900_analogs[i]) {
73 delete is900_analogs[i];
74 }
75 } catch (...) {
76 fprintf(stderr, "vrpn_Tracker_Fastrak::~vrpn_Tracker_Fastrak(): delete failed\n");
77 return;
78 }
79 }
80}
81
90
92{
93 char outstring[64];
94 const char *timestring;
95 const char *buttonstring;
96 const char *analogstring;
97
98 // Set output format for the station to be position and quaternion,
99 // and any of the extended Fastrak (stylus with button) or
100 // IS900 states (timestamp, button, analog).
101 // This command is a capitol 'o' followed by the number of the
102 // station, then comma-separated values (2 for xyz, 11 for quat, 21 for
103 // timestamp, 22 for buttons, 16 for Fastrak stylus button,
104 // 23 for joystick, 0 for space) that
105 // indicate data sets, followed by character 13 (octal 15).
106 // Note that the sensor number has to be bumped to map to station number.
107
108 timestring = do_is900_timestamps ? ",21" : "";
109 if (really_fastrak) {
110 buttonstring = is900_buttons[sensor] ? ",16" : "";
111 } else {
112 buttonstring = is900_buttons[sensor] ? ",22" : "";
113 }
114 analogstring = is900_analogs[sensor] ? ",23" : "";
115 snprintf(outstring, 64, "O%d,2,11%.3s%.3s%.3s,0\015", sensor+1, timestring,
116 buttonstring, analogstring);
117 if (vrpn_write_characters(serial_fd, (const unsigned char *)outstring,
118 strlen(outstring)) == (int)strlen(outstring)) {
119 vrpn_SleepMsecs(50); // Sleep for a bit to let command run
120 } else {
121 VRPN_MSG_ERROR("Write failed on format command");
123 return -1;
124 }
125
126 return 0;
127}
128
136
138{
139 int len;
140
141 len = 4; // Basic report, "0" plus Fastrak station char + status char + space at the end
142 len += 3*4; // Four bytes/float, 3 floats for position
143 len += 4*4; // Four bytes/float, 4 floats for quaternion
144
145 // Add in the timestamp (4 bytes of float) if it is present
147 len += 4;
148 }
149
150 // Add in the buttons (1 byte for IS900, 2 for Fastrak) if present
151 if (is900_buttons[sensor]) {
152 if (really_fastrak) {
153 len += 2;
154 } else {
155 len += 1;
156 }
157 }
158
159 // Add in the joystick (one byte each for two values) if present
160 if (is900_analogs[sensor]) {
161 len += 2*1;
162 }
163
164 return len;
165}
166
167// This routine will reset the tracker and set it to generate the types
168// of reports we want. It relies on the power-on configuration to set the
169// active sensors based on the 'Rcvr Select Switch', as described on page
170// 128 of the Fastrak manual printed November 1993.
171
173{
174 int i,resetLen,ret;
175 unsigned char reset[10];
176 char errmsg[512];
177
178 //--------------------------------------------------------------------
179 // This section deals with resetting the tracker to its default state.
180 // Multiple attempts are made to reset, getting more aggressive each
181 // time. This section completes when the tracker reports a valid status
182 // message after the reset has completed.
183 //--------------------------------------------------------------------
184
185 // Send the tracker a string that should reset it. The first time we
186 // try this, just do the normal 'c' command to put it into polled mode.
187 // after a few tries with this, use the ^Y reset. Later, try to reset
188 // to the factory defaults. Then toggle the extended mode.
189 // Then put in a carriage return to try and break it out of
190 // a query mode if it is in one. These additions are cumulative: by the
191 // end, we're doing them all.
192 resetLen = 0;
193 num_resets++; // We're trying another reset
194 if (num_resets > 1) { // Try to get it out of a query loop if its in one
195 reset[resetLen++] = (unsigned char) (13); // Return key -> get ready
196 }
197 if (num_resets > 5) {
198 reset[resetLen++] = 'Y'; // Put tracker into tracking (not point) mode
199 }
200 if (num_resets > 4) { // Even more aggressive
201 reset[resetLen++] = 't'; // Toggle extended mode (in case it is on)
202 }
203 /* XXX These commands are probably never needed, and can cause real
204 headaches for people who are keeping state in their trackers (especially
205 the InterSense trackers). Taking them out in version 05.01; you can put
206 them back in if your tracker isn't resetting as well.
207 if (num_resets > 3) { // Get a little more aggressive
208 reset[resetLen++] = 'W'; // Reset to factory defaults
209 reset[resetLen++] = (unsigned char) (11); // Ctrl + k --> Burn settings into EPROM
210 }
211 */
212 if (num_resets > 2) {
213 reset[resetLen++] = (unsigned char) (25); // Ctrl + Y -> reset the tracker
214 }
215 reset[resetLen++] = 'c'; // Put it into polled (not continuous) mode
216
217 snprintf(errmsg, 512, "Resetting the tracker (attempt %d)", num_resets);
218 VRPN_MSG_WARNING(errmsg);
219 for (i = 0; i < resetLen; i++) {
220 if (vrpn_write_characters(serial_fd, &reset[i], 1) == 1) {
221 fprintf(stderr,".");
222 vrpn_SleepMsecs(1000.0*2); // Wait after each character to give it time to respond
223 } else {
224 perror("Fastrak: Failed writing to tracker");
226 return;
227 }
228 }
229 //XXX Take out the sleep and make it keep spinning quickly
230 // You only need to sleep 10 seconds for an actual Fastrak.
231 // For the Intersense trackers, you need to sleep 20. So,
232 // sleeping 20 is the more general solution...
233 if (num_resets > 2) {
234 vrpn_SleepMsecs(1000.0*20); // Sleep to let the reset happen, if we're doing ^Y
235 }
236
237 fprintf(stderr,"\n");
238
239 // Get rid of the characters left over from before the reset
241
242 // Make sure that the tracker has stopped sending characters
243 vrpn_SleepMsecs(1000.0*2);
244 unsigned char scrap[80];
245 if ( (ret = vrpn_read_available_characters(serial_fd, scrap, 80)) != 0) {
246 snprintf(errmsg, 512,"Got >=%d characters after reset",ret);
247 VRPN_MSG_WARNING(errmsg);
248 for (i = 0; i < ret; i++) {
249 if (isprint(scrap[i])) {
250 fprintf(stderr,"%c",scrap[i]);
251 } else {
252 fprintf(stderr,"[0x%02X]",scrap[i]);
253 }
254 }
255 fprintf(stderr, "\n");
256 vrpn_flush_input_buffer(serial_fd); // Flush what's left
257 }
258
259 // Asking for tracker status
260 if (vrpn_write_characters(serial_fd, (const unsigned char *) "S", 1) == 1) {
261 vrpn_SleepMsecs(1000.0*1); // Sleep for a second to let it respond
262 } else {
263 perror(" Fastrak write failed");
265 return;
266 }
267
268 // Read Status
269 unsigned char statusmsg[56];
270
271 // Attempt to read 55 characters. For some reason, later versions of the
272 // InterSense IS900 only report a 54-character status message. If this
273 // happens, handle it.
274 ret = vrpn_read_available_characters(serial_fd, statusmsg, 55);
275 if ( (ret != 55) && (ret != 54) ) {
276 fprintf(stderr,
277 " Got %d of 55 characters for status (54 expected for IS900)\n",ret);
278 }
279 if ( (statusmsg[0]!='2') || (statusmsg[ret-1]!=(char)(10)) ) {
280 statusmsg[55] = '\0'; // Null-terminate the string
281 fprintf(stderr, " Fastrak: status is (");
282 for (int i = 0; i < ret; i++) {
283 if (isprint(statusmsg[i])) {
284 fprintf(stderr,"%c",statusmsg[i]);
285 } else {
286 fprintf(stderr,"[0x%02X]",statusmsg[i]);
287 }
288 }
289 fprintf(stderr,"\n)\n");
290 VRPN_MSG_ERROR("Bad status report from Fastrak, retrying reset");
291 return;
292 } else {
293 VRPN_MSG_WARNING("Fastrak/Isense gives status (this is good)");
294 num_resets = 0; // Success, use simple reset next time
295 }
296
297 //--------------------------------------------------------------------
298 // Now that the tracker has given a valid status report, set all of
299 // the parameters the way we want them. We rely on power-up setting
300 // based on the receiver select switches to turn on the receivers that
301 // the user wants.
302 //--------------------------------------------------------------------
303
304 // Set output format for each of the possible stations.
305
306 for (i = 0; i < num_stations; i++) {
308 return;
309 }
310 }
311
312 if (really_fastrak) {
313 char outstring[64];
314 snprintf(outstring, 64, "e1,0\r");
315 if (vrpn_write_characters(serial_fd, (const unsigned char *)outstring,
316 strlen(outstring)) == (int)strlen(outstring)) {
317 vrpn_SleepMsecs(50); // Sleep for a bit to let command run
318 } else {
319 VRPN_MSG_ERROR("Write failed on mouse format command");
321 }
322 }
323
324 // Enable filtering if the constructor parameter said to.
325 // Set filtering for both position (x command) and orientation (v command)
326 // to the values that are recommended as a "jumping off point" in the
327 // Fastrak manual.
328
329 if (do_filter) {
331 (const unsigned char *)"x0.2,0.2,0.8,0.8\015", 17) == 17) {
332 vrpn_SleepMsecs(1000.0*1); // Sleep for a second to let it respond
333 } else {
334 perror(" Fastrak write position filter failed");
336 return;
337 }
339 (const unsigned char *)"v0.2,0.2,0.8,0.8\015", 17) == 17) {
340 vrpn_SleepMsecs(1000.0*1); // Sleep for a second to let it respond
341 } else {
342 perror(" Fastrak write orientation filter failed");
344 return;
345 }
346 }
347
348 // Send the additional reset commands, if any, to the tracker.
349 // These commands come in lines, with character \015 ending each
350 // line. If a line start with an asterisk (*), treat it as a pause
351 // command, with the number of seconds to wait coming right after
352 // the asterisk. Otherwise, the line is sent directly to the tracker.
353 // Wait a while for them to take effect, then clear the input
354 // buffer.
355 if (strlen(add_reset_cmd) > 0) {
356 char *next_line;
357 char add_cmd_copy[sizeof(add_reset_cmd)+1];
358 char string_to_send[sizeof(add_reset_cmd)+1];
359 int seconds_to_wait;
360
361 printf(" Fastrak writing extended reset commands...\n");
362
363 // Make a copy of the additional reset string, since it is consumed
364 vrpn_strcpy(add_cmd_copy, add_reset_cmd);
365 add_cmd_copy[sizeof(add_cmd_copy)-1] = '\0';
366
367 // Pass through the string, testing each line to see if it is
368 // a sleep command or a line to send to the tracker. Continue until
369 // there are no more line delimiters ('\015'). Be sure to write the
370 // \015 to the end of the string sent to the tracker.
371 // Note that strok() puts a NULL character in place of the delimiter.
372
373 next_line = strtok(add_cmd_copy, "\015");
374 while (next_line != NULL) {
375 if (next_line[0] == '*') { // This is a "sleep" line, see how long
376 seconds_to_wait = atoi(&next_line[1]);
377 fprintf(stderr," ...sleeping %d seconds\n",seconds_to_wait);
378 vrpn_SleepMsecs(1000.0*seconds_to_wait);
379 } else { // This is a command line, send it
380 snprintf(string_to_send, sizeof(add_reset_cmd) + 1, "%.2040s\015", next_line);
381 fprintf(stderr, " ...sending command: %s\n", string_to_send);
383 (const unsigned char *)string_to_send,strlen(string_to_send));
384 }
385 next_line = strtok(next_line+strlen(next_line)+1, "\015");
386 }
387
388 // Sleep a little while to let this finish, then clear the input buffer
389 vrpn_SleepMsecs(1000.0*2);
391 }
392
393 // Set data format to BINARY mode
394 vrpn_write_characters(serial_fd, (const unsigned char *)"f", 1);
395
396 // Set tracker to continuous mode
397 if (vrpn_write_characters(serial_fd,(const unsigned char *) "C", 1) != 1) {
398 perror(" Fastrak write failed");
400 return;
401 } else {
402 fprintf(stderr, " Fastrak set to continuous mode\n");
403 }
404
405 // If we are using the IS-900 timestamps, clear the timer on the device and
406 // store the time when we cleared it. First, drain any characters in the output
407 // buffer to ensure we're sending right away. Then, send the reset command and
408 // store the time that we sent it, plus the estimated time for the characters to
409 // get across the serial line to the device at the current baud rate.
410 // Set time units to milliseconds (MT) and reset the time (MZ).
412 char clear_timestamp_cmd[] = "MT\015MZ\015";
413
415
416 if (vrpn_write_characters(serial_fd, (const unsigned char *)clear_timestamp_cmd,
417 strlen(clear_timestamp_cmd)) != (int)strlen(clear_timestamp_cmd)) {
418 VRPN_MSG_ERROR("Cannot send command to clear timestamp");
420 return;
421 }
422
423 // Drain the output buffer again, then record the time as the base time from
424 // the tracker.
427 }
428
429 // Done with reset.
430 vrpn_gettimeofday(&timestamp, NULL); // Set watchdog now
431 VRPN_MSG_WARNING("Reset Completed (this is good)");
432 status = vrpn_TRACKER_SYNCING; // We're trying for a new reading
433}
434
435// This function will read characters until it has a full report, then
436// put that report into the time, sensor, pos and quat fields so that it can
437// be sent the next time through the loop. The time stored is that of
438// the first character received as part of the report. Reports start with
439// the header "0xy", where x is the station number and y is either the
440// space character or else one of the characters "A-F". Characters "A-F"
441// indicate weak signals and so forth, but in practice it is much harder
442// to deal with them than to ignore them (they don't indicate hard error
443// conditions). The report follows, 4 bytes per word in little-endian byte
444// order; each word is an IEEE floating-point binary value. The first three
445// are position in X,Y and Z. The next four are the unit quaternion in the
446// order W, X,Y,Z. There are some optional fields for the Intersense 900
447// tracker, then there is an ASCII space character at the end.
448// If we get a report that is not valid, we assume that we have lost a
449// character or something and re-synchronize with the Fastrak by waiting
450// until the start-of-report character ('0') comes around again.
451// The routine that calls this one makes sure we get a full reading often
452// enough (ie, it is responsible for doing the watchdog timing to make sure
453// the tracker hasn't simply stopped sending characters).
454
456{
457 char errmsg[512]; // Error message to send to VRPN
458 int ret; // Return value from function call to be checked
459 int i; // Loop counter
460 unsigned char *bufptr; // Points into buffer at the current value to read
461
462 //--------------------------------------------------------------------
463 // Each report starts with an ASCII '0' character. If we're synching,
464 // read a byte at a time until we find a '0' character.
465 //--------------------------------------------------------------------
466
468 // Try to get a character. If none, just return.
470 return 0;
471 }
472
473 // If it is not an '0', we don't want it but we
474 // need to look at the next one, so just return and stay
475 // in Syncing mode so that we will try again next time through.
476 // Also, flush the buffer so that it won't take as long to catch up.
477 if ( buffer[0] != '0') {
478 snprintf(errmsg, 512,"While syncing (looking for '0', "
479 "got '%c')", buffer[0]);
480 VRPN_MSG_INFO(errmsg);
482 return 0;
483 }
484
485 // Got the first character of a report -- go into AWAITING_STATION mode
486 // and record that we got one character at this time. The next
487 // bit of code will attempt to read the station.
488 // The time stored here is as close as possible to when the
489 // report was generated. For the InterSense 900 in timestamp
490 // mode, this value will be overwritten later.
491 bufcount = 1;
494 }
495
496 //--------------------------------------------------------------------
497 // The second character of each report is the station number. Once
498 // we know this, we can compute how long the report should be for the
499 // given station, based on what values are in its report.
500 // The station number is converted into a VRPN sensor number, where
501 // the first Fastrak station is '1' and the first VRPN sensor is 0.
502 //--------------------------------------------------------------------
503
505 // Try to get a character. If none, just return.
507 return 0;
508 }
509
510 d_sensor = buffer[1] - '1'; // Convert ASCII 1 to sensor 0 and so on.
511 if ( (d_sensor < 0) || (d_sensor >= num_stations) ) {
513 snprintf(errmsg, 512,"Bad sensor # (%d) in record, re-syncing", d_sensor);
514 VRPN_MSG_INFO(errmsg);
516 return 0;
517 }
518
519 // Figure out how long the current report should be based on the
520 // settings for this sensor.
522
523 // Got the station report -- to into PARTIAL mode and record
524 // that we got one character at this time. The next bit of code
525 // will attempt to read the rest of the report.
526 bufcount++;
528 }
529
530 //--------------------------------------------------------------------
531 // Read as many bytes of this report as we can, storing them
532 // in the buffer. We keep track of how many have been read so far
533 // and only try to read the rest. The routine that calls this one
534 // makes sure we get a full reading often enough (ie, it is responsible
535 // for doing the watchdog timing to make sure the tracker hasn't simply
536 // stopped sending characters).
537 //--------------------------------------------------------------------
538
541 if (ret == -1) {
542 VRPN_MSG_ERROR("Error reading report");
544 return 0;
545 }
546 bufcount += ret;
547 if (bufcount < REPORT_LEN) { // Not done -- go back for more
548 return 0;
549 }
550
551 //--------------------------------------------------------------------
552 // We now have enough characters to make a full report. Check to make
553 // sure that its format matches what we expect. If it does, the next
554 // section will parse it. If it does not, we need to go back into
555 // synch mode and ignore this report. A well-formed report has the
556 // first character '0', the next character is the ASCII station
557 // number, and the third character is either a space or a letter.
558 //--------------------------------------------------------------------
559
560 if (buffer[0] != '0') {
562 VRPN_MSG_INFO("Not '0' in record, re-syncing");
564 return 0;
565 }
566 // Sensor checking was handled when we received the character for it
567 if ( (buffer[2] != ' ') && !isalpha(buffer[2]) ) {
569 VRPN_MSG_INFO("Bad 3rd char in record, re-syncing");
571 return 0;
572 }
573 if (buffer[bufcount-1] != ' ') {
575 VRPN_MSG_INFO("No space character at end of report, re-syncing");
577 return 0;
578 }
579
580 //--------------------------------------------------------------------
581 // Decode the X,Y,Z of the position and the W,X,Y,Z of the quaternion
582 // (keeping in mind that we store quaternions as X,Y,Z, W).
583 //--------------------------------------------------------------------
584 // The reports coming from the Fastrak are in little-endian order,
585 // which is the opposite of the network-standard byte order that is
586 // used by VRPN. Here we swap the order to big-endian so that the
587 // routines below can pull out the values in the correct order.
588 // This is slightly inefficient on machines that have little-endian
589 // order to start with, since it means swapping the values twice, but
590 // that is more than outweighed by the cleanliness gained by keeping
591 // all architecture-dependent code in the vrpn_Shared.C file.
592 //--------------------------------------------------------------------
593
594 // Point at the first value in the buffer (position of the X value)
595 bufptr = &buffer[3];
596
597 // When copying the positions, convert from inches to meters, since the
598 // Fastrak reports in inches and VRPN reports in meters.
599 pos[0] = vrpn_unbuffer_from_little_endian<vrpn_float32>(bufptr) * VRPN_INCHES_TO_METERS;
600 pos[1] = vrpn_unbuffer_from_little_endian<vrpn_float32>(bufptr) * VRPN_INCHES_TO_METERS;
601 pos[2] = vrpn_unbuffer_from_little_endian<vrpn_float32>(bufptr) * VRPN_INCHES_TO_METERS;
602
603 // Change the order of the quaternion fields to match quatlib order
604 d_quat[Q_W] = vrpn_unbuffer_from_little_endian<vrpn_float32>(bufptr);
605 d_quat[Q_X] = vrpn_unbuffer_from_little_endian<vrpn_float32>(bufptr);
606 d_quat[Q_Y] = vrpn_unbuffer_from_little_endian<vrpn_float32>(bufptr);
607 d_quat[Q_Z] = vrpn_unbuffer_from_little_endian<vrpn_float32>(bufptr);
608
609 //--------------------------------------------------------------------
610 // If we are doing IS900 timestamps, decode the time, add it to the
611 // time we zeroed the tracker, and update the report time. Remember
612 // to convert the MILLIseconds from the report into MICROseconds and
613 // seconds.
614 //--------------------------------------------------------------------
615
617 struct timeval delta_time; // Time since the clock was reset
618
619 // Read the floating-point value of the time from the record.
620 vrpn_float32 read_time = vrpn_unbuffer_from_little_endian<vrpn_float32>(bufptr);
621
622 // Convert from the float in MILLIseconds to the struct timeval
623 delta_time.tv_sec = (long)(read_time / 1000); // Integer trunction to seconds
624 read_time -= delta_time.tv_sec * 1000; // Subtract out what we just counted
625 delta_time.tv_usec = (long)(read_time * 1000); // Convert remainder to MICROseconds
626
627 // Store the current time
629 }
630
631 //--------------------------------------------------------------------
632 // If this sensor has an IS900 button or fastrak button on it, decode
633 // the button values into the button device and mainloop the button
634 // device so that it will report any changes. Each button is stored
635 // in one bit of the byte, with the lowest-numbered button in the
636 // lowest bit.
637 //--------------------------------------------------------------------
638
639 if (is900_buttons[d_sensor]) {
640 // the following section was modified by Debug to add support for Fastrak stylus button
641 int value;
642 if (really_fastrak) {
643 value=*(++bufptr)-'0'; // only one button, status in ASCII, skip over space
644 is900_buttons[d_sensor]->set_button(0, value);
645 } else {// potentially multiple buttons, values encoded in binary as a bit field
646 for (i = 0; i < is900_buttons[d_sensor]->number_of_buttons(); i++) {
647 value = ( (*bufptr) >> i) & 1;
648 is900_buttons[d_sensor]->set_button(i, value);
649 }
650 }
651 is900_buttons[d_sensor]->mainloop();
652
653 bufptr++;
654 }
655
656 //--------------------------------------------------------------------
657 // If this sensor has an IS900 analog on it, decode the analog values
658 // into the analog device and mainloop the analog device so that it
659 // will report any changes. The first byte holds the unsigned char
660 // representation of left/right. The second holds up/down. For each,
661 // 0 means min (left or rear), 127 means center and 255 means max.
662 //--------------------------------------------------------------------
663
664 if (is900_analogs[d_sensor]) {
665
666 // Read the raw values for the left/right and top/bottom channels
667 unsigned char raw_lr = *bufptr;
668 bufptr++;
669 unsigned char raw_tb = *bufptr;
670 bufptr++;
671
672 // Normalize the values to the range -1 to 1
673 is900_analogs[d_sensor]->setChannelValue(0, (raw_lr - 127) / 128.0);
674 is900_analogs[d_sensor]->setChannelValue(1, (raw_tb - 127) / 128.0);
675
676 // Report the new values
677 is900_analogs[d_sensor]->report_changes();
678 is900_analogs[d_sensor]->mainloop();
679 }
680
681 //--------------------------------------------------------------------
682 // Done with the decoding, set the report to ready
683 //--------------------------------------------------------------------
684
686 bufcount = 0;
687
688#ifdef VERBOSE2
690#endif
691
692 return 1;
693}
694
695
703
704int vrpn_Tracker_Fastrak::add_is900_button(const char *button_device_name, int sensor, int numbuttons)
705{
706 // Make sure this is a valid sensor
707 if ( (sensor < 0) || (sensor >= num_stations) ) {
708 return -1;
709 }
710
711 // Add a new button device and set the pointer to point at it.
712 try { is900_buttons[sensor] = new vrpn_Button_Server(button_device_name, d_connection, numbuttons); }
713 catch (...) {
714 VRPN_MSG_ERROR("Cannot open button device");
715 return -1;
716 }
717
718 // Send a new station-format command to the tracker so it will report the button states.
719 return set_sensor_output_format(sensor);
720}
721
722// this routine is called when an "FTStylus" button is encountered by the tracker init string parser
723// it sets up the VRPN button device & enables the switch "really_fastrak" that affects subsequent interpretation
724// of button readings - Debug
725int vrpn_Tracker_Fastrak::add_fastrak_stylus_button(const char *button_device_name, int sensor, int numbuttons)
726{
727 // Make sure this is a valid sensor
728 if ( (sensor < 0) || (sensor >= num_stations) ) {
729 return -1;
730 }
731
732 // Add a new button device and set the pointer to point at it.
733 try { is900_buttons[sensor] = new vrpn_Button_Server(button_device_name, d_connection, numbuttons); }
734 catch (...) {
735 VRPN_MSG_ERROR("Cannot open button device");
736 return -1;
737 }
738
739 // Debug's HACK here. Make sure it knows that it is a plain vanilla fastrak, so it will
740 // get the button output parameters right.
741 really_fastrak=true;
742
743 // Send a new station-format command to the tracker so it will report the button states.
744 return set_sensor_output_format(sensor);
745}
746
747
761
762int vrpn_Tracker_Fastrak::add_is900_analog(const char *analog_device_name, int sensor,
763 double c0Min, double c0Low, double c0Hi, double c0Max,
764 double c1Min, double c1Low, double c1Hi, double c1Max)
765{
766 // Make sure this is a valid sensor
767 if ( (sensor < 0) || (sensor >= num_stations) ) {
768 return -1;
769 }
770
771 // Add a new analog device and set the pointer to point at it.
772 try { is900_analogs[sensor] = new vrpn_Clipping_Analog_Server(analog_device_name, d_connection); }
773 catch (...) {
774 VRPN_MSG_ERROR("Cannot open analog device");
775 return -1;
776 }
777
778 // Set the analog to have two channels, and set its channels to 0 to start with
779 is900_analogs[sensor]->setNumChannels(2);
780 is900_analogs[sensor]->setChannelValue(0, 0.0);
781 is900_analogs[sensor]->setChannelValue(1, 0.0);
782
783 // Set the scaling on the two channels.
784 is900_analogs[sensor]->setClipValues(0, c0Min, c0Low, c0Hi, c0Max);
785 is900_analogs[sensor]->setClipValues(1, c1Min, c1Low, c1Hi, c1Max);
786
787 // Send a new station-format command to the tracker so it will report the analog status
788 return set_sensor_output_format(sensor);
789}
vrpn_Connection * d_connection
Connection that this object talks to.
int set_sensor_output_format(int sensor)
Augments the basic Fastrak format to include IS900 features if needed.
virtual int get_report(void)
Gets a report if one is available, returns 0 if not, 1 if complete report.
int report_length(int sensor)
Augments the basic Fastrak report length to include IS900 features if needed.
virtual void reset()
Reset the tracker.
int add_fastrak_stylus_button(const char *button_device_name, int sensor, int numbuttons=1)
vrpn_Clipping_Analog_Server * is900_analogs[vrpn_FASTRAK_MAX_STATIONS]
vrpn_Button_Server * is900_buttons[vrpn_FASTRAK_MAX_STATIONS]
int add_is900_analog(const char *analog_device_name, int sensor, double c0Min=-1, double c0Low=0, double c0Hi=0, double c0Max=1, double c1Min=-1, double c1Low=0, double c1Hi=0, double c1Max=1)
Add the analog part of an IS900 joystick device to one of the sensors This allows configuration of an...
vrpn_Tracker_Fastrak(const char *name, vrpn_Connection *c, const char *port="/dev/ttyS1", long baud=19200, int enable_filtering=1, int numstations=vrpn_FASTRAK_MAX_STATIONS, const char *additional_reset_commands=NULL, int is900_timestamps=0)
The constructor is given the name of the tracker (the name of the sender it should use),...
int add_is900_button(const char *button_device_name, int sensor, int numbuttons=5)
Add an IS900 button device to one of the sensors This allows configuration of an InterSense IS-900.
unsigned char buffer[VRPN_TRACKER_BUF_SIZE]
vrpn_Tracker_Serial(const char *name, vrpn_Connection *c, const char *port="/dev/ttyS1", long baud=38400)
vrpn_float64 d_quat[4]
vrpn_int32 d_sensor
vrpn_float64 pos[3]
void print_latest_report(void)
struct timeval timestamp
All types of client/server/peer objects in VRPN should be derived from the vrpn_BaseClass type descri...
Header containing macros formerly duplicated in a lot of implementation files.
#define VRPN_MSG_INFO(msg)
#define VRPN_MSG_ERROR(msg)
#define VRPN_MSG_WARNING(msg)
int vrpn_write_characters(int comm, const unsigned char *buffer, size_t bytes)
Write the buffer to the serial port.
int vrpn_flush_input_buffer(int comm)
Throw out any characters within the input buffer.
int vrpn_drain_output_buffer(int comm)
Wait until all of the characters in the output buffer are sent, then return.
int vrpn_read_available_characters(int comm, unsigned char *buffer, size_t bytes)
vrpn_Serial: Pulls all the serial port routines into one file to make porting to new operating system...
void vrpn_SleepMsecs(double dMilliSecs)
timeval vrpn_TimevalSum(const timeval &tv1, const timeval &tv2)
Definition vrpn_Shared.C:58
void vrpn_strcpy(char(&to)[charCount], const char *pSrc)
Null-terminated-string copy function that both guarantees not to overrun the buffer and guarantees th...
#define vrpn_gettimeofday
#define VRPN_INCHES_TO_METERS
Definition vrpn_Shared.h:14
const int vrpn_TRACKER_FAIL
const int vrpn_TRACKER_SYNCING
const int vrpn_TRACKER_PARTIAL
const int vrpn_TRACKER_AWAITING_STATION
class VRPN_API vrpn_Clipping_Analog_Server
const int vrpn_FASTRAK_MAX_STATIONS
class VRPN_API vrpn_Connection
class VRPN_API vrpn_Button_Server