PageRenderTime 53ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/vrpn_3Space.C

https://gitlab.com/sat-metalab/vrpn
C | 266 lines | 179 code | 30 blank | 57 comment | 49 complexity | 7bdf4ded9d73aed9e5cc356bb069be7a MD5 | raw file
  1. #include <ctype.h> // for isprint
  2. #include <math.h> // for sqrt
  3. #include <stdio.h> // for fprintf, stderr, perror, etc
  4. #include "quat.h" // for Q_W, Q_X, Q_Y, Q_Z
  5. #include "vrpn_3Space.h"
  6. #include "vrpn_BaseClass.h" // for ::vrpn_TEXT_ERROR, etc
  7. #include "vrpn_Serial.h" // for vrpn_write_characters, etc
  8. #include "vrpn_Shared.h" // for vrpn_SleepMsecs, etc
  9. #include "vrpn_Tracker.h" // for vrpn_TRACKER_FAIL, etc
  10. #include "vrpn_Types.h" // for vrpn_int16, vrpn_float64
  11. // This constant turns the tracker binary values in the range -32768 to
  12. // 32768 to meters.
  13. #define T_3_DATA_MAX (32768.0)
  14. #define T_3_INCH_RANGE (65.48)
  15. #define T_3_CM_RANGE (T_3_INCH_RANGE * 2.54)
  16. #define T_3_METER_RANGE (T_3_CM_RANGE / 100.0)
  17. #define T_3_BINARY_TO_METERS (T_3_METER_RANGE / T_3_DATA_MAX)
  18. void vrpn_Tracker_3Space::reset()
  19. {
  20. int i,resetLen,ret;
  21. unsigned char reset[10];
  22. // Send the tracker a string that should reset it. The first time we
  23. // try this, just do the normal ^Y reset. Later, try to reset
  24. // to the factory defaults. Then toggle the extended mode.
  25. // Then put in a carriage return to try and break it out of
  26. // a query mode if it is in one. These additions are cumulative: by the
  27. // end, we're doing them all.
  28. resetLen = 0;
  29. d_numResets++; // We're trying another reset
  30. if (d_numResets > 1) { // Try to get it out of a query loop if its in one
  31. reset[resetLen++] = (char) (13); // Return key -> get ready
  32. }
  33. if (d_numResets > 7) {
  34. reset[resetLen++] = 'Y'; // Put tracker into tracking (not point) mode
  35. }
  36. if (d_numResets > 3) { // Get a little more aggressive
  37. if (d_numResets > 4) { // Even more aggressive
  38. reset[resetLen++] = 't'; // Toggle extended mode (in case it is on)
  39. }
  40. reset[resetLen++] = 'W'; // Reset to factory defaults
  41. reset[resetLen++] = (char) (11); // Ctrl + k --> Burn settings into EPROM
  42. }
  43. reset[resetLen++] = (char) (25); // Ctrl + Y -> reset the tracker
  44. send_text_message("Resetting", timestamp, vrpn_TEXT_ERROR, d_numResets);
  45. for (i = 0; i < resetLen; i++) {
  46. if (vrpn_write_characters(serial_fd, &reset[i], 1) == 1) {
  47. vrpn_SleepMsecs(1000*2); // Wait 2 seconds each character
  48. } else {
  49. send_text_message("Failed writing to tracker", timestamp, vrpn_TEXT_ERROR, d_numResets);
  50. perror("3Space: Failed writing to tracker");
  51. status = vrpn_TRACKER_FAIL;
  52. return;
  53. }
  54. }
  55. vrpn_SleepMsecs(1000.0*10); // Sleep to let the reset happen
  56. // Get rid of the characters left over from before the reset
  57. vrpn_flush_input_buffer(serial_fd);
  58. // Make sure that the tracker has stopped sending characters
  59. vrpn_SleepMsecs(1000.0*2);
  60. unsigned char scrap[80];
  61. if ( (ret = vrpn_read_available_characters(serial_fd, scrap, 80)) != 0) {
  62. fprintf(stderr," 3Space warning: got >=%d characters after reset:\n",ret);
  63. for (i = 0; i < ret; i++) {
  64. if (isprint(scrap[i])) {
  65. fprintf(stderr,"%c",scrap[i]);
  66. } else {
  67. fprintf(stderr,"[0x%02X]",scrap[i]);
  68. }
  69. }
  70. fprintf(stderr, "\n");
  71. vrpn_flush_input_buffer(serial_fd); // Flush what's left
  72. }
  73. // Asking for tracker status
  74. if (vrpn_write_characters(serial_fd, (const unsigned char *) "S", 1) == 1) {
  75. vrpn_SleepMsecs(1000.0*1); // Sleep for a second to let it respond
  76. } else {
  77. perror(" 3Space write failed");
  78. status = vrpn_TRACKER_FAIL;
  79. return;
  80. }
  81. // Read Status
  82. unsigned char statusmsg[56];
  83. if ( (ret = vrpn_read_available_characters(serial_fd, statusmsg, 55)) != 55){
  84. fprintf(stderr, " Got %d of 55 characters for status\n",ret);
  85. }
  86. if ( (statusmsg[0]!='2') || (statusmsg[54]!=(char)(10)) ) {
  87. int i;
  88. statusmsg[55] = '\0'; // Null-terminate the string
  89. fprintf(stderr, " Tracker: status is (");
  90. for (i = 0; i < 55; i++) {
  91. if (isprint(statusmsg[i])) {
  92. fprintf(stderr,"%c",statusmsg[i]);
  93. } else {
  94. fprintf(stderr,"[0x%02X]",statusmsg[i]);
  95. }
  96. }
  97. fprintf(stderr, ")\n Bad status report from tracker, retrying reset\n");
  98. return;
  99. } else {
  100. send_text_message("Got status (tracker back up)!", timestamp, vrpn_TEXT_ERROR, 0);
  101. d_numResets = 0; // Success, use simple reset next time
  102. }
  103. // Set output format to be position,quaternion
  104. // These are a capitol 'o' followed by comma-separated values that
  105. // indicate data sets according to appendix F of the 3Space manual,
  106. // then followed by character 13 (octal 15).
  107. if (vrpn_write_characters(serial_fd, (const unsigned char *)"O2,11\015", 6) == 6) {
  108. vrpn_SleepMsecs(1000.0*1); // Sleep for a second to let it respond
  109. } else {
  110. perror(" 3Space write failed");
  111. status = vrpn_TRACKER_FAIL;
  112. return;
  113. }
  114. // Set data format to BINARY mode
  115. vrpn_write_characters(serial_fd, (const unsigned char *)"f", 1);
  116. // Set tracker to continuous mode
  117. if (vrpn_write_characters(serial_fd,(const unsigned char *) "C", 1) != 1)
  118. perror(" 3Space write failed");
  119. else {
  120. fprintf(stderr, " 3Space set to continuous mode\n");
  121. }
  122. fprintf(stderr, " (at the end of 3Space reset routine)\n");
  123. vrpn_gettimeofday(&timestamp, NULL); // Set watchdog now
  124. status = vrpn_TRACKER_SYNCING; // We're trying for a new reading
  125. }
  126. int vrpn_Tracker_3Space::get_report(void)
  127. {
  128. int ret;
  129. // The reports are each 20 characters long, and each start with a
  130. // byte that has the high bit set and no other bytes have the high
  131. // bit set. If we're synching, read a byte at a time until we find
  132. // one with the high bit set.
  133. if (status == vrpn_TRACKER_SYNCING) {
  134. // Try to get a character. If none, just return.
  135. if (vrpn_read_available_characters(serial_fd, buffer, 1) != 1) {
  136. return 0;
  137. }
  138. // If the high bit isn't set, we don't want it we
  139. // need to look at the next one, so just return
  140. if ( (buffer[0] & 0x80) == 0) {
  141. send_text_message("Syncing (high bit not set)", timestamp, vrpn_TEXT_WARNING);
  142. return 0;
  143. }
  144. // Got the first character of a report -- go into PARTIAL mode
  145. // and say that we got one character at this time.
  146. bufcount = 1;
  147. vrpn_gettimeofday(&timestamp, NULL);
  148. status = vrpn_TRACKER_PARTIAL;
  149. }
  150. // Read as many bytes of this 20 as we can, storing them
  151. // in the buffer. We keep track of how many have been read so far
  152. // and only try to read the rest. The routine that calls this one
  153. // makes sure we get a full reading often enough (ie, it is responsible
  154. // for doing the watchdog timing to make sure the tracker hasn't simply
  155. // stopped sending characters).
  156. ret = vrpn_read_available_characters(serial_fd, &buffer[bufcount],
  157. 20-bufcount);
  158. if (ret == -1) {
  159. send_text_message("Error reading, resetting", timestamp, vrpn_TEXT_ERROR);
  160. status = vrpn_TRACKER_FAIL;
  161. return 0;
  162. }
  163. bufcount += ret;
  164. if (bufcount < 20) { // Not done -- go back for more
  165. return 0;
  166. }
  167. { // Decode the report
  168. unsigned char decode[17];
  169. int i;
  170. const unsigned char mask[8] = {0x01, 0x02, 0x04, 0x08,
  171. 0x10, 0x20, 0x40, 0x80 };
  172. // Clear the MSB in the first byte
  173. buffer[0] &= 0x7F;
  174. // Decode the 3Space binary representation into standard
  175. // 8-bit bytes. This is done according to page 4-4 of the
  176. // 3Space user's manual, which says that the high-order bits
  177. // of each group of 7 bytes is packed into the 8th byte of the
  178. // group. Decoding involves setting those bits in the bytes
  179. // iff their encoded counterpart is set and then skipping the
  180. // byte that holds the encoded bits.
  181. // We decode from buffer[] into decode[] (which is 3 bytes
  182. // shorter due to the removal of the bit-encoding bytes).
  183. // decoding from buffer[0-6] into decode[0-6]
  184. for (i=0; i<7; i++) {
  185. decode[i] = buffer[i];
  186. if ( (buffer[7] & mask[i]) != 0) {
  187. decode[i] |= (unsigned char)(0x80);
  188. }
  189. }
  190. // decoding from buffer[8-14] into decode[7-13]
  191. for (i=7; i<14; i++) {
  192. decode[i] = buffer[i+1];
  193. if ( (buffer[15] & mask[i-7]) != 0) {
  194. decode[i] |= (unsigned char)(0x80);
  195. }
  196. }
  197. // decoding from buffer[16-18] into decode[14-16]
  198. for (i=14; i<17; i++) {
  199. decode[i] = buffer[i+2];
  200. if ( (buffer[19] & mask[i-14]) != 0) {
  201. decode[i] |= (unsigned char)(0x80);
  202. }
  203. }
  204. // Parse out sensor number, which is the second byte and is
  205. // stored as the ASCII number of the sensor, with numbers
  206. // starting from '1'. We turn it into a zero-based unit number.
  207. d_sensor = decode[1] - '1';
  208. // Position
  209. unsigned char * unbufPtr = &decode[3];
  210. pos[0] = vrpn_unbuffer_from_little_endian<vrpn_int16>(unbufPtr) * T_3_BINARY_TO_METERS;
  211. pos[1] = vrpn_unbuffer_from_little_endian<vrpn_int16>(unbufPtr) * T_3_BINARY_TO_METERS;
  212. pos[2] = vrpn_unbuffer_from_little_endian<vrpn_int16>(unbufPtr) * T_3_BINARY_TO_METERS;
  213. // Quarternion orientation. The 3Space gives quaternions
  214. // as w,x,y,z while the VR code handles them as x,y,z,w,
  215. // so we need to switch the order when decoding. Also the
  216. // tracker does not normalize the quaternions.
  217. d_quat[Q_W] = vrpn_unbuffer_from_little_endian<vrpn_int16>(unbufPtr);
  218. d_quat[Q_X] = vrpn_unbuffer_from_little_endian<vrpn_int16>(unbufPtr);
  219. d_quat[Q_Y] = vrpn_unbuffer_from_little_endian<vrpn_int16>(unbufPtr);
  220. d_quat[Q_Z] = vrpn_unbuffer_from_little_endian<vrpn_int16>(unbufPtr);
  221. //Normalize quaternion
  222. double norm = sqrt ( d_quat[0]*d_quat[0] + d_quat[1]*d_quat[1]
  223. + d_quat[2]*d_quat[2] + d_quat[3]*d_quat[3]);
  224. for (i=0; i<4; i++) {
  225. d_quat[i] /= norm;
  226. }
  227. // Done with the decoding, set the report to ready
  228. // Ready for another report
  229. status = vrpn_TRACKER_SYNCING;
  230. bufcount = 0;
  231. }
  232. return 1; // Got a report.
  233. #ifdef VERBOSE
  234. print_latest_report();
  235. #endif
  236. }