vrpn 07.35
Virtual Reality Peripheral Network
Loading...
Searching...
No Matches
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.
21const int STATUS_BROKEN = -1; // Broken joystick
22const int STATUS_READING = 1; // Looking for a report
23const int CENTERED_VALUE = -1; // returned value for centered POV
24
25#define MAX_TIME_INTERVAL (2000000) // max time to try and reacquire
26
27vrpn_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
69void 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
148void 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
165int 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
338void 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
347void 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.
360void 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
vrpn_float64 last[vrpn_CHANNEL_MAX]
Definition vrpn_Analog.h:39
vrpn_float64 channel[vrpn_CHANNEL_MAX]
Definition vrpn_Analog.h:38
struct timeval timestamp
Definition vrpn_Analog.h:41
vrpn_int32 num_channel
Definition vrpn_Analog.h:40
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(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
All button servers should derive from this class, which provides the ability to turn any of the butto...
Definition vrpn_Button.h:66
vrpn_int32 num_buttons
Definition vrpn_Button.h:48
struct timeval timestamp
Definition vrpn_Button.h:49
virtual void report_changes(void)
unsigned char lastbuttons[vrpn_BUTTON_MAX_BUTTONS]
Definition vrpn_Button.h:46
unsigned char buttons[vrpn_BUTTON_MAX_BUTTONS]
Definition vrpn_Button.h:45
Generic connection class not specific to the transport mechanism.
#define MAX_TIME_INTERVAL
#define STATUS_READING
#define vrpn_CHANNEL_MAX
Definition vrpn_Analog.h:16
@ vrpn_TEXT_ERROR
const int vrpn_BUTTON_MAX_BUTTONS
Definition vrpn_Button.h:13
unsigned long vrpn_TimevalDuration(struct timeval endT, struct timeval startT)
Return number of microseconds between startT and endT.
#define vrpn_gettimeofday
Definition vrpn_Shared.h:99
#define min(x, y)