vrpn  07.33
Virtual Reality Peripheral Network
vrpn_Joylin.C
Go to the documentation of this file.
1 /*
2 # Linux Joystick. Interface to the Linux Joystick driver by Vojtech Pavlik
3 # included in several Linux distributions. The server code has been tested
4 # with Linux Joystick driver version 1.2.14. Yet, there is no way how to
5 # map a typical joystick's zillion buttons and axes on few buttons and axes
6 # really used. Unfortunately, even joysticks of the same kind can have
7 # different button mappings from one to another. Driver written by Harald
8 # Barth (haba@pdc.kth.se).
9 */
10 
11 #include "vrpn_Joylin.h"
12 
13 #ifdef VRPN_USE_JOYLIN
14 
15 #define NAME_LENGTH 128
16 
17 #include <fcntl.h> // for open, O_RDONLY
18 #include <stdio.h> // for NULL, fprintf, perror, etc
19 #include <stdlib.h> // for exit
20 #include <sys/select.h> // for select, FD_ISSET, FD_SET, etc
21 #include "vrpn_Shared.h" // for timeval, vrpn_gettimeofday
22 #include "vrpn_Types.h" // for vrpn_float64
23 
24 #include <sys/ioctl.h> // for ioctl
25 #include <unistd.h> // for read
26 #include <string.h> // for strncpy
27 
28 #include "vrpn_BaseClass.h" // for ::vrpn_TEXT_ERROR
29 #include "vrpn_Connection.h" // for vrpn_Connection
30 #include <linux/joystick.h> // for js_event, JSIOCGAXES, etc
31 
32 vrpn_Joylin::vrpn_Joylin(char * name,
33  vrpn_Connection * c,
34  char *portname):
35  vrpn_Analog(name, c), vrpn_Button_Filter(name, c)
36 {
37  namelen = 128;
38  num_channel = 2; // inherited : default for generic me-know-nothing PC joystick
39  num_buttons = 2; // inherited : this value is corrected by the ioctl call below.
40  fd = -1;
41  version = 0x000800;
42  devname = (char *) calloc(namelen, sizeof(char));
43  if (devname == NULL) {
44  fprintf(stderr,"vrpn_Joylin::vrpn_Joylin(): Out of memory\n");
45  return;
46  }
47 
48  device = strdup(portname);
49  init();
50 }
51 
53 {
54  if (devname != NULL) {
55  delete [] devname;
56  devname = NULL;
57  }
58 }
59 
60 /****************************************************************************/
61 /* Initialize the device
62 */
64 {
65  if ((fd = open(device, O_RDONLY)) < 0) { /* FIX LATER */
66  fprintf(stderr, "vrpn_Joylin constructor could not open %s", device);
67  perror(" joystick device");
68  return -1;
69  }
70 
71  ioctl(fd, JSIOCGVERSION, &version);
72  ioctl(fd, JSIOCGAXES, &num_channel);
73  ioctl(fd, JSIOCGBUTTONS, &num_buttons);
74  ioctl(fd, JSIOCGNAME(namelen), devname);
75 
76 #ifdef DEBUG
77  printf("Joystick (%s) has %d axes and %d buttons. Driver version is %d.%d.%d.\n",
78  devname, num_channel, num_buttons, version >> 16, (version >> 8) & 0xff, version & 0xff);
79 #endif
80 
81  return 0;
82 }
83 
84 void vrpn_Joylin::mainloop(void)
85 {
86  struct timeval zerotime;
87  fd_set fdset;
88  struct js_event js;
89  int i;
90 
91  zerotime.tv_sec = 0;
92  zerotime.tv_usec = 0;
93 
94  // Since we are a server, call the generic server mainloop()
96 
97  if (fd < 0) { return; }
98 
99  bool got_response;
100  do {
101  got_response = false;
102  FD_ZERO(&fdset); /* clear fdset */
103  FD_SET(fd, &fdset); /* include fd in fdset */
104  select(fd+1, &fdset, NULL, NULL, &zerotime);
105 
106  if (FD_ISSET(fd, &fdset)){
107  if (read(fd, &js, sizeof(struct js_event)) != sizeof(struct js_event)) {
108  send_text_message("Error reading from joystick", vrpn_Analog::timestamp, vrpn_TEXT_ERROR);
110 
111  /* try to reopen the device, e.g. wireless joysticks
112  * like to disconnect when not in use to save battery */
113  close(fd);
114  vrpn_SleepMsecs(5000);
115  init();
116  return;
117  }
118  got_response = true;
119 
120  switch(js.type & ~JS_EVENT_INIT) {
121  case JS_EVENT_BUTTON:
122  vrpn_gettimeofday((timeval *)&this->vrpn_Button::timestamp, NULL);
123  buttons[js.number] = js.value;
124  break;
125  case JS_EVENT_AXIS:
126  vrpn_gettimeofday((timeval *)&this->vrpn_Analog::timestamp, NULL);
127  channel[js.number] = js.value / 32767.0; /* FIX LATER */
128  break;
129  }
130 
131 #ifdef DEBUG
132  if (num_channel) {
133  printf("Axes: ");
134  for (i = 0; i < num_channel; i++) {
135  printf("%2d:%.3f ", i, channel[i]);
136  }
137  }
138  if (num_buttons) {
139  printf("Buttons: ");
140  for (i = 0; i < num_buttons; i++) {
141  printf("%2d:%s ", i, buttons[i] ? "on " : "off");
142  }
143  }
144  printf("\n");
145  fflush(stdout);
146 #endif
147 
148  vrpn_Analog::report_changes(); // report any analog event;
149  vrpn_Button::report_changes(); // report any button event;
150  }
151  } while (got_response);
152 }
153 
154 #else
155 
157  vrpn_Connection * c,
158  char *):
159  vrpn_Analog(name, c), vrpn_Button_Filter(name, c)
160 {
161  fprintf(stderr,"vrpn_Joylin::vrpn_Joylin: Can't open Linux joystick on non-Linux machine\n");
162 }
163 
165 {
166 }
167 
169 {
170 }
171 
172 #endif
173 
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
vrpn_int32 num_buttons
Definition: vrpn_Button.h:47
vrpn_float64 channel[vrpn_CHANNEL_MAX]
Definition: vrpn_Analog.h:38
virtual int send_pending_reports(void)=0
send pending report, clear the buffer. This function was protected, now is public, so we can use it to send out intermediate results without calling mainloop
vrpn_Joylin(char *name, vrpn_Connection *c, char *portname)
Definition: vrpn_Joylin.C:156
Generic connection class not specific to the transport mechanism.
All types of client/server/peer objects in VRPN should be derived from the vrpn_BaseClass type descri...
virtual int init(void)
Initialize things that the constructor can&#39;t. Returns 0 on success, -1 on failure.
virtual void report_changes(void)
Definition: vrpn_Button.C:422
vrpn_int32 num_channel
Definition: vrpn_Analog.h:40
vrpn_Connection * d_connection
Connection that this object talks to.
int send_text_message(const char *msg, struct timeval timestamp, vrpn_TEXT_SEVERITY type=vrpn_TEXT_NORMAL, vrpn_uint32 level=0)
Sends a NULL-terminated text message from the device d_sender_id.
struct timeval timestamp
Definition: vrpn_Button.h:48
#define vrpn_gettimeofday
Definition: vrpn_Shared.h:89
All button servers should derive from this class, which provides the ability to turn any of the butto...
Definition: vrpn_Button.h:65
unsigned char buttons[vrpn_BUTTON_MAX_BUTTONS]
Definition: vrpn_Button.h:44
struct timeval timestamp
Definition: vrpn_Analog.h:41
void mainloop(void)
Called once through each main loop iteration to handle updates. Remote object mainloop() should call ...
Definition: vrpn_Joylin.C:168