vrpn 07.35
Virtual Reality Peripheral Network
Loading...
Searching...
No Matches
vrpn_Saitek_Controller_Raw.C
Go to the documentation of this file.
1// vrpn_Saitek_Controller_Raw.C: VRPN driver for Saitek Controller Raw devices
2
3#include <stdio.h> // for fprintf, stderr, NULL
4#include <string.h> // for memset
5#include <math.h> // for sqrt and fabs
6
9
10#if defined(VRPN_USE_HID)
11
12// USB vendor and product IDs for the models we support
13static const vrpn_uint16 SAITEK_VENDOR = 0x06a3;
14static const vrpn_uint16 ST290_PRO = 0x0d60;
15
16static const double POLL_INTERVAL = 1e+6 / 30.0; // If we have not heard, ask.
17
18#define GAMEPAD_TRIGGER_THRESHOLD 30
19
21// helpers
23static vrpn_float64 normalize_dpad(unsigned char up, unsigned char right, unsigned char down, unsigned char left)
24{
25 int x = 0;
26 int y = 0;
27 if (right)
28 {
29 x += 1;
30 }
31 if (left)
32 {
33 x -= 1;
34 }
35 if (up)
36 {
37 y += 1;
38 }
39 if (down)
40 {
41 y -= 1;
42 }
43 size_t index = ((x + 1) * 3) + (y + 1);
44 vrpn_float64 angles[] = {225, 270, 315, 180, -1, 0, 135, 90, 45};
45 return (angles[index]);
46}
47
48static void normalize_axis(const unsigned int value, const short deadzone, const vrpn_float64 scale, vrpn_float64& channel, int wordSize = 16)
49{
50 channel = (static_cast<float>(value) - (float) (1 << (wordSize - 1)));
51 if (fabs(channel) < (deadzone * 3 / 4))
52 {
53 channel = 0.0f;
54 }
55 else
56 {
57 channel /= (float) (1 << (wordSize - 1));
58 }
59 channel *= scale;
60 if (channel < -1.0) { channel = -1.0; }
61 if (channel > 1.0) { channel = 1.0; }
62}
63
64static void normalize_axes(const unsigned int x, const unsigned int y, const short deadzone, const vrpn_float64 scale, vrpn_float64& channelX, vrpn_float64& channelY, int wordSize = 16)
65{
66 normalize_axis(x, deadzone, scale, channelX, wordSize);
67 normalize_axis(y, deadzone, scale, channelY, wordSize);
68}
69
71// Common base class
74 vrpn_uint16 vendor, vrpn_uint16 product) :
75 vrpn_BaseClass(name, c), vrpn_HidInterface(filter, vendor, product), _filter(filter)
76{
77 init_hid();
78}
79
81{
82 try {
83 delete _filter;
84 } catch (...) {
85 fprintf(stderr, "vrpn_Saitek_Controller_Raw::~vrpn_Saitek_Controller_Raw(): delete failed\n");
86 return;
87 }
88}
89
91{
92 // Get notifications when clients connect and disconnect
95}
96
97void vrpn_Saitek_Controller_Raw::on_data_received(size_t bytes, vrpn_uint8 *buffer)
98{
99 decodePacket(bytes, buffer);
100}
101
103{
104 return (0);
105}
106
108{
109 return (0);
110}
111
113// ST290 Pro Joystick
116vrpn_Saitek_Controller_Raw(new vrpn_HidProductAcceptor(SAITEK_VENDOR, ST290_PRO), name, c, SAITEK_VENDOR, ST290_PRO),
117 vrpn_Analog(name, c), vrpn_Button_Filter(name, c), vrpn_Dial(name, c)
118{
122
123 // Initialize the state of all the analogs, buttons, and dials
124 memset(buttons, 0, sizeof(buttons));
125 memset(lastbuttons, 0, sizeof(lastbuttons));
126 memset(channel, 0, sizeof(channel));
127 memset(last, 0, sizeof(last));
128}
129
131{
132 update();
134 struct timeval current_time;
135 vrpn_gettimeofday(&current_time, NULL);
136 if (vrpn_TimevalDuration(current_time, _timestamp) > POLL_INTERVAL)
137 {
138 _timestamp = current_time;
140
141 // Call the server_mainloop on our unique base class.
143 }
144}
145
146void vrpn_Saitek_ST290_Pro::report(vrpn_uint32 class_of_service)
147{
150 if (vrpn_Dial::num_dials > 0)
151 {
153 }
154
155 vrpn_Analog::report_changes(class_of_service);
157 if (vrpn_Dial::num_dials > 0)
158 {
160 }
161}
162
163void vrpn_Saitek_ST290_Pro::report_changes(vrpn_uint32 class_of_service)
164{
167 if (vrpn_Dial::num_dials > 0)
168 {
170 }
171
172 vrpn_Analog::report(class_of_service);
174 if (vrpn_Dial::num_dials > 0)
175 {
177 }
178}
179
180void vrpn_Saitek_ST290_Pro::decodePacket(size_t bytes, vrpn_uint8 *buffer)
181{
182 // ST290 Pro joystick
183
184 // Decode all full reports, each of which is 6 bytes long.
185 // Because there is only one type of report, the initial "0" report-type
186 // byte is removed by the HIDAPI driver.
187 /*
188 [0]: X-axis (left=00, right=ff)
189 [1]: Y-axis - lower byte (up=00, down=ff)
190 [2]: Z-rotate (left=00, right=ff)
191 [3]: Slider (up=00, down=ff)
192 [4]: buttons high nibble "1"=0x10, "2"=0x20, "3"=0x40, "4"=0x80, POV Hat low nibble (none=0x00, N=0x01, NE=0x02, ... NW=0x08)
193 [5]: 0xf0 high nibble, buttons low nibble (none=0x00, "5"=0x01, "6"=0x02)
194 */
195 // XXX Check to see that this works with HIDAPI, there may be two smaller reports.
196 if (bytes == 6)
197 {
198 normalize_axes(buffer[0], buffer[1], 0x08, 1.0f, channel[0], channel[1], 8);
199 normalize_axis(buffer[2], 0x08, 1.0f, channel[2], 8);
200 normalize_axis(buffer[3], 0x08, 1.0f, channel[3], 8);
201
202 vrpn_uint8 value, mask;
203 value = (buffer[4] >> 4);
204 for (int btn = 0; btn < 4; btn++)
205 {
206 mask = static_cast<vrpn_uint8>(1 << (btn % 8));
207 buttons[btn] = ((value & mask) != 0);
208 }
209 value = (buffer[5] & 0x0f);
210 for (int btn = 0; btn < 4; btn++)
211 {
212 mask = static_cast<vrpn_uint8>(1 << (btn % 8));
213 buttons[btn + 4] = ((value & mask) != 0);
214 }
215
216 // Point of View Hat
217 buttons[6] = buttons[7] = buttons[8] = buttons[9] = 0;
218 switch (buffer[4] & 0x0f)
219 {
220 case 1: // up
221 buttons[6] = true;
222 break;
223 case 2:
224 buttons[6] = buttons[7] = true;
225 break;
226 case 3: // right
227 buttons[7] = true;
228 break;
229 case 4:
230 buttons[7] = buttons[8] = true;
231 break;
232 case 5: // down
233 buttons[8] = true;
234 break;
235 case 6:
236 buttons[8] = buttons[9] = true;
237 break;
238 case 7: // left
239 buttons[9] = true;
240 break;
241 case 8:
242 buttons[9] = buttons[6] = true;
243 break;
244 case 0:
245 default:
246 // nothing to do
247 break;
248 }
249 channel[4] = normalize_dpad(buttons[7], buttons[8], buttons[9], buttons[10]);
250 }
251 else
252 {
253 fprintf(stderr, "vrpn_Saitek_ST290_Pro: Found a corrupted report; # total bytes = %u\n", static_cast<unsigned>(bytes));
254 }
255}
256
257// End of VRPN_USE_HID
258#endif
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
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.
void server_mainloop(void)
Handles functions that all servers should provide in their mainloop() (ping/pong, for example) Should...
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:66
virtual void report_changes(void)
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.
virtual vrpn_int32 register_message_type(const char *name)
struct timeval timestamp
Definition vrpn_Dial.h:28
virtual void report(void)
Definition vrpn_Dial.C:82
vrpn_int32 num_dials
Definition vrpn_Dial.h:27
virtual void update()
Polls the device buffers and causes on_data_received callbacks if appropriate You NEED to call this f...
Accepts any device with the given vendor and product IDs.
vrpn_Saitek_Controller_Raw(vrpn_HidAcceptor *filter, const char *name, vrpn_Connection *c=0, vrpn_uint16 vendor=0, vrpn_uint16 product=0)
virtual void decodePacket(size_t bytes, vrpn_uint8 *buffer)=0
static int VRPN_CALLBACK on_connect(void *thisPtr, vrpn_HANDLERPARAM p)
static int VRPN_CALLBACK on_last_disconnect(void *thisPtr, vrpn_HANDLERPARAM p)
void on_data_received(size_t bytes, vrpn_uint8 *buffer)
Derived class reimplements this callback.
void decodePacket(size_t bytes, vrpn_uint8 *buffer)
virtual void mainloop(void)
Called once through each main loop iteration to handle updates. Remote object mainloop() should call ...
vrpn_Saitek_ST290_Pro(const char *name, vrpn_Connection *c=0)
This structure is what is passed to a vrpn_Connection message callback.
#define VRPN_SUPPRESS_EMPTY_OBJECT_WARNING()
const char * vrpn_dropped_last_connection
const char * vrpn_got_connection
#define POLL_INTERVAL
Definition vrpn_IDEA.C:26
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