vrpn  07.33
Virtual Reality Peripheral Network
vrpn_Futaba.C
Go to the documentation of this file.
1 // vrpn_Futaba.C: VRPN driver for Futaba devices
2 
3 #include <stdio.h> // for fprintf, stderr, NULL
4 #include <string.h> // for memset
5 #include <math.h> // for fabs
6 
7 #include "vrpn_Futaba.h"
8 
10 
11 #if defined(VRPN_USE_HID)
12 
13 static const double POLL_INTERVAL = 1e+6 / 30.0; // If we have not heard, ask.
14 
15 // USB vendor and product IDs for the models we support
16 static const vrpn_uint16 FUTABA_VENDOR = 0x1781;
17 static const vrpn_uint16 FUTABA_ELITE = 0x0e56;
18 
19 static void normalize_axis(const unsigned int value, const short deadzone, const vrpn_float64 scale, vrpn_float64& channel) {
20  channel = (static_cast<float>(value) - 128.0f);
21  if (fabs(channel) < deadzone)
22  {
23  channel = 0.0f;
24  }
25  else
26  {
27  channel /= 128.0f;
28  }
29  channel *= scale;
30  if (channel < -1.0) { channel = -1.0; }
31  if (channel > 1.0) { channel = 1.0; }
32 }
33 
34 static void normalize_axes(const unsigned int x, const unsigned int y, const short deadzone, const vrpn_float64 scale, vrpn_float64& channelX, vrpn_float64& channelY) {
35  normalize_axis(x, deadzone, scale, channelX);
36  normalize_axis(y, deadzone, scale, channelY);
37 }
38 
40  : vrpn_HidInterface(filter)
41  , vrpn_BaseClass(name, c)
42  , _filter(filter)
43 {
44  init_hid();
45 }
46 
48 {
49  delete _filter;
50 }
51 
53  // Get notifications when clients connect and disconnect
56 }
57 
58 void vrpn_Futaba::on_data_received(size_t bytes, vrpn_uint8 *buffer)
59 {
60  decodePacket(bytes, buffer);
61 }
62 
64 {
65  vrpn_Futaba *me = static_cast<vrpn_Futaba *>(thisPtr);
66  return 0;
67 }
68 
69 int vrpn_Futaba::on_connect(void *thisPtr, vrpn_HANDLERPARAM /*p*/)
70 {
71  vrpn_Futaba *me = static_cast<vrpn_Futaba *>(thisPtr);
72  return 0;
73 }
74 
76  : vrpn_Futaba(_filter = new vrpn_HidProductAcceptor(FUTABA_VENDOR, FUTABA_ELITE), name, c)
77  , vrpn_Button_Filter(name, c)
78  , vrpn_Analog(name, c)
79  , vrpn_Dial(name, c)
80 {
84 
85  // Initialize the state of all the analogs, buttons, and dials
86  _lastDial = 0;
87  memset(buttons, 0, sizeof(buttons));
88  memset(lastbuttons, 0, sizeof(lastbuttons));
89  memset(channel, 0, sizeof(channel));
90  memset(last, 0, sizeof(last));
91 }
92 
94 {
95  update();
97  struct timeval current_time;
98  vrpn_gettimeofday(&current_time, NULL);
99  if (vrpn_TimevalDuration(current_time, _timestamp) > POLL_INTERVAL ) {
100  _timestamp = current_time;
101  report_changes();
102 
105  if (vrpn_Dial::num_dials > 0)
106  {
108  }
109  }
110 }
111 
112 void vrpn_Futaba_InterLink_Elite::report(vrpn_uint32 class_of_service) {
115  if (vrpn_Dial::num_dials > 0)
116  {
118  }
119 
120  vrpn_Analog::report(class_of_service);
122  if (vrpn_Dial::num_dials > 0)
123  {
125  }
126 }
127 
128 void vrpn_Futaba_InterLink_Elite::report_changes(vrpn_uint32 class_of_service) {
131  if (vrpn_Dial::num_dials > 0)
132  {
134  }
135 
136  vrpn_Analog::report(class_of_service);
138  if (vrpn_Dial::num_dials > 0)
139  {
141  }
142 }
143 
144 void vrpn_Futaba_InterLink_Elite::decodePacket(size_t bytes, vrpn_uint8 *buffer) {
145  // Decode all full reports, each of which is 8 bytes long.
146  // Because there is only one type of report, the initial "0" report-type
147  // byte is removed by the HIDAPI driver.
148  // XXX Check to see that this works with HIDAPI, there may be two smaller reports.
149  if (bytes == 8) {
150  if (buffer[0] == 5) {
151 
152  // Report joystick axes as analogs
153  // rudder (6th byte, left joy left/right, left/right): Left 2B, center (normal) 82 (calc 84), right DC
154  // throttle (4th byte, left joy up/down): Up 32, (center calc 7f), down CC
155  normalize_axes(buffer[5], buffer[3], 5, (1.0f / 0.70f), channel[0], channel[1]);
156  // aileron (2nd byte, right joy left/right, roll): Left 27, center (normal) 81 (calc 7e), right D5
157  // elevator (3rd byte, right joy up/down, forward/back): Up 34, center (normal) 81 (calc 81), down CF
158  normalize_axes(buffer[1], buffer[2], 5, (1.0f / 0.70f), channel[2], channel[3]);
159 
160  if (vrpn_Dial::num_dials > 0) {
161  // dial (5th byte): Ch6 00-FF
162  // Do the unsigned/signed conversion at the last minute so the
163  // signed values work properly.
164  dials[0] = static_cast<vrpn_int8>(buffer[4] - _lastDial) / 128.0;
165  // Store the current dial position for the next delta
166  _lastDial = buffer[4];
167  }
168  else
169  {
170  // dial (5th byte): Ch6 Flaps Gain 00-FF
171  normalize_axis(buffer[4], 5, 1.0f, channel[4]);
172  }
173 
174  vrpn_uint8 value;
175  // switches (8th byte):
176  value = buffer[7];
177  // button #0: 01 Ch5 fwd
178  // button #1: 02 Ch7 fwd
179  // button #2: 04 reset
180  // button #3: 08 Ch8 down
181  // button #4: 10 Ch8 up
182  // button #5: 20 <none>
183  // button #6: 40 menu/select
184  // button #7: 80 cancel
185  for (int btn = 0; btn < 8; btn++) {
186  vrpn_uint8 mask = static_cast<vrpn_uint8>(1 << (btn % 8));
187  buttons[btn] = ((value & mask) != 0);
188  }
189 
190  // trim switches (7th byte): it is not possible to have the odd button at the same times as the previous even button
191  value = buffer[6];
192  // button #8: 01 aileron right
193  // button #9: 02 aileron left
194  // button #10:03 elevator up
195  // button #11:06 elevator down
196  // button #12:09 rudder right
197  // button #13:12 rudder left
198  // button #14:1B throttle up
199  // button #15:36 throttle down
200  // button #16:51 up
201  // button #17:a2 down
202  //0000 0001 1
203  //0000 0010 2
204  //0000 0011 3,4,5
205  //0000 0110 6,7,8
206  //0000 1001 9,a,b,c,d,e,f,10,11
207  //0001 0010 12,13,14,15,16,17,18,19,1a
208  //0001 1011 1b,...,35
209  //0011 0110 36,...,50
210  //0101 0001 51,...,a1
211  //1010 0010 a2,...,f2
212  //start with highest and work down.
213  const vrpn_uint8 btnCount = 10;
214  const vrpn_uint8 btnValues[btnCount] = {0xa2, 0x51, 0x36, 0x1b, 0x12, 0x09, 0x06, 0x03, 0x02, 0x01};
215  for (int i = 0; i < btnCount; i++) {
216  if ((value & btnValues[i]) == btnValues[i]) {
217  value ^= btnValues[i];
218  buttons[17 - i] = 1;
219  } else {
220  buttons[17 - i] = 0;
221  }
222  }
223  } else {
224  fprintf(stderr, "vrpn_Futaba_InterLink_Elite: Unknown report = %u\n", static_cast<unsigned>(buffer[0]));
225  }
226  } else {
227  fprintf(stderr, "vrpn_Futaba_InterLink_Elite: Found a corrupted report; # total bytes = %u\n", static_cast<unsigned>(bytes));
228  }
229 }
230 
231 // End of VRPN_USE_HID
232 #endif
void server_mainloop(void)
Handles functions that all servers should provide in their mainloop() (ping/pong, for example) Should...
vrpn_HidAcceptor * _filter
Definition: vrpn_Futaba.h:42
vrpn_int32 num_buttons
Definition: vrpn_Button.h:47
virtual void decodePacket(size_t bytes, vrpn_uint8 *buffer)=0
struct timeval _timestamp
Definition: vrpn_Futaba.h:41
vrpn_float64 channel[vrpn_CHANNEL_MAX]
Definition: vrpn_Analog.h:38
Accepts any device with the given vendor and product IDs.
struct timeval timestamp
Definition: vrpn_Dial.h:28
Generic connection class not specific to the transport mechanism.
static int VRPN_CALLBACK on_connect(void *thisPtr, vrpn_HANDLERPARAM p)
Definition: vrpn_Futaba.C:69
vrpn_int32 num_dials
Definition: vrpn_Dial.h:27
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
#define VRPN_SUPPRESS_EMPTY_OBJECT_WARNING()
const char * vrpn_dropped_last_connection
virtual void report_changes(void)
Definition: vrpn_Button.C:382
virtual void report_changes(void)
Definition: vrpn_Button.C:422
vrpn_int32 num_channel
Definition: vrpn_Analog.h:40
virtual void report(void)
Definition: vrpn_Dial.C:82
int register_autodeleted_handler(vrpn_int32 type, vrpn_MESSAGEHANDLER handler, void *userdata, vrpn_int32 sender=vrpn_ANY_SENDER)
Registers a handler with the connection, and remembers to delete at destruction.
vrpn_Connection * d_connection
Connection that this object talks to.
This structure is what is passed to a vrpn_Connection message callback.
void on_data_received(size_t bytes, vrpn_uint8 *buffer)
Derived class reimplements this callback.
Definition: vrpn_Futaba.C:58
void init_hid(void)
Definition: vrpn_Futaba.C:52
#define POLL_INTERVAL
Definition: vrpn_IDEA.C:26
const char * vrpn_got_connection
struct timeval timestamp
Definition: vrpn_Button.h:48
static int VRPN_CALLBACK on_last_disconnect(void *thisPtr, vrpn_HANDLERPARAM p)
Definition: vrpn_Futaba.C:63
#define vrpn_gettimeofday
Definition: vrpn_Shared.h:89
virtual void update()
Polls the device buffers and causes on_data_received callbacks if appropriate You NEED to call this f...
Class from which all user-level (and other) classes that communicate with vrpn_Connections should der...
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 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
vrpn_Futaba(vrpn_HidAcceptor *filter, const char *name, vrpn_Connection *c=0)
Definition: vrpn_Futaba.C:39
virtual ~vrpn_Futaba(void)
Definition: vrpn_Futaba.C:47
virtual vrpn_int32 register_message_type(const char *name)
struct timeval timestamp
Definition: vrpn_Analog.h:41
vrpn_float64 last[vrpn_CHANNEL_MAX]
Definition: vrpn_Analog.h:39
vrpn_float64 dials[vrpn_DIAL_MAX]
Definition: vrpn_Dial.h:26