Privacy
An open-source, flexible 3D physical simulation framework
ConnexionHID.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2011, 2012, DFKI GmbH Robotics Innovation Center
3  *
4  * This file is part of the MARS simulation framework.
5  *
6  * MARS is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License
8  * as published by the Free Software Foundation, either version 3
9  * of the License, or (at your option) any later version.
10  *
11  * MARS is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with MARS. If not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 #include "../ConnexionHID.h"
22 
23 #include <mars/interfaces/MARSDefs.h>
24 
25 #include <linux/input.h>
26 #include <dirent.h>
27 #include <cstdio>
28 #include <fcntl.h>
29 #include <unistd.h>
30 #include <cstring>
31 #include <cmath>
32 
33 #define PATH_BUFFER_SIZE (1024)
34 
35 
36 namespace mars {
37  namespace plugins {
38  namespace connexion_plugin {
39 
40  /* file descriptor of the /dev/input node of the SpaceMouse */
41  static int fd = -1;
42 
43 
44  /* Scan all devices in /dev/input/ to find the SpaceMouse.
45  * Returns the file descriptor of the SpaceMouse or -1 if it could not be found.
46  */
47  static int getFileDescriptor() {
48  struct dirent *entry;
49  DIR *dp;
50  char path[PATH_BUFFER_SIZE];
51  struct input_id device_info;
52  const char *devDirectory = "/dev/input/";
53 
54  /* open the directory */
55  dp = opendir(devDirectory);
56  if(dp == NULL) {
57  return -1;
58  }
59  /* walk the directory (non-recursively) */
60  while((entry = readdir(dp))) {
61  strncpy(path, devDirectory, sizeof(path));
62  /* if strlen(devDirectory) > sizeof(path) the path won't be NULL terminated
63  * and *bad things* will happen. Therfore, we force NULL termination.
64  */
65  path[PATH_BUFFER_SIZE-1] = '\0';
66  strncat(path, entry->d_name, sizeof(path));
67 
68  fd = open(path, O_RDONLY | O_NONBLOCK);
69  if(-1 == fd) {
70  /* could not open file. probably we do not have read permission. */
71  continue;
72  }
73 
74  /* try to read the vendor and device ID */
75  if(!ioctl(fd, EVIOCGID, &device_info)) {
76  if((device_info.vendor == LOGITECH_VENDOR_ID) &&
77  (device_info.product == LOGITECH_SPACE_NAVIGATOR_DEVICE_ID)) {
78  /* BINGO!!! this is it! */
79  break;
80  }
81  }
82  close(fd);
83  fd = -1;
84  }
85 
86  if(-1 == fd) {
87  fprintf(stderr,
88  "ERROR: could not find SpaceMouse! \n"
89  " Do you have read permission on the /dev/input/ device?\n");
90  }
91  closedir(dp);
92  return fd;
93  }
94 
95  int initConnexionHID(void *windowID) {
97  if(fd < 0) {
98  return 0;
99  }
100  return 1;
101  }
102 
104  if(fd > 0) {
105  close(fd);
106  }
107  fd = -1;
108  }
109 
111  struct connexionValues *rawValues) {
112  /* If input events don't come in fast enough a certain DoF may not be
113  * updated during a frame. This results in choppy and ugly animation.
114  * To solve this we record the number of frames a certain DoF was idle
115  * and only set the DoF to 0 if we reach a certain idleThreshold.
116  * When there is activity on a axis the idleFrameCount is reset to 0.
117  */
118  int i, eventCnt;
119  /* how many bytes were read */
120  size_t bytesRead;
121  /* the events (up to 64 at once) */
122  struct input_event events[64];
123  /* keep track of idle frames for each DoF for smoother animation. see above */
124  static int idleFrameCount[6] = {0, 0, 0, 0, 0, 0};
125  int idleThreshold = 3;
126 
127  /* read the raw event data from the device */
128  bytesRead = read(fd, events, sizeof(struct input_event) * 64);
129  eventCnt = (int) ((long)bytesRead / (long)sizeof(struct input_event));
130  if (bytesRead < (int) sizeof(struct input_event)) {
131  perror("evtest: short read");
132  return;
133  }
134 
135  /* Increase all idle counts. They are later reset if there is activity */
136  for(i = 0; i < 6; ++i) {
137  ++idleFrameCount[i];
138  }
139 
140  /* handle input events sequentially */
141  for(i = 0; i < eventCnt; ++i) {
142  if(EV_KEY == events[i].type) {
143  switch(events[i].code) {
144  case BTN_0:
145  rawValues->button1 = events[i].value;
146  break;
147  case BTN_1:
148  rawValues->button2 = events[i].value;
149  break;
150  }
151  } else if(EV_REL == events[i].type || EV_ABS == events[i].type) {
152  switch(events[i].code) {
153  case REL_X:
154  rawValues->tx = events[i].value;
155  idleFrameCount[0] = 0;
156  break;
157  case REL_Y:
158  rawValues->ty = events[i].value;
159  idleFrameCount[1] = 0;
160  break;
161  case REL_Z:
162  rawValues->tz = events[i].value;
163  idleFrameCount[2] = 0;
164  break;
165  case REL_RX:
166  rawValues->rx = events[i].value;
167  idleFrameCount[3] = 0;
168  break;
169  case REL_RY:
170  rawValues->ry = events[i].value;
171  idleFrameCount[4] = 0;
172  break;
173  case REL_RZ:
174  rawValues->rz = events[i].value;
175  idleFrameCount[5] = 0;
176  break;
177  }
178  }
179  }
180 
181  /* Set rawValue to zero if DoF was idle for more than idleThreshold frames */
182  for(i = 0; i < 6; ++i) {
183  if(idleFrameCount[i] >= idleThreshold) {
184  if(0==i) {
185  rawValues->tx = 0;
186  } else if (1==i) {
187  rawValues->ty = 0;
188  } else if (2==i) {
189  rawValues->tz = 0;
190  } else if (3==i) {
191  rawValues->rx = 0;
192  } else if (4==i) {
193  rawValues->ry = 0;
194  } else if (5==i) {
195  rawValues->rz = 0;
196  }
197  }
198  }
199 
200  coordinates[0] = rawValues->tx * fabs(rawValues->tx * 0.001);
201  coordinates[1] = -rawValues->tz * fabs(rawValues->tz * 0.001);
202  coordinates[2] = -rawValues->ty * fabs(rawValues->ty * 0.001);
203  coordinates[3] = rawValues->rx * fabs(rawValues->rx * 0.0008);
204  coordinates[4] = -rawValues->rz * fabs(rawValues->rz * 0.0008);
205  coordinates[5] = -rawValues->ry * fabs(rawValues->ry * 0.0008);
206  }
207 
208  } // end of namespace connexion_plugin
209  } // end of namespace plugins
210 } // end of namespace mars
#define PATH_BUFFER_SIZE
void getValue(interfaces::sReal *coordiantes, struct connexionValues *rawValues)
#define LOGITECH_SPACE_NAVIGATOR_DEVICE_ID
Definition: ConnexionHID.h:29
int initConnexionHID(void *windowID)
double sReal
Definition: MARSDefs.h:49
#define LOGITECH_VENDOR_ID
Definition: ConnexionHID.h:26
Copyright 2012, DFKI GmbH Robotics Innovation Center.