7#if defined(VRPN_USE_WIIUSE)
19#ifndef WIIUSE_HAS_VERSION
20#define WIIUSE_HAS_VERSION(major, minor, patch) false
25class vrpn_Wiimote_Device {
27 vrpn_Wiimote_Device() :
32 reorderButtons(
false),
35 struct wiimote_t *device;
47#define min(x,y) ((x)<(y)?(x):(y))
50#if defined (vrpn_THREADS_AVAILABLE)
51struct vrpn_WiiMote_SharedData {
53 : connectLock(), wmHandle(wm), msgLock(), stopFlag(
false), running(
false)
64inline void vrpn_WiiMote::acquireMessageLock() {
65#if defined (vrpn_THREADS_AVAILABLE)
67 sharedData->msgLock.p();
71inline void vrpn_WiiMote::releaseMessageLock() {
72#if defined (vrpn_THREADS_AVAILABLE)
73 sharedData->msgLock.v();
77unsigned vrpn_WiiMote::map_button(
unsigned btn) {
113 fprintf(stderr,
"WiiMote: unhandled button %d\n", btn);
119void vrpn_WiiMote::handle_event() {
125 for (i = 0; i < 16; i++) {
126 if (wiimote->reorderButtons) {
127 buttons[map_button(i)] = (wiimote->device->btns & (1 << i)) != 0;
129 buttons[i] = (wiimote->device->btns & (1 << i)) != 0;
133 switch (wiimote->device->exp.type) {
138 for (i = 0; i < 16; i++) {
139 buttons[16 + i] = (wiimote->device->exp.nunchuk.btns & (1 << i)) != 0;
144 for (i = 0; i < 16; i++) {
145 buttons[32 + i] = (wiimote->device->exp.classic.btns & (1 << i)) != 0;
149 case EXP_GUITAR_HERO_3:
150 for (i = 0; i < 16; i++) {
151 buttons[48 + i] = (wiimote->device->exp.gh3.btns & (1 << i)) != 0;
158 if (IS_PRESSED(wiimote->device, WIIMOTE_BUTTON_A)) {
159 wiiuse_set_wii_board_calib(wiimote->device);
168 channel[0] = wiimote->device->battery_level;
169 if (WIIUSE_USING_ACC(wiimote->device)) {
170 channel[1] = wiimote->device->gforce.x;
171 channel[2] = wiimote->device->gforce.y;
172 channel[3] = wiimote->device->gforce.z;
174 if (WIIUSE_USING_IR(wiimote->device)) {
176 for (dot = 0; dot < 4; dot++) {
177 if (wiimote->device->ir.dot[dot].visible) {
178 channel[4 + 3 * dot + 0] = wiimote->device->ir.dot[dot].rx;
179 channel[4 + 3 * dot + 1] = wiimote->device->ir.dot[dot].ry;
180 channel[4 + 3 * dot + 2] = wiimote->device->ir.dot[dot].size;
190 switch (wiimote->device->exp.type) {
196 channel[16 + 0] = wiimote->device->exp.nunchuk.gforce.x;
197 channel[16 + 1] = wiimote->device->exp.nunchuk.gforce.y;
198 channel[16 + 2] = wiimote->device->exp.nunchuk.gforce.z;
199 channel[16 + 3] = wiimote->device->exp.nunchuk.js.ang;
200 channel[16 + 4] = wiimote->device->exp.nunchuk.js.mag;
201#if WIIUSE_HAS_VERSION(0,14,2)
202 channel[16 + 5] = wiimote->device->exp.nunchuk.js.x;
203 channel[16 + 6] = wiimote->device->exp.nunchuk.js.y;
208 channel[32 + 0] = wiimote->device->exp.classic.l_shoulder;
209 channel[32 + 1] = wiimote->device->exp.classic.r_shoulder;
210 channel[32 + 2] = wiimote->device->exp.classic.ljs.ang;
211 channel[32 + 3] = wiimote->device->exp.classic.ljs.mag;
212 channel[32 + 4] = wiimote->device->exp.classic.rjs.ang;
213 channel[32 + 5] = wiimote->device->exp.classic.rjs.mag;
214#if WIIUSE_HAS_VERSION(0,14,2)
215 channel[32 + 6] = wiimote->device->exp.classic.ljs.x;
216 channel[32 + 7] = wiimote->device->exp.classic.ljs.y;
217 channel[32 + 8] = wiimote->device->exp.classic.rjs.x;
218 channel[32 + 9] = wiimote->device->exp.classic.rjs.y;
223 case EXP_GUITAR_HERO_3:
224 channel[48 + 0] = wiimote->device->exp.gh3.whammy_bar;
225 channel[48 + 1] = wiimote->device->exp.gh3.js.ang;
226 channel[48 + 2] = wiimote->device->exp.gh3.js.mag;
227#if WIIUSE_HAS_VERSION(0,14,2)
228 channel[48 + 3] = wiimote->device->exp.gh3.js.x;
229 channel[48 + 4] = wiimote->device->exp.gh3.js.y;
236 struct wii_board_t* wb = (wii_board_t*)&wiimote->device->exp.wb;
237 float total = wb->tl + wb->tr + wb->bl + wb->br;
238 float x = ((wb->tr + wb->br) / total) * 2 - 1;
239 float y = ((wb->tl + wb->tr) / total) * 2 - 1;
256 sprintf(msg,
"Unknown Wii Remote expansion type: device->exp.type = %d", wiimote->device->exp.type);
264void vrpn_WiiMote::connect_wiimote(
int timeout) {
268 wiimote->device = NULL;
269 unsigned num_available;
272 if (!wiimote->bdaddr.empty()) {
274 std::string current(available_wiimotes[i]->bdaddr_str);
275 if (current == wiimote->bdaddr) {
276 wiimote->device = available_wiimotes[i];
278 }
else if (!current.empty()) {
279 acquireMessageLock();
281 sprintf(msg,
"Wiimote found, but it's not the one we want: '%s' isn't '%s'\n", available_wiimotes[i]->bdaddr_str, wiimote->bdaddr.c_str());
283 releaseMessageLock();
288 if (wiimote->bdaddr.empty()) {
291 if (! wiimote->device) {
292 acquireMessageLock();
294 sprintf(msg,
"Could not open remote %d (%d found)", wiimote->which, num_available);
296 releaseMessageLock();
297 wiimote->found =
false;
300 wiimote->found =
true;
303 wiimote->connected = (wiiuse_connect(&(wiimote->device), 1) != 0);
304 if (wiimote->connected) {
305 acquireMessageLock();
307 sprintf(msg,
"Connected to remote %d", wiimote->which);
309 releaseMessageLock();
312 wiiuse_rumble(wiimote->device, 1);
314 initialize_wiimote_state();
317 acquireMessageLock();
319 sprintf(msg,
"No connection to remote %d", wiimote->which);
321 releaseMessageLock();
325void vrpn_WiiMote::initialize_wiimote_state(
void) {
326 if (!wiimote->device || !wiimote->found || !wiimote->connected) {
331 switch (wiimote->which) {
333 wiiuse_set_leds(wiimote->device, WIIMOTE_LED_1);
336 wiiuse_set_leds(wiimote->device, WIIMOTE_LED_2);
339 wiiuse_set_leds(wiimote->device, WIIMOTE_LED_3);
342 wiiuse_set_leds(wiimote->device, WIIMOTE_LED_4);
348 sprintf(msg,
"Too-large remote %d (1-4 available)", wiimote->which);
354 wiiuse_motion_sensing(wiimote->device, wiimote->useMS);
357 wiiuse_rumble(wiimote->device, 0);
360 wiiuse_set_ir(wiimote->device, wiimote->useIR);
371#if defined (vrpn_THREADS_AVAILABLE)
372 waitingForConnection(true),
378#ifndef vrpn_THREADS_AVAILABLE
379 last_reconnect_attempt.tv_sec = 0;
380 last_reconnect_attempt.tv_usec = 0;
383 try { wiimote =
new vrpn_Wiimote_Device; }
385 FAIL(
"vrpn_WiiMote: out of memory");
409 FAIL(
"vrpn_WiiMote: can't register change channel request handler");
416 FAIL(
"vrpn_WiiMote: can't register change channels request handler");
424 FAIL(
"Can't register self-destruct handler");
430 wiimote->which = which > 0 ? which : 1;
431 wiimote->useMS = useMS;
432 wiimote->useIR = useIR;
433 wiimote->reorderButtons = (reorderButtons != 0);
435 wiimote->bdaddr = std::string(bdaddr);
438 if (!wiimote->bdaddr.empty()) {
439 fprintf(stderr,
"vrpn_WiiMote: Specifying the bluetooth address of the desired wiimote is only supported on Linux right now\n");
440 wiimote->bdaddr.clear();
445#if !defined(DEBUG) && defined(WIIUSE_HAS_OUTPUT_REDIRECTION)
447 wiiuse_set_output(LOGLEVEL_DEBUG, 0);
448 wiiuse_set_output(LOGLEVEL_INFO, 0);
450#if defined (vrpn_THREADS_AVAILABLE)
454 try { sharedData =
new vrpn_WiiMote_SharedData(
this); }
456 FAIL(
"vrpn_WiiMote: out of memory");
459 connectThreadData.
pvUD = sharedData;
461 acquireMessageLock();
463 try { connectThread =
new vrpn_Thread(&vrpn_WiiMote::connectThreadFunc, connectThreadData); }
465 FAIL(
"vrpn_WiiMote: out of memory");
476#if defined (vrpn_THREADS_AVAILABLE)
478 sharedData->stopFlag =
true;
480 if (!waitingForConnection) {
481 sharedData->connectLock.v();
483 while (connectThread->running()) {
486 releaseMessageLock();
488 acquireMessageLock();
492 delete connectThread;
495 fprintf(stderr,
"vrpn_WiiMote::~vrpn_WiiMote(): delete failed\n");
501 if (wiimote->connected) {
502 wiiuse_disconnect(wiimote->device);
507 fprintf(stderr,
"vrpn_WiiMote::~vrpn_WiiMote(): delete failed\n");
518#if defined (vrpn_THREADS_AVAILABLE)
519 if (waitingForConnection) {
521 if (sharedData->connectLock.condP()) {
523 waitingForConnection =
false;
526 releaseMessageLock();
528 acquireMessageLock();
539#if defined (vrpn_THREADS_AVAILABLE)
540 waitingForConnection =
true;
542 sharedData->connectLock.v();
546 if (diff.tv_sec >= 1) {
547 last_reconnect_attempt = _timestamp;
559 if (wiimote->connected && wiiuse_poll(&(wiimote->device), 1)) {
560 switch (wiimote->device->event) {
569 case WIIUSE_DISCONNECT:
570 case WIIUSE_UNEXPECTED_DISCONNECT:
571 wiimote->connected =
false;
572 wiiuse_disconnect(wiimote->device);
574#ifndef vrpn_THREADS_AVAILABLE
575 last_reconnect_attempt = _timestamp;
579 case WIIUSE_READ_DATA:
584 case WIIUSE_NUNCHUK_INSERTED:
588 case WIIUSE_CLASSIC_CTRL_INSERTED:
592 case WIIUSE_GUITAR_HERO_3_CTRL_INSERTED:
597 case WIIUSE_WII_BOARD_CTRL_INSERTED:
602 case WIIUSE_NUNCHUK_REMOVED:
603 case WIIUSE_CLASSIC_CTRL_REMOVED:
604 case WIIUSE_GUITAR_HERO_3_CTRL_REMOVED:
609 case WIIUSE_WII_BOARD_CTRL_REMOVED:
610 send_text_message(
"Wii Balance Board controller removed/disconnected", _timestamp,
627 return (wiimote->found) && (wiimote->connected);
630void vrpn_WiiMote::report(vrpn_uint32 class_of_service) {
649 const char* bufptr = p.
buffer;
663 fprintf(stderr,
"vrpn_WiiMote::handle_request_message(): Index out of bounds\n");
665 sprintf(msg,
"Error: (handle_request_message): channel %d is not active. Squelching.", chan_num);
674 wiiuse_rumble(me->wiimote->device, 1);
676 wiiuse_rumble(me->wiimote->device, 0);
682 int level =
static_cast<int>(value);
683 wiiuse_set_ir_sensitivity(me->wiimote->device, level);
693 const char* bufptr = p.
buffer;
703 sprintf(msg,
"Error: (handle_request_channels_message): channels above %d not active; "
704 "bad request up to channel %d. Squelching.", me->
o_num_channel, num);
710 sprintf(msg,
"Error: (handle_request_channels_message): invalid channel %d. Squelching.", num);
719 wiiuse_rumble(me->wiimote->device, 1);
721 wiiuse_rumble(me->wiimote->device, 0);
732#if defined (vrpn_THREADS_AVAILABLE)
735 vrpn_WiiMote_SharedData *sharedData =
static_cast<vrpn_WiiMote_SharedData *
>(threadData.
pvUD);
736 if (! sharedData || ! sharedData->wmHandle) {
741 sharedData->connectLock.p();
742 if (sharedData->stopFlag) {
745 sharedData->wmHandle->connect_wiimote(3);
747 sharedData->connectLock.v();
vrpn_float64 o_channel[vrpn_CHANNEL_MAX]
vrpn_int32 request_channels_m_id
vrpn_float64 channel[vrpn_CHANNEL_MAX]
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 ...
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...
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.
vrpn_int32 d_sender_id
Sender ID registered with the connection.
void server_mainloop(void)
Handles functions that all servers should provide in their mainloop() (ping/pong, for example) Should...
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.
Generic connection class not specific to the transport mechanism.
virtual vrpn_int32 register_message_type(const char *name)
static int VRPN_CALLBACK handle_request_message(void *userdata, vrpn_HANDLERPARAM p)
vrpn_WiiMote(const char *name, vrpn_Connection *c=NULL, unsigned which=0, unsigned useMS=1, unsigned useIR=1, unsigned reorderButtons=0, const char *bdaddr=NULL)
static int VRPN_CALLBACK handle_request_channels_message(void *userdata, vrpn_HANDLERPARAM p)
static int VRPN_CALLBACK handle_last_connection_dropped(void *selfPtr, vrpn_HANDLERPARAM data)
virtual void mainloop()
Called once through each main loop iteration to handle updates. Remote object mainloop() should call ...
This structure is what is passed to a vrpn_Connection message callback.
const char * vrpn_dropped_last_connection
VRPN_API int vrpn_unbuffer(const char **buffer, timeval *t)
Utility routine for taking a struct timeval from a buffer that was sent as a message.
timeval vrpn_TimevalDiff(const timeval &tv1, const timeval &tv2)
void vrpn_SleepMsecs(double dMilliSecs)
#define vrpn_gettimeofday
#define VRPN_WIIUSE_MAX_WIIMOTES