123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992 |
- /*
- * wiiuse
- *
- * Written By:
- * Michael Laforest < para >
- * Email: < thepara (--AT--) g m a i l [--DOT--] com >
- *
- * Copyright 2006-2007
- *
- * This file is part of wiiuse.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * $Header$
- *
- */
- /**
- * @file
- * @brief Handles wiimote events.
- *
- * The file includes functions that handle the events
- * that are sent from the wiimote to us.
- */
- #include "wiiuse_internal.h"
- #include "events.h"
- #include "classic.h" /* for classic_ctrl_disconnected, etc */
- #include "dynamics.h" /* for calculate_gforce, etc */
- #include "guitar_hero_3.h" /* for guitar_hero_3_disconnected, etc */
- #include "ir.h" /* for calculate_basic_ir, etc */
- #include "nunchuk.h" /* for nunchuk_disconnected, etc */
- #include "wiiboard.h" /* for wii_board_disconnected, etc */
- #include "motion_plus.h" /* for motion_plus_disconnected, etc */
- #include "os.h" /* for wiiuse_os_poll */
- #include <stdio.h> /* for printf, perror */
- #include <stdlib.h> /* for free, malloc */
- #include <string.h> /* for memcpy, memset */
- static void event_data_read(struct wiimote_t* wm, byte* msg);
- static void event_data_write(struct wiimote_t *wm, byte *msg);
- static void event_status(struct wiimote_t* wm, byte* msg);
- static void handle_expansion(struct wiimote_t* wm, byte* msg);
- static void save_state(struct wiimote_t* wm);
- static int state_changed(struct wiimote_t* wm);
- /**
- * @brief Poll the wiimotes for any events.
- *
- * @param wm An array of pointers to wiimote_t structures.
- * @param wiimotes The number of wiimote_t structures in the \a wm array.
- *
- * @return Returns number of wiimotes that an event has occurred on.
- *
- * It is necessary to poll the wiimote devices for events
- * that occur. If an event occurs on a particular wiimote,
- * the event variable will be set.
- */
- int wiiuse_poll(struct wiimote_t** wm, int wiimotes) {
- return wiiuse_os_poll(wm, wiimotes);
- }
- int wiiuse_update(struct wiimote_t** wiimotes, int nwiimotes, wiiuse_update_cb callback) {
- int evnt = 0;
- if (wiiuse_poll(wiimotes, nwiimotes)) {
- static struct wiimote_callback_data_t s;
- int i = 0;
- for (; i < nwiimotes; ++i) {
- switch (wiimotes[i]->event) {
- case WIIUSE_NONE:
- break;
- default:
- /* this could be: WIIUSE_EVENT, WIIUSE_STATUS, WIIUSE_CONNECT, etc.. */
- s.uid = wiimotes[i]->unid;
- s.leds = wiimotes[i]->leds;
- s.battery_level = wiimotes[i]->battery_level;
- s.accel = wiimotes[i]->accel;
- s.orient = wiimotes[i]->orient;
- s.gforce = wiimotes[i]->gforce;
- s.ir = wiimotes[i]->ir;
- s.buttons = wiimotes[i]->btns;
- s.buttons_held = wiimotes[i]->btns_held;
- s.buttons_released = wiimotes[i]->btns_released;
- s.event = wiimotes[i]->event;
- s.state = wiimotes[i]->state;
- s.expansion = wiimotes[i]->exp;
- callback(&s);
- evnt++;
- break;
- }
- }
- }
- return evnt;
- }
- /**
- * @brief Called on a cycle where no significant change occurs.
- *
- * @param wm Pointer to a wiimote_t structure.
- */
- void idle_cycle(struct wiimote_t* wm) {
- /*
- * Smooth the angles.
- *
- * This is done to make sure that on every cycle the orientation
- * angles are smoothed. Normally when an event occurs the angles
- * are updated and smoothed, but if no packet comes in then the
- * angles remain the same. This means the angle wiiuse reports
- * is still an old value. Smoothing needs to be applied in this
- * case in order for the angle it reports to converge to the true
- * angle of the device.
- */
- if (WIIUSE_USING_ACC(wm) && WIIMOTE_IS_FLAG_SET(wm, WIIUSE_SMOOTHING)) {
- apply_smoothing(&wm->accel_calib, &wm->orient, SMOOTH_ROLL);
- apply_smoothing(&wm->accel_calib, &wm->orient, SMOOTH_PITCH);
- }
- /* clear out any old read requests */
- clear_dirty_reads(wm);
- }
- /**
- * @brief Clear out all old 'dirty' read requests.
- *
- * @param wm Pointer to a wiimote_t structure.
- */
- void clear_dirty_reads(struct wiimote_t* wm) {
- struct read_req_t* req = wm->read_req;
- while (req && req->dirty) {
- WIIUSE_DEBUG("Cleared old read request for address: %x", req->addr);
- wm->read_req = req->next;
- free(req);
- req = wm->read_req;
- }
- }
- /**
- * @brief Handle accel data in a wiimote message.
- *
- * @param wm Pointer to a wiimote_t structure.
- * @param msg The message specified in the event packet.
- */
- static void handle_wm_accel(struct wiimote_t* wm, byte* msg) {
- wm->accel.x = msg[2];
- wm->accel.y = msg[3];
- wm->accel.z = msg[4];
- /* calculate the remote orientation */
- calculate_orientation(&wm->accel_calib, &wm->accel, &wm->orient, WIIMOTE_IS_FLAG_SET(wm, WIIUSE_SMOOTHING));
- /* calculate the gforces on each axis */
- calculate_gforce(&wm->accel_calib, &wm->accel, &wm->gforce);
- }
- /**
- * @brief Analyze the event that occurred on a wiimote.
- *
- * @param wm Pointer to a wiimote_t structure.
- * @param event The event that occurred.
- * @param msg The message specified in the event packet.
- *
- * Pass the event to the registered event callback.
- */
- void propagate_event(struct wiimote_t* wm, byte event, byte* msg) {
- save_state(wm);
- switch (event) {
- case WM_RPT_BTN: {
- /* button */
- wiiuse_pressed_buttons(wm, msg);
- break;
- }
- case WM_RPT_BTN_ACC: {
- /* button - motion */
- wiiuse_pressed_buttons(wm, msg);
- handle_wm_accel(wm, msg);
- break;
- }
- case WM_RPT_READ: {
- /* data read */
- event_data_read(wm, msg);
- /* yeah buttons may be pressed, but this wasn't an "event" */
- return;
- }
- case WM_RPT_CTRL_STATUS: {
- /* controller status */
- event_status(wm, msg);
- /* don't execute the event callback */
- return;
- }
- case WM_RPT_BTN_EXP: {
- /* button - expansion */
- wiiuse_pressed_buttons(wm, msg);
- handle_expansion(wm, msg + 2);
- break;
- }
- case WM_RPT_BTN_ACC_EXP: {
- /* button - motion - expansion */
- wiiuse_pressed_buttons(wm, msg);
- handle_wm_accel(wm, msg);
- handle_expansion(wm, msg + 5);
- break;
- }
- case WM_RPT_BTN_ACC_IR: {
- /* button - motion - ir */
- wiiuse_pressed_buttons(wm, msg);
- handle_wm_accel(wm, msg);
- /* ir */
- calculate_extended_ir(wm, msg + 5);
- break;
- }
- case WM_RPT_BTN_IR_EXP: {
- /* button - ir - expansion */
- wiiuse_pressed_buttons(wm, msg);
- handle_expansion(wm, msg + 12);
- /* ir */
- calculate_basic_ir(wm, msg + 2);
- break;
- }
- case WM_RPT_BTN_ACC_IR_EXP: {
- /* button - motion - ir - expansion */
- wiiuse_pressed_buttons(wm, msg);
- handle_wm_accel(wm, msg);
- handle_expansion(wm, msg + 15);
- /* ir */
- calculate_basic_ir(wm, msg + 5);
- break;
- }
- case WM_RPT_WRITE: {
- event_data_write(wm, msg);
- break;
- }
- default: {
- WIIUSE_WARNING("Unknown event, can not handle it [Code 0x%x].", event);
- return;
- }
- }
- /* was there an event? */
- if (state_changed(wm)) {
- wm->event = WIIUSE_EVENT;
- }
- }
- /**
- * @brief Find what buttons are pressed.
- *
- * @param wm Pointer to a wiimote_t structure.
- * @param msg The message specified in the event packet.
- */
- void wiiuse_pressed_buttons(struct wiimote_t* wm, byte* msg) {
- int16_t now;
- /* convert from big endian */
- now = from_big_endian_uint16_t(msg) & WIIMOTE_BUTTON_ALL;
- /* pressed now & were pressed, then held */
- wm->btns_held = (now & wm->btns);
- /* were pressed or were held & not pressed now, then released */
- wm->btns_released = ((wm->btns | wm->btns_held) & ~now);
- /* buttons pressed now */
- wm->btns = now;
- }
- /**
- * @brief Received a data packet from a read request.
- *
- * @param wm Pointer to a wiimote_t structure.
- * @param msg The message specified in the event packet.
- *
- * Data from the wiimote comes in packets. If the requested
- * data segment size is bigger than one packet can hold then
- * several packets will be received. These packets are first
- * reassembled into one, then the registered callback function
- * that handles data reads is invoked.
- */
- static void event_data_read(struct wiimote_t* wm, byte* msg) {
- /* we must always assume the packet received is from the most recent request */
- byte err;
- byte len;
- uint16_t offset;
- struct read_req_t* req = wm->read_req;
- wiiuse_pressed_buttons(wm, msg);
- /* find the next non-dirty request */
- while (req && req->dirty) {
- req = req->next;
- }
- /* if we don't have a request out then we didn't ask for this packet */
- if (!req) {
- WIIUSE_WARNING("Received data packet when no request was made.");
- return;
- }
- err = msg[2] & 0x0F;
- if (err == 0x08) {
- WIIUSE_WARNING("Unable to read data - address does not exist.");
- } else if (err == 0x07) {
- WIIUSE_WARNING("Unable to read data - address is for write-only registers.");
- } else if (err) {
- WIIUSE_WARNING("Unable to read data - unknown error code %x.", err);
- }
- if (err) {
- /* this request errored out, so skip it and go to the next one */
- /* delete this request */
- wm->read_req = req->next;
- free(req);
- /* if another request exists send it to the wiimote */
- if (wm->read_req) {
- wiiuse_send_next_pending_read_request(wm);
- }
- return;
- }
- len = ((msg[2] & 0xF0) >> 4) + 1;
- offset = from_big_endian_uint16_t(msg + 3);
- req->addr = (req->addr & 0xFFFF);
- req->wait -= len;
- if (req->wait >= req->size)
- /* this should never happen */
- {
- req->wait = 0;
- }
- WIIUSE_DEBUG("Received read packet:");
- WIIUSE_DEBUG(" Packet read offset: %i bytes", offset);
- WIIUSE_DEBUG(" Request read offset: %i bytes", req->addr);
- WIIUSE_DEBUG(" Read offset into buf: %i bytes", offset - req->addr);
- WIIUSE_DEBUG(" Read data size: %i bytes", len);
- WIIUSE_DEBUG(" Still need: %i bytes", req->wait);
- /* reconstruct this part of the data */
- memcpy((req->buf + offset - req->addr), (msg + 5), len);
- #ifdef WITH_WIIUSE_DEBUG
- {
- int i = 0;
- printf("Read: ");
- for (; i < req->size - req->wait; ++i) {
- printf("%x ", req->buf[i]);
- }
- printf("\n");
- }
- #endif
- /* if all data has been received, execute the read event callback or generate event */
- if (!req->wait) {
- if (req->cb) {
- /* this was a callback, so invoke it now */
- req->cb(wm, req->buf, req->size);
- /* delete this request */
- wm->read_req = req->next;
- free(req);
- } else {
- /*
- * This should generate an event.
- * We need to leave the event in the array so the client
- * can access it still. We'll flag is as being 'dirty'
- * and give the client one cycle to use it. Next event
- * we will remove it from the list.
- */
- wm->event = WIIUSE_READ_DATA;
- req->dirty = 1;
- }
- /* if another request exists send it to the wiimote */
- if (wm->read_req) {
- wiiuse_send_next_pending_read_request(wm);
- }
- }
- }
- static void event_data_write(struct wiimote_t *wm, byte *msg) {
- struct data_req_t* req = wm->data_req;
- wiiuse_pressed_buttons(wm, msg);
- /* if we don't have a request out then we didn't ask for this packet */
- if (!req) {
- WIIUSE_WARNING("Transmitting data packet when no request was made.");
- return;
- }
- if (!(req->state == REQ_SENT)) {
- WIIUSE_WARNING("Transmission is not necessary");
- /* delete this request */
- wm->data_req = req->next;
- free(req);
- return;
- }
- req->state = REQ_DONE;
- if (req->cb) {
- /* this was a callback, so invoke it now */
- req->cb(wm, NULL, 0);
- /* delete this request */
- wm->data_req = req->next;
- free(req);
- } else {
- /*
- * This should generate an event.
- * We need to leave the event in the array so the client
- * can access it still. We'll flag is as being 'REQ_DONE'
- * and give the client one cycle to use it. Next event
- * we will remove it from the list.
- */
- wm->event = WIIUSE_WRITE_DATA;
- }
- /* if another request exists send it to the wiimote */
- if (wm->data_req) {
- wiiuse_send_next_pending_write_request(wm);
- }
- }
- /**
- * @brief Read the controller status.
- *
- * @param wm Pointer to a wiimote_t structure.
- * @param msg The message specified in the event packet.
- *
- * Read the controller status and execute the registered status callback.
- */
- static void event_status(struct wiimote_t* wm, byte* msg) {
- int led[4] = {0, 0, 0, 0};
- int attachment = 0;
- int ir = 0;
- int exp_changed = 0;
- struct data_req_t* req = wm->data_req;
- /* initial handshake is not finished yet, ignore this */
- if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_HANDSHAKE)) {
- return;
- }
- /*
- * An event occurred.
- * This event can be overwritten by a more specific
- * event type during a handshake or expansion removal.
- */
- wm->event = WIIUSE_STATUS;
- wiiuse_pressed_buttons(wm, msg);
- /* find what LEDs are lit */
- if (msg[2] & WM_CTRL_STATUS_BYTE1_LED_1) {
- led[0] = 1;
- }
- if (msg[2] & WM_CTRL_STATUS_BYTE1_LED_2) {
- led[1] = 1;
- }
- if (msg[2] & WM_CTRL_STATUS_BYTE1_LED_3) {
- led[2] = 1;
- }
- if (msg[2] & WM_CTRL_STATUS_BYTE1_LED_4) {
- led[3] = 1;
- }
- /* probe for Motion+ */
- if (!WIIMOTE_IS_SET(wm, WIIMOTE_STATE_MPLUS_PRESENT)) {
- wiiuse_probe_motion_plus(wm);
- }
- /* is an attachment connected to the expansion port? */
- if ((msg[2] & WM_CTRL_STATUS_BYTE1_ATTACHMENT) == WM_CTRL_STATUS_BYTE1_ATTACHMENT) {
- WIIUSE_DEBUG("Attachment detected!");
- attachment = 1;
- }
- /* is the speaker enabled? */
- if ((msg[2] & WM_CTRL_STATUS_BYTE1_SPEAKER_ENABLED) == WM_CTRL_STATUS_BYTE1_SPEAKER_ENABLED) {
- WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_SPEAKER);
- }
- /* is IR sensing enabled? */
- if ((msg[2] & WM_CTRL_STATUS_BYTE1_IR_ENABLED) == WM_CTRL_STATUS_BYTE1_IR_ENABLED) {
- ir = 1;
- }
- /* find the battery level and normalize between 0 and 1 */
- wm->battery_level = (msg[5] / (float)WM_MAX_BATTERY_CODE);
- /* expansion port */
- if (attachment && !WIIMOTE_IS_SET(wm, WIIMOTE_STATE_EXP) && !WIIMOTE_IS_SET(wm, WIIMOTE_STATE_EXP_HANDSHAKE)) {
- /* send the initialization code for the attachment */
- handshake_expansion(wm, NULL, 0);
- exp_changed = 1;
- } else if (!attachment && WIIMOTE_IS_SET(wm, WIIMOTE_STATE_EXP)) {
- /* attachment removed */
- disable_expansion(wm);
- exp_changed = 1;
- }
- #ifdef WIIUSE_WIN32
- if (!attachment) {
- WIIUSE_DEBUG("Setting timeout to normal %i ms.", wm->normal_timeout);
- wm->timeout = wm->normal_timeout;
- }
- #endif
- /*
- * From now on the remote will only send status packets.
- * We need to send a WIIMOTE_CMD_REPORT_TYPE packet to
- * reenable other incoming reports.
- */
- if (exp_changed && WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR)) {
- /*
- * Since the expansion status changed IR needs to
- * be reset for the new IR report mode.
- */
- WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_IR);
- wiiuse_set_ir(wm, 1);
- } else {
- wiiuse_set_report_type(wm);
- return;
- }
- /* handling new Tx for changed exp */
- if (!req) {
- return;
- }
- if (!(req->state == REQ_SENT)) {
- return;
- }
- wm->data_req = req->next;
- req->state = REQ_DONE;
- /* if(req->cb!=NULL) req->cb(wm,msg,6); */
- free(req);
- }
- /**
- * @brief Handle data from the expansion.
- *
- * @param wm A pointer to a wiimote_t structure.
- * @param msg The message specified in the event packet for the expansion.
- */
- static void handle_expansion(struct wiimote_t* wm, byte* msg) {
- switch (wm->exp.type) {
- case EXP_NUNCHUK:
- nunchuk_event(&wm->exp.nunchuk, msg);
- break;
- case EXP_CLASSIC:
- classic_ctrl_event(&wm->exp.classic, msg);
- break;
- case EXP_GUITAR_HERO_3:
- guitar_hero_3_event(&wm->exp.gh3, msg);
- break;
- case EXP_WII_BOARD:
- wii_board_event(&wm->exp.wb, msg);
- break;
- case EXP_MOTION_PLUS:
- case EXP_MOTION_PLUS_CLASSIC:
- case EXP_MOTION_PLUS_NUNCHUK:
- motion_plus_event(&wm->exp.mp, wm->exp.type, msg);
- break;
- default:
- break;
- }
- }
- /**
- * @brief Handle the handshake data from the expansion device.
- *
- * @param wm A pointer to a wiimote_t structure.
- * @param data The data read in from the device.
- * @param len The length of the data block, in bytes.
- *
- * Tries to determine what kind of expansion was attached
- * and invoke the correct handshake function.
- *
- * If the data is NULL then this function will try to start
- * a handshake with the expansion.
- */
- void handshake_expansion(struct wiimote_t* wm, byte* data, uint16_t len) {
- int id;
- byte val = 0;
- byte buf = 0x00;
- byte* handshake_buf;
- int gotIt = 0;
- WIIUSE_DEBUG("handshake_expansion with state %d", wm->expansion_state);
- switch (wm->expansion_state) {
- /* These two initialization writes disable the encryption */
- case 0:
- wm->expansion_state = 1;
- /* increase the timeout until the handshake completes */
- #ifdef WIIUSE_WIN32
- WIIUSE_DEBUG("write 0x55 - Setting timeout to expansion %i ms.", wm->exp_timeout);
- wm->timeout = wm->exp_timeout;
- #endif
- buf = 0x55;
- wiiuse_write_data_cb(wm, WM_EXP_MEM_ENABLE1, &buf, 1, handshake_expansion);
- break;
- case 1:
- wm->expansion_state = 2;
- /* increase the timeout until the handshake completes */
- #ifdef WIIUSE_WIN32
- WIIUSE_DEBUG("write 0x00 - Setting timeout to expansion %i ms.", wm->exp_timeout);
- wm->timeout = wm->exp_timeout;
- #endif
- val = 0x00;
- wiiuse_write_data_cb(wm, WM_EXP_MEM_ENABLE2, &buf, 1, handshake_expansion);
- break;
- case 2:
- wm->expansion_state = 3;
- /* get the calibration data */
- if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_EXP)) {
- disable_expansion(wm);
- }
- handshake_buf = malloc(EXP_HANDSHAKE_LEN * sizeof(byte));
- /* tell the wiimote to send expansion data */
- WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_EXP);
- wiiuse_read_data_cb(wm, handshake_expansion, handshake_buf, WM_EXP_MEM_CALIBR, EXP_HANDSHAKE_LEN);
- break;
- case 3:
- if (!data || !len) {
- WIIUSE_DEBUG("no handshake data received from expansion");
- disable_expansion(wm);
- return;
- }
- wm->expansion_state = 0;
- id = from_big_endian_uint32_t(data + 220);
- switch (id) {
- case EXP_ID_CODE_NUNCHUK:
- if (nunchuk_handshake(wm, &wm->exp.nunchuk, data, len)) {
- wm->event = WIIUSE_NUNCHUK_INSERTED;
- gotIt = 1;
- }
- break;
- case EXP_ID_CODE_CLASSIC_CONTROLLER:
- if (classic_ctrl_handshake(wm, &wm->exp.classic, data, len)) {
- wm->event = WIIUSE_CLASSIC_CTRL_INSERTED;
- gotIt = 1;
- }
- break;
- case EXP_ID_CODE_GUITAR:
- if (guitar_hero_3_handshake(wm, &wm->exp.gh3, data, len)) {
- wm->event = WIIUSE_GUITAR_HERO_3_CTRL_INSERTED;
- gotIt = 1;
- }
- break;
- case EXP_ID_CODE_MOTION_PLUS:
- case EXP_ID_CODE_MOTION_PLUS_CLASSIC:
- case EXP_ID_CODE_MOTION_PLUS_NUNCHUK:
- /* wiiuse_motion_plus_handshake(wm, data, len); */
- wm->event = WIIUSE_MOTION_PLUS_ACTIVATED;
- gotIt = 1;
- break;
- case EXP_ID_CODE_WII_BOARD:
- if (wii_board_handshake(wm, &wm->exp.wb, data, len)) {
- wm->event = WIIUSE_WII_BOARD_CTRL_INSERTED;
- gotIt = 1;
- }
- break;
- default:
- WIIUSE_WARNING("Unknown expansion type. Code: 0x%x", id);
- break;
- }
- free(data);
- if (gotIt) {
- WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_EXP_HANDSHAKE);
- WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_EXP);
- } else {
- WIIUSE_WARNING("Could not handshake with expansion id: 0x%x", id);
- }
- wiiuse_set_ir_mode(wm);
- wiiuse_status(wm);
- break;
- }
- }
- /**
- * @brief Disable the expansion device if it was enabled.
- *
- * @param wm A pointer to a wiimote_t structure.
- * @param data The data read in from the device.
- * @param len The length of the data block, in bytes.
- *
- * If the data is NULL then this function will try to start
- * a handshake with the expansion.
- */
- void disable_expansion(struct wiimote_t* wm) {
- WIIUSE_DEBUG("Disabling expansion");
- if (!WIIMOTE_IS_SET(wm, WIIMOTE_STATE_EXP)) {
- return;
- }
- /* tell the associated module the expansion was removed */
- switch (wm->exp.type) {
- case EXP_NUNCHUK:
- nunchuk_disconnected(&wm->exp.nunchuk);
- wm->event = WIIUSE_NUNCHUK_REMOVED;
- break;
- case EXP_CLASSIC:
- classic_ctrl_disconnected(&wm->exp.classic);
- wm->event = WIIUSE_CLASSIC_CTRL_REMOVED;
- break;
- case EXP_GUITAR_HERO_3:
- guitar_hero_3_disconnected(&wm->exp.gh3);
- wm->event = WIIUSE_GUITAR_HERO_3_CTRL_REMOVED;
- break;
- case EXP_WII_BOARD:
- wii_board_disconnected(&wm->exp.wb);
- wm->event = WIIUSE_WII_BOARD_CTRL_REMOVED;
- break;
- case EXP_MOTION_PLUS:
- case EXP_MOTION_PLUS_CLASSIC:
- case EXP_MOTION_PLUS_NUNCHUK:
- motion_plus_disconnected(&wm->exp.mp);
- wm->event = WIIUSE_MOTION_PLUS_REMOVED;
- break;
- default:
- break;
- }
- WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_EXP);
- wm->exp.type = EXP_NONE;
- wm->expansion_state = 0;
- }
- /**
- * @brief Save important state data.
- * @param wm A pointer to a wiimote_t structure.
- */
- static void save_state(struct wiimote_t* wm) {
- /* wiimote */
- wm->lstate.btns = wm->btns;
- wm->lstate.accel = wm->accel;
- /* ir */
- if (WIIUSE_USING_IR(wm)) {
- wm->lstate.ir_ax = wm->ir.ax;
- wm->lstate.ir_ay = wm->ir.ay;
- wm->lstate.ir_distance = wm->ir.distance;
- }
- /* expansion */
- switch (wm->exp.type) {
- case EXP_NUNCHUK:
- wm->lstate.exp_ljs_ang = wm->exp.nunchuk.js.ang;
- wm->lstate.exp_ljs_mag = wm->exp.nunchuk.js.mag;
- wm->lstate.exp_btns = wm->exp.nunchuk.btns;
- wm->lstate.exp_accel = wm->exp.nunchuk.accel;
- break;
- case EXP_CLASSIC:
- wm->lstate.exp_ljs_ang = wm->exp.classic.ljs.ang;
- wm->lstate.exp_ljs_mag = wm->exp.classic.ljs.mag;
- wm->lstate.exp_rjs_ang = wm->exp.classic.rjs.ang;
- wm->lstate.exp_rjs_mag = wm->exp.classic.rjs.mag;
- wm->lstate.exp_r_shoulder = wm->exp.classic.r_shoulder;
- wm->lstate.exp_l_shoulder = wm->exp.classic.l_shoulder;
- wm->lstate.exp_btns = wm->exp.classic.btns;
- break;
- case EXP_GUITAR_HERO_3:
- wm->lstate.exp_ljs_ang = wm->exp.gh3.js.ang;
- wm->lstate.exp_ljs_mag = wm->exp.gh3.js.mag;
- wm->lstate.exp_r_shoulder = wm->exp.gh3.whammy_bar;
- wm->lstate.exp_btns = wm->exp.gh3.btns;
- break;
- case EXP_WII_BOARD:
- wm->lstate.exp_wb_rtr = wm->exp.wb.rtr;
- wm->lstate.exp_wb_rtl = wm->exp.wb.rtl;
- wm->lstate.exp_wb_rbr = wm->exp.wb.rbr;
- wm->lstate.exp_wb_rbl = wm->exp.wb.rbl;
- break;
- case EXP_MOTION_PLUS:
- case EXP_MOTION_PLUS_CLASSIC:
- case EXP_MOTION_PLUS_NUNCHUK: {
- wm->lstate.drx = wm->exp.mp.raw_gyro.pitch;
- wm->lstate.dry = wm->exp.mp.raw_gyro.roll;
- wm->lstate.drz = wm->exp.mp.raw_gyro.yaw;
- if (wm->exp.type == EXP_MOTION_PLUS_CLASSIC) {
- wm->lstate.exp_ljs_ang = wm->exp.classic.ljs.ang;
- wm->lstate.exp_ljs_mag = wm->exp.classic.ljs.mag;
- wm->lstate.exp_rjs_ang = wm->exp.classic.rjs.ang;
- wm->lstate.exp_rjs_mag = wm->exp.classic.rjs.mag;
- wm->lstate.exp_r_shoulder = wm->exp.classic.r_shoulder;
- wm->lstate.exp_l_shoulder = wm->exp.classic.l_shoulder;
- wm->lstate.exp_btns = wm->exp.classic.btns;
- } else {
- wm->lstate.exp_ljs_ang = wm->exp.nunchuk.js.ang;
- wm->lstate.exp_ljs_mag = wm->exp.nunchuk.js.mag;
- wm->lstate.exp_btns = wm->exp.nunchuk.btns;
- wm->lstate.exp_accel = wm->exp.nunchuk.accel;
- }
- break;
- }
- case EXP_NONE:
- break;
- }
- }
- /**
- * @brief Determine if the current state differs significantly from the previous.
- * @param wm A pointer to a wiimote_t structure.
- * @return 1 if a significant change occurred, 0 if not.
- */
- static int state_changed(struct wiimote_t* wm) {
- #define STATE_CHANGED(a, b) if (a != b) return 1
- #define CROSS_THRESH(last, now, thresh) \
- do { \
- if (WIIMOTE_IS_FLAG_SET(wm, WIIUSE_ORIENT_THRESH)) { \
- if ((diff_f(last.roll, now.roll) >= thresh) || \
- (diff_f(last.pitch, now.pitch) >= thresh) || \
- (diff_f(last.yaw, now.yaw) >= thresh)) \
- { \
- last = now; \
- return 1; \
- } \
- } else { \
- if (last.roll != now.roll) return 1; \
- if (last.pitch != now.pitch) return 1; \
- if (last.yaw != now.yaw) return 1; \
- } \
- } while (0)
- #define CROSS_THRESH_XYZ(last, now, thresh) \
- do { \
- if (WIIMOTE_IS_FLAG_SET(wm, WIIUSE_ORIENT_THRESH)) { \
- if ((diff_f(last.x, now.x) >= thresh) || \
- (diff_f(last.y, now.y) >= thresh) || \
- (diff_f(last.z, now.z) >= thresh)) \
- { \
- last = now; \
- return 1; \
- } \
- } else { \
- if (last.x != now.x) return 1; \
- if (last.y != now.y) return 1; \
- if (last.z != now.z) return 1; \
- } \
- } while (0)
- /* ir */
- if (WIIUSE_USING_IR(wm)) {
- STATE_CHANGED(wm->lstate.ir_ax, wm->ir.ax);
- STATE_CHANGED(wm->lstate.ir_ay, wm->ir.ay);
- STATE_CHANGED(wm->lstate.ir_distance, wm->ir.distance);
- }
- /* accelerometer */
- if (WIIUSE_USING_ACC(wm)) {
- /* raw accelerometer */
- CROSS_THRESH_XYZ(wm->lstate.accel, wm->accel, wm->accel_threshold);
- /* orientation */
- CROSS_THRESH(wm->lstate.orient, wm->orient, wm->orient_threshold);
- }
- /* expansion */
- switch (wm->exp.type) {
- case EXP_NUNCHUK: {
- STATE_CHANGED(wm->lstate.exp_ljs_ang, wm->exp.nunchuk.js.ang);
- STATE_CHANGED(wm->lstate.exp_ljs_mag, wm->exp.nunchuk.js.mag);
- STATE_CHANGED(wm->lstate.exp_btns, wm->exp.nunchuk.btns);
- CROSS_THRESH(wm->lstate.exp_orient, wm->exp.nunchuk.orient, wm->exp.nunchuk.orient_threshold);
- CROSS_THRESH_XYZ(wm->lstate.exp_accel, wm->exp.nunchuk.accel, wm->exp.nunchuk.accel_threshold);
- break;
- }
- case EXP_CLASSIC: {
- STATE_CHANGED(wm->lstate.exp_ljs_ang, wm->exp.classic.ljs.ang);
- STATE_CHANGED(wm->lstate.exp_ljs_mag, wm->exp.classic.ljs.mag);
- STATE_CHANGED(wm->lstate.exp_rjs_ang, wm->exp.classic.rjs.ang);
- STATE_CHANGED(wm->lstate.exp_rjs_mag, wm->exp.classic.rjs.mag);
- STATE_CHANGED(wm->lstate.exp_r_shoulder, wm->exp.classic.r_shoulder);
- STATE_CHANGED(wm->lstate.exp_l_shoulder, wm->exp.classic.l_shoulder);
- STATE_CHANGED(wm->lstate.exp_btns, wm->exp.classic.btns);
- break;
- }
- case EXP_GUITAR_HERO_3: {
- STATE_CHANGED(wm->lstate.exp_ljs_ang, wm->exp.gh3.js.ang);
- STATE_CHANGED(wm->lstate.exp_ljs_mag, wm->exp.gh3.js.mag);
- STATE_CHANGED(wm->lstate.exp_r_shoulder, wm->exp.gh3.whammy_bar);
- STATE_CHANGED(wm->lstate.exp_btns, wm->exp.gh3.btns);
- break;
- }
- case EXP_WII_BOARD: {
- STATE_CHANGED(wm->lstate.exp_wb_rtr, wm->exp.wb.tr);
- STATE_CHANGED(wm->lstate.exp_wb_rtl, wm->exp.wb.tl);
- STATE_CHANGED(wm->lstate.exp_wb_rbr, wm->exp.wb.br);
- STATE_CHANGED(wm->lstate.exp_wb_rbl, wm->exp.wb.bl);
- break;
- }
- case EXP_MOTION_PLUS:
- case EXP_MOTION_PLUS_CLASSIC:
- case EXP_MOTION_PLUS_NUNCHUK: {
- STATE_CHANGED(wm->lstate.drx, wm->exp.mp.raw_gyro.pitch);
- STATE_CHANGED(wm->lstate.dry, wm->exp.mp.raw_gyro.roll);
- STATE_CHANGED(wm->lstate.drz, wm->exp.mp.raw_gyro.yaw);
- if (wm->exp.type == EXP_MOTION_PLUS_CLASSIC) {
- STATE_CHANGED(wm->lstate.exp_ljs_ang, wm->exp.classic.ljs.ang);
- STATE_CHANGED(wm->lstate.exp_ljs_mag, wm->exp.classic.ljs.mag);
- STATE_CHANGED(wm->lstate.exp_rjs_ang, wm->exp.classic.rjs.ang);
- STATE_CHANGED(wm->lstate.exp_rjs_mag, wm->exp.classic.rjs.mag);
- STATE_CHANGED(wm->lstate.exp_r_shoulder, wm->exp.classic.r_shoulder);
- STATE_CHANGED(wm->lstate.exp_l_shoulder, wm->exp.classic.l_shoulder);
- STATE_CHANGED(wm->lstate.exp_btns, wm->exp.classic.btns);
- } else {
- STATE_CHANGED(wm->lstate.exp_ljs_ang, wm->exp.nunchuk.js.ang);
- STATE_CHANGED(wm->lstate.exp_ljs_mag, wm->exp.nunchuk.js.mag);
- STATE_CHANGED(wm->lstate.exp_btns, wm->exp.nunchuk.btns);
- CROSS_THRESH(wm->lstate.exp_orient, wm->exp.nunchuk.orient, wm->exp.nunchuk.orient_threshold);
- CROSS_THRESH_XYZ(wm->lstate.exp_accel, wm->exp.nunchuk.accel, wm->exp.nunchuk.accel_threshold);
- }
- break;
- }
- case EXP_NONE: {
- break;
- }
- }
- STATE_CHANGED(wm->lstate.btns, wm->btns);
- return 0;
- }
|