vrpn  07.33
Virtual Reality Peripheral Network
vrpn_Joywin32.C
Go to the documentation of this file.
1 
2 #include "vrpn_Joywin32.h"
3 
4 #if defined(_WIN32)
5 
6 #pragma comment(lib,"winmm.lib")
7 #include "vrpn_Shared.h"
8 #include <windows.h>
9 #include <stdio.h>
10 #include <cmath>
11 #include <algorithm>
12 // vrpn_Joywin32.C
13 // This is a driver for joysticks being used through the
14 // Win32 basic interface.
15 // The driver portions of this code are based on the Microsoft MSDN
16 // and tutorial from DigiBen at gametutorials.com
17 
18 #undef VERBOSE
19 
20 // Defines the modes in which the box can find itself.
21 const int STATUS_BROKEN = -1; // Broken joystick
22 const int STATUS_READING = 1; // Looking for a report
23 const int CENTERED_VALUE = -1; // returned value for centered POV
24 
25 #define MAX_TIME_INTERVAL (2000000) // max time to try and reacquire
26 
27 vrpn_Joywin32::vrpn_Joywin32 (const char * name, vrpn_Connection * c, vrpn_uint8 joyNumber, vrpn_float64 readRate, vrpn_uint8 mode, vrpn_int32 deadzone) :
28  vrpn_Analog(name, c),
29  vrpn_Button_Filter(name, c),
30  _read_rate(readRate),
31  _joyNumber(joyNumber),
32  _numchannels((std::min)(12,vrpn_CHANNEL_MAX)), // Maximum available
33  _numbuttons((std::min)(128,vrpn_BUTTON_MAX_BUTTONS)), // Maximum available
34  _mode(mode)
35 {
36  last_error_report.tv_sec = 0;
37  last_error_report.tv_usec = 0;
38 
39  if (deadzone >100 || deadzone<0) {
40  fprintf(stderr,"invalid deadzone, (should be a percentage between 0 and 100).\n");
41  _status = STATUS_BROKEN;
42  return;
43  }
44 
45  if (_mode >2) {
46  fprintf(stderr,"invalid mode, should be 0 (raw), 1 (normalized to 0,1) or 2 (normalized to -1,1).\n");
47  _status = STATUS_BROKEN;
48  return;
49  }
50 
51  if (_read_rate <0 ) {
52  fprintf(stderr,"invalid read rate, should be positive.\n");
53  _status = STATUS_BROKEN;
54  return;
55  }
56 
57  if (_numchannels < 12) {
58  fprintf(stderr,"vrpn_JoyWin32::vrpn_JoyWin32(): Not enough analog channels!\n");
59  _status = STATUS_BROKEN;
60  return;
61  }
62 
63  _deadzone = deadzone / 100.0;
64 
65  // initialize the joystick
66  init_joystick();
67 }
68 
69 void vrpn_Joywin32::init_joystick(void)
70 {
71  DWORD dwResult = 0;
72 
73  // This function below return the number of joysticks the driver supports.
74  // If it returns 0 then there is no joystick driver installed.
75 
76  if (!joyGetNumDevs())
77  {
78  fprintf(stderr,"There are no joystick devices installed.\n");
79  _status = STATUS_BROKEN;
80  return;
81  }
82 
83  if(_joyNumber > joyGetNumDevs()) {
84  fprintf(stderr,"There are not %d joysticks devices installed, unable to get joystick id %d.\n", _joyNumber, _joyNumber);
85  _status = STATUS_BROKEN;
86  return;
87  }
88 
89  // initialize requested joystick
90  // polling every 10 ms.
91  JOYINFO tempJoyInfo;
92  dwResult = joyGetPos (_joyNumber-1, &tempJoyInfo);
93 
94  // Let's check what the return value was from joySetCapture()
95  // - If the joystick is unplugged, say so.
96  // - If there is no driver installed, say so
97  // - If we can access the joystick for some strange reason, say so
98  // Otherwise, let's return a SUCCESS!
99  // You don't need to do this, but it helps the user solve the problem if there is one.
100  // Error checking is VERY important, and employers want to see you use it.
101 
102  switch (dwResult)
103  {
104  case JOYERR_UNPLUGGED: // The joystick is unplugged
105  fprintf(stderr, "Please plug in the joystick first.\n");
106  _status = STATUS_BROKEN;
107  return;
108  case MMSYSERR_NODRIVER: // There is no driver for a joystick
109  fprintf(stderr, "No valid joystick driver.\n");
110  _status = STATUS_BROKEN;
111  return; // Return failure
112  case JOYERR_PARMS:
113  fprintf(stderr, "Bad joystick parameters.\n");
114  _status = STATUS_BROKEN;
115  return; // return failure
116  case JOYERR_NOCANDO: // Unknown error, try restarting
117  fprintf(stderr, "Couldn't capture joystick input, try restarting.\n");
118  _status = STATUS_BROKEN;
119  return; // return failure
120  }
121 
122  // get joystick caps
123  if (joyGetDevCaps(_joyNumber-1, &_jc, sizeof(_jc)) != JOYERR_NOERROR){
124  fprintf(stderr, "Unable to get joystick capabilities.\n");
125  _status = STATUS_BROKEN;
126  return;
127  }
128 
129  /* set size of data, deprecated
130  // _numchannels = _jc.wNumAxes;
131  // _numbuttons = _jc.wNumButtons;
132 
133  if (_jc.wCaps & JOYCAPS_HASPOV) {
134  _numchannels++;
135  }*/
136 
137  vrpn_Analog::num_channel = _numchannels;
138  vrpn_Button::num_buttons = _numbuttons;
139 
140  fprintf(stderr, "Joystick (%s) has %d axes and %d buttons.\n",
141  _jc.szPname, _jc.wNumAxes+(JOYCAPS_HASPOV?1:0), _jc.wNumButtons);
142 
143  // Set the mode to reading. Set time to zero, so we'll try to read
144  _status = STATUS_READING;
145  vrpn_gettimeofday(&_timestamp, NULL);
146 }
147 
148 void vrpn_Joywin32::clear_values(void)
149 {
150  vrpn_uint32 i;
151 
152  for (i = 0; i < _numbuttons; i++) {
154  }
155  for (i = 0; i < _numchannels; i++) {
157  }
158 }
159 
160 // This function will send a report if any of the analog or button values
161 // have changed. This reads from the joystick _read_rate times per second, returns
162 // right away at other times.
163 // Returns 0 on success, -1 (and sets _status) on failure.
164 
165 int vrpn_Joywin32::get_report(void)
166 {
167  // If it is not time for the next read, just return
168  struct timeval reporttime;
169  vrpn_gettimeofday(&reporttime, NULL);
170  if (vrpn_TimevalDuration(reporttime, _timestamp) < 1000000.0 / _read_rate) {
171  return 0;
172  }
173 #ifdef VERBOSE
174  printf(" now: %ld:%ld, last %ld:%ld\n", reporttime.tv_sec, reporttime.tv_usec,
175  _timestamp.tv_sec, static_cast<long>(_timestamp.tv_usec));
176  printf(" win32 joystick: Getting report\n");
177 #endif
178 
179  // update channels and buttons state :
180  JOYINFOEX jie;
181  jie.dwFlags = JOY_RETURNALL;//JOY_RETURNBUTTONS|JOY_RETURNCENTERED|JOY_RETURNPOVCTS|JOY_RETURNR|JOY_RETURNU|JOY_RETURNV|JOY_RETURNX|JOY_RETURNY|JOY_RETURNZ|JOY_USEDEADZONE;
182  jie.dwSize = sizeof(jie);
183 
184  if (joyGetPosEx(_joyNumber-1, &jie) != JOYERR_NOERROR ){
185  fprintf(stderr, "Unable to get joystick information.\n");
186  // clear channels and buttons :
187  clear_values();
188  _status = STATUS_BROKEN;
189  return -1;
190  }
191 
192  // update vrpn_Channels state
193  // all joysticks have x and y axes.
194 
195  vrpn_float64 normalizer;
196 
197  //*************** Retrieve information from JOYINFOEX about joystick state *****************
198  channel[0] = jie.dwXpos;
199  channel[1] = jie.dwYpos;
200 
201  if (_jc.wCaps & JOYCAPS_HASZ) {
202  channel[2] = jie.dwZpos;
203  }
204  else channel[2] = 0;
205 
206  if (_jc.wCaps & JOYCAPS_HASR) {
207  channel[3] = jie.dwRpos;
208  }
209  else channel[3] = 0;
210  if (_jc.wCaps & JOYCAPS_HASU) {
211  channel[4] = jie.dwUpos;
212  }
213  else channel[4] = 0;
214  if (_jc.wCaps & JOYCAPS_HASV) {
215  channel[5] = jie.dwVpos;
216  }
217  else channel[5] = 0;
218 
219  channel[6] = 0;
220  channel[7] = 0;
221 
222  if (_jc.wCaps & JOYCAPS_HASPOV) {
223  channel[8] = jie.dwPOV;
224  if (channel[8] == 65535 || channel[8] == -1) {
225  channel[8] = CENTERED_VALUE;
226  }
227  if (channel[8] != CENTERED_VALUE) {
228  channel[8] /= 100.0;
229  }
230  }
231  else {
232  channel[8] = -1;
233  }
234 
235  channel[9] = -1;
236  channel[10] = -1;
237  channel[11] = -1;
238 
239  //*********************** normalize from -1 to 1 *********************************
240 
241  if (_mode == 2) {
242  normalizer = (_jc.wXmax - _jc.wXmin);
243  if (normalizer != 0) channel[0] = (2*channel[0] - _jc.wXmax - _jc.wXmin) / (_jc.wXmax - _jc.wXmin);
244  normalizer = (_jc.wYmax - _jc.wYmin);
245  if (normalizer != 0) channel[1] = (2*channel[1] - _jc.wYmax - _jc.wYmin) / (_jc.wYmax - _jc.wYmin);
246  if (_jc.wCaps & JOYCAPS_HASZ) {
247  normalizer = (_jc.wZmax - _jc.wZmin);
248  if (normalizer != 0) channel[2] = (2*channel[2] - _jc.wZmax - _jc.wZmin) / (_jc.wZmax - _jc.wZmin);
249  }
250  if (_jc.wCaps & JOYCAPS_HASR) {
251  normalizer = (_jc.wRmax - _jc.wRmin);
252  if (normalizer != 0) channel[3] = (2*channel[3] - _jc.wRmax - _jc.wRmin) / (_jc.wRmax - _jc.wRmin);
253  }
254  if (_jc.wCaps & JOYCAPS_HASU) {
255  normalizer = (_jc.wUmax - _jc.wUmin);
256  if (normalizer != 0) channel[4] = (2*channel[4] - _jc.wUmax - _jc.wUmin) / (_jc.wUmax - _jc.wUmin);
257  }
258  if (_jc.wCaps & JOYCAPS_HASV) {
259  normalizer = (_jc.wVmax - _jc.wVmin);
260  if (normalizer != 0) channel[5] = (2*channel[5] - _jc.wVmax - _jc.wVmin) / (_jc.wVmax - _jc.wVmin);
261  }
262  }
263  //*********************** normalize from 0 to 1 *********************************
264  else if (_mode == 1){
265  normalizer = _jc.wXmax - _jc.wXmin;
266  if (normalizer != 0) channel[0] = (channel[0] - _jc.wXmin) / normalizer;
267  normalizer = _jc.wYmax - _jc.wYmin;
268  if (normalizer != 0) channel[1] = (channel[1] - _jc.wYmin) / normalizer;
269  if (_jc.wCaps & JOYCAPS_HASZ) {
270  normalizer = _jc.wZmax - _jc.wZmin;
271  if (normalizer != 0) channel[2] = (channel[2] - _jc.wZmin) / normalizer;
272  }
273  if (_jc.wCaps & JOYCAPS_HASR) {
274  normalizer = _jc.wRmax - _jc.wRmin;
275  if (normalizer != 0) channel[3] = (channel[3] - _jc.wRmin) / normalizer;
276  }
277  if (_jc.wCaps & JOYCAPS_HASU) {
278  normalizer = _jc.wUmax - _jc.wUmin;
279  if (normalizer != 0) channel[4] = (channel[4] - _jc.wUmin) / normalizer;
280  }
281  if (_jc.wCaps & JOYCAPS_HASV) {
282  normalizer = _jc.wVmax - _jc.wVmin;
283  if (normalizer != 0) channel[5] = (channel[5] - _jc.wVmin) / normalizer;
284  }
285  }
286 
287  // tidy up clipping
288  if (_mode == 1){
289  // clip to -1;1 + deadzone each channel which is not a POV
290  for (vrpn_uint32 j=0;j<8;j++) {
291  // clip to -1 ; 1
292  if (channel[j] > 1.0) channel[j] = 1.0;
293  else if (channel[j] < 0.0) channel[j] = 0.0;
294 
295  // clip with dead zone
296  if (channel[j] <= _deadzone) {
297  channel[j] = 0;
298  }
299  else {
300  channel[j] = (channel[j] - _deadzone)/(1-_deadzone);
301  }
302  }
303  }
304  else if(_mode == 2) {
305  // clip to -1;1 + deadzone each channel which is not a POV
306  for (vrpn_uint32 j=0;j<8;j++) {
307  // clip to -1 ; 1
308  if (channel[j] > 1.0) channel[j] = 1.0;
309  else if (channel[j] < -1.0) channel[j] = -1.0;
310 
311  // clip with dead zone
312  if (channel[j] > -_deadzone && channel[j] < _deadzone) {
313  channel[j] = 0;
314  }
315  else {
316  if (channel[j]>0) {
317  channel[j] = (channel[j] - _deadzone)/(1-_deadzone);
318  }
319  else {
320  channel[j] = (channel[j] + _deadzone)/(1-_deadzone);
321  }
322  }
323  }
324  }
325 
326  // update vrpn_Buttons state
327  for (vrpn_uint32 i=0;i<(std::min)(_jc.wMaxButtons, _numbuttons);i++) {
328  // get flag for current button with a single bit mask and move it left to get 0x1 or 0x0 value
329  buttons[i] = (char) ((jie.dwButtons&(1<<(i)))>>(i));
330  }
331 
332  // Send any changes out over the connection.
333  _timestamp = reporttime;
334  report_changes();
335  return 0;
336 }
337 
338 void vrpn_Joywin32::report_changes(vrpn_uint32 class_of_service)
339 {
340  vrpn_Analog::timestamp = _timestamp;
341  vrpn_Button::timestamp = _timestamp;
342 
343  vrpn_Analog::report_changes(class_of_service);
345 }
346 
347 void vrpn_Joywin32::report(vrpn_uint32 class_of_service)
348 {
349  vrpn_Analog::timestamp = _timestamp;
350  vrpn_Button::timestamp = _timestamp;
351 
352  vrpn_Analog::report(class_of_service);
354 }
355 
356 
357 // This routine is called each time through the server's main loop. It will
358 // take a course of action depending on the current status of the joystick,
359 // either trying to reset it or trying to get a reading from it.
360 void vrpn_Joywin32::mainloop()
361 {
362  // Call the generic server mainloop, since we are a server
363  server_mainloop();
364 
365  switch(_status) {
366  case STATUS_BROKEN:
367  {
368  struct timeval now;
369  vrpn_gettimeofday(&now, NULL);
370  if (vrpn_TimevalDuration(now, last_error_report) > MAX_TIME_INTERVAL) {
371  send_text_message("Cannot talk to joystick, trying resetting it", now, vrpn_TEXT_ERROR);
372  last_error_report = now;
373 
374  init_joystick();
375  }
376  }
377  break;
378 
379  case STATUS_READING:
380  get_report();
381  break;
382 
383  default:
384  fprintf(stderr,"vrpn_Joywin32: Unknown mode (internal error)\n");
385  break;
386  }
387 }
388 
389 #endif
390 
#define min(x, y)
Definition: vrpn_WiiMote.C:47
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
vrpn_int32 num_buttons
Definition: vrpn_Button.h:47
STL namespace.
vrpn_float64 channel[vrpn_CHANNEL_MAX]
Definition: vrpn_Analog.h:38
Generic connection class not specific to the transport mechanism.
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
virtual void report_changes(void)
Definition: vrpn_Button.C:422
vrpn_int32 num_channel
Definition: vrpn_Analog.h:40
struct timeval timestamp
Definition: vrpn_Button.h:48
const int vrpn_BUTTON_MAX_BUTTONS
Definition: vrpn_Button.h:12
#define MAX_TIME_INTERVAL
#define vrpn_gettimeofday
Definition: vrpn_Shared.h:89
#define vrpn_CHANNEL_MAX
Definition: vrpn_Analog.h:16
All button servers should derive from this class, which provides the ability to turn any of the butto...
Definition: vrpn_Button.h:65
#define STATUS_READING
unsigned char lastbuttons[vrpn_BUTTON_MAX_BUTTONS]
Definition: vrpn_Button.h:45
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
struct timeval timestamp
Definition: vrpn_Analog.h:41
vrpn_float64 last[vrpn_CHANNEL_MAX]
Definition: vrpn_Analog.h:39