int wiiuse_set_report_type(struct wiimote_t *wm,cmd_blk_cb cb) { ubyte buf[2]; int motion,ir,exp; if(!wm || !WIIMOTE_IS_CONNECTED(wm)) return 0; buf[0] = (WIIMOTE_IS_FLAG_SET(wm, WIIUSE_CONTINUOUS) ? 0x04 : 0x00); /* set to 0x04 for continuous reporting */ buf[1] = 0x00; motion = WIIMOTE_IS_SET(wm, WIIMOTE_STATE_ACC) || WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR); exp = WIIMOTE_IS_SET(wm, WIIMOTE_STATE_EXP); ir = WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR); if (motion && ir && exp) buf[1] = WM_RPT_BTN_ACC_IR_EXP; else if (motion && exp) buf[1] = WM_RPT_BTN_ACC_EXP; else if (motion && ir) buf[1] = WM_RPT_BTN_ACC_IR; else if (ir && exp) buf[1] = WM_RPT_BTN_IR_EXP; else if (ir) buf[1] = WM_RPT_BTN_ACC_IR; else if (exp) buf[1] = WM_RPT_BTN_EXP; else if (motion) buf[1] = WM_RPT_BTN_ACC; else buf[1] = WM_RPT_BTN; WIIUSE_DEBUG("Setting report type: 0x%x", buf[1]); wiiuse_sendcmd(wm,WM_CMD_REPORT_TYPE,buf,2,cb); return buf[1]; }
int wiiuse_write_data(struct wiimote_t *wm,uint addr,ubyte *data,ubyte len,cmd_blk_cb cb) { struct op_t *op; struct cmd_blk_t *cmd; if(!wm || !WIIMOTE_IS_CONNECTED(wm)) return 0; if(!data || !len) return 0; cmd = (struct cmd_blk_t*)__lwp_queue_get(&wm->cmdq); if(!cmd) return 0; cmd->cb = cb; cmd->len = 22; op = (struct op_t*)cmd->data; op->cmd = WM_CMD_WRITE_DATA; op->buffer = NULL; op->wait = 0; op->writedata.addr = BIG_ENDIAN_LONG(addr); op->writedata.size = (len&0x0f); memcpy(op->writedata.data,data,len); memset(op->writedata.data+len,0,(16 - len)); __wiiuse_push_command(wm,cmd); return 1; }
/** * @brief Send the next pending data read request to the wiimote. * * @param wm Pointer to a wiimote_t structure. * * @see wiiuse_read_data() * * This function is not part of the wiiuse API. */ void wiiuse_send_next_pending_read_request(struct wiimote_t* wm) { byte buf[6]; struct read_req_t* req; if (!wm || !WIIMOTE_IS_CONNECTED(wm)) { return; } if (!wm->read_req) { return; } /* skip over dirty ones since they have already been read */ req = wm->read_req; while (req && req->dirty) { req = req->next; } if (!req) { return; } /* the offset is in big endian */ to_big_endian_uint32_t(buf, req->addr); /* the length is in big endian */ to_big_endian_uint16_t(buf + 4, req->size); WIIUSE_DEBUG("Request read at address: 0x%x length: %i", req->addr, req->size); wiiuse_send(wm, WM_CMD_READ_DATA, buf, 6); }
int wiiuse_io_write(struct wiimote_t* wm, byte* buf, int len) { DWORD bytes; int i; if (!wm || !WIIMOTE_IS_CONNECTED(wm)) return 0; switch (wm->stack) { case WIIUSE_STACK_UNKNOWN: { /* try to auto-detect the stack type */ if (i = WriteFile(wm->dev_handle, buf, 22, &bytes, &wm->hid_overlap)) { /* bluesoleil will always return 1 here, even if it's not connected */ wm->stack = WIIUSE_STACK_BLUESOLEIL; return i; } if (i = HidD_SetOutputReport(wm->dev_handle, buf, len)) { wm->stack = WIIUSE_STACK_MS; return i; } WIIUSE_ERROR("Unable to determine bluetooth stack type."); return 0; } case WIIUSE_STACK_MS: return HidD_SetOutputReport(wm->dev_handle, buf, len); case WIIUSE_STACK_BLUESOLEIL: return WriteFile(wm->dev_handle, buf, 22, &bytes, &wm->hid_overlap); } return 0; }
/** * @brief Enable or disable the rumble. * * @param wm Pointer to a wiimote_t structure. * @param status 1 to enable, 0 to disable. */ void wiiuse_rumble(struct wiimote_t* wm, int status) { byte buf; if (!wm || !WIIMOTE_IS_CONNECTED(wm)) { return; } /* make sure to keep the current lit leds */ buf = wm->leds; if (status) { WIIUSE_DEBUG("Starting rumble..."); WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_RUMBLE); buf |= 0x01; } else { WIIUSE_DEBUG("Stopping rumble..."); WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_RUMBLE); buf &= ~(0x01); } /* preserve IR state */ if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR)) { buf |= 0x04; } wiiuse_send(wm, WM_CMD_RUMBLE, &buf, 1); }
void wiiuse_status(struct wiimote_t *wm,cmd_blk_cb cb) { ubyte buf; if(!wm || !WIIMOTE_IS_CONNECTED(wm)) return; buf = 0x00; wiiuse_sendcmd(wm,WM_CMD_CTRL_STATUS,&buf,1,cb); }
void wiiuse_set_leds(struct wiimote_t *wm,int leds,cmd_blk_cb cb) { ubyte buf; if(!wm || !WIIMOTE_IS_CONNECTED(wm)) return; wm->leds = (leds&0xf0); buf = wm->leds; wiiuse_sendcmd(wm,WM_CMD_LED,&buf,1,cb); }
/** * @brief Request the wiimote controller status. * * @param wm Pointer to a wiimote_t structure. * * Controller status includes: battery level, LED status, expansions */ void wiiuse_status(struct wiimote_t* wm) { byte buf = 0; if (!wm || !WIIMOTE_IS_CONNECTED(wm)) { return; } WIIUSE_DEBUG("Requested wiimote status."); wiiuse_send(wm, WM_CMD_CTRL_STATUS, &buf, 1); }
/** * @brief Set the report type based on the current wiimote state. * * @param wm Pointer to a wiimote_t structure. * * @return The report type sent. * * The wiimote reports formatted packets depending on the * report type that was last requested. This function will * update the type of report that should be sent based on * the current state of the device. */ int wiiuse_set_report_type(struct wiimote_t* wm) { byte buf[2]; int motion, exp, ir, balance_board; if (!wm || !WIIMOTE_IS_CONNECTED(wm)) { return 0; } buf[0] = (WIIMOTE_IS_FLAG_SET(wm, WIIUSE_CONTINUOUS) ? 0x04 : 0x00); /* set to 0x04 for continuous reporting */ buf[1] = 0x00; /* if rumble is enabled, make sure we keep it */ if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_RUMBLE)) { buf[0] |= 0x01; } motion = WIIMOTE_IS_SET(wm, WIIMOTE_STATE_ACC); exp = WIIMOTE_IS_SET(wm, WIIMOTE_STATE_EXP); ir = WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR); balance_board = exp && (wm->exp.type == EXP_WII_BOARD); if (motion && ir && exp) { buf[1] = WM_RPT_BTN_ACC_IR_EXP; } else if (motion && exp) { buf[1] = WM_RPT_BTN_ACC_EXP; } else if (motion && ir) { buf[1] = WM_RPT_BTN_ACC_IR; } else if (ir && exp) { buf[1] = WM_RPT_BTN_IR_EXP; } else if (ir) { buf[1] = WM_RPT_BTN_ACC_IR; } else if(exp && balance_board) { if(wm->exp.wb.use_alternate_report) buf[1] = WM_RPT_BTN_EXP_8; else buf[1] = WM_RPT_BTN_EXP; } else if (exp) { buf[1] = WM_RPT_BTN_EXP; } else if (motion) { buf[1] = WM_RPT_BTN_ACC; } else { buf[1] = WM_RPT_BTN; } WIIUSE_DEBUG("Setting report type: 0x%x", buf[1]); exp = wiiuse_send(wm, WM_CMD_REPORT_TYPE, buf, 2); if (exp <= 0) { return exp; } return buf[1]; }
int wiiuse_os_read(struct wiimote_t* wm, byte* buf, int len) { DWORD b, r; if (!wm || !WIIMOTE_IS_CONNECTED(wm)) { return 0; } if (!ReadFile(wm->dev_handle, buf, len, &b, &wm->hid_overlap)) { /* partial read */ b = GetLastError(); if ((b == ERROR_HANDLE_EOF) || (b == ERROR_DEVICE_NOT_CONNECTED)) { /* remote disconnect */ wiiuse_disconnected(wm); return 0; } r = WaitForSingleObject(wm->hid_overlap.hEvent, wm->timeout); if (r == WAIT_TIMEOUT) { /* timeout - cancel and continue */ if (*buf) { WIIUSE_WARNING("Packet ignored. This may indicate a problem (timeout is %i ms).", wm->timeout); } CancelIo(wm->dev_handle); ResetEvent(wm->hid_overlap.hEvent); return 0; } else if (r == WAIT_FAILED) { WIIUSE_WARNING("A wait error occurred on reading from wiimote %i.", wm->unid); return 0; } if (!GetOverlappedResult(wm->dev_handle, &wm->hid_overlap, &b, 0)) { return 0; } /* log the received data */ #ifdef WITH_WIIUSE_DEBUG { DWORD i; printf("[DEBUG] (id %i) RECV: (%.2x) ", wm->unid, buf[0]); for (i = 1; i < b; i++) { printf("%.2x ", buf[i]); } printf("\n"); } #endif } ResetEvent(wm->hid_overlap.hEvent); return 1; }
/** * @brief Disconnect a wiimote. * * @param wm Pointer to a wiimote_t structure. * * @see wiic_connect() * * Note that this will not free the wiimote structure. */ void wiic_disconnect( struct wiimote_t* wm ) { if ( !wm || !WIIMOTE_IS_CONNECTED(wm) ) return; close( wm->out_sock ); close( wm->in_sock ); wm->out_sock = -1; wm->in_sock = -1; wm->event = WIIC_NONE; WIIMOTE_DISABLE_STATE( wm, WIIMOTE_STATE_CONNECTED ); WIIMOTE_DISABLE_STATE( wm, WIIMOTE_STATE_HANDSHAKE ); }
short any_wiimote_connected(wiimote** wm, int wiimotes) { int i; if (!wm) { return 0; } for (i = 0; i < wiimotes; i++) { if (wm[i] && WIIMOTE_IS_CONNECTED(wm[i])) { return 1; } } return 0; }
void wiiuse_send_next_command(struct wiimote_t *wm) { struct cmd_blk_t *cmd = wm->cmd_head; if(!wm || !WIIMOTE_IS_CONNECTED(wm)) return; if(!cmd) return; if(cmd->state!=CMD_READY) return; cmd->state = CMD_SENT; if(WIIMOTE_IS_SET(wm,WIIMOTE_STATE_RUMBLE)) cmd->data[1] |= 0x01; wiiuse_io_write(wm,cmd->data,cmd->len); }
void wiiuse_disconnect(struct wiimote_t* wm) { if (!wm || WIIMOTE_IS_CONNECTED(wm)) return; CloseHandle(wm->dev_handle); wm->dev_handle = 0; ResetEvent(&wm->hid_overlap); wm->event = WIIUSE_NONE; WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_CONNECTED); WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_HANDSHAKE); }
bool FWiimoteInputDevice::AnyWiimoteConnected() const { if (!GWiimotes) { return false; } for (int i = 0; i < MAX_WIIMOTES; i++) { if (GWiimotes[i] && WIIMOTE_IS_CONNECTED(GWiimotes[i])) { return true; } } return false; }
/** * @brief Read data from the wiimote (callback version). * * @param wm Pointer to a wiimote_t structure. * @param read_cb Function pointer to call when the data arrives from the wiimote. * @param buffer An allocated buffer to store the data as it arrives from the wiimote. * Must be persistent in memory and large enough to hold the data. * @param addr The address of wiimote memory to read from. * @param len The length of the block to be read. * * The library can only handle one data read request at a time * because it must keep track of the buffer and other * events that are specific to that request. So if a request * has already been made, subsequent requests will be added * to a pending list and be sent out when the previous * finishes. */ int wiiuse_read_data_cb(struct wiimote_t* wm, wiiuse_read_cb read_cb, byte* buffer, unsigned int addr, uint16_t len) { struct read_req_t* req; if (!wm || !WIIMOTE_IS_CONNECTED(wm)) { return 0; } if (!buffer || !len) { return 0; } /* make this request structure */ req = (struct read_req_t*)malloc(sizeof(struct read_req_t)); if (req == NULL) { return 0; } req->cb = read_cb; req->buf = buffer; req->addr = addr; req->size = len; req->wait = len; req->dirty = 0; req->next = NULL; /* add this to the request list */ if (!wm->read_req) { /* root node */ wm->read_req = req; WIIUSE_DEBUG("Data read request can be sent out immediately."); /* send the request out immediately */ wiiuse_send_next_pending_read_request(wm); } else { struct read_req_t* nptr = wm->read_req; for (; nptr->next; nptr = nptr->next) { ; } nptr->next = req; WIIUSE_DEBUG("Added pending data read request."); } return 1; }
/** * @brief Set the enabled LEDs. * * @param wm Pointer to a wiimote_t structure. * @param leds What LEDs to enable. * * \a leds is a bitwise or of WIIMOTE_LED_1, WIIMOTE_LED_2, WIIMOTE_LED_3, or WIIMOTE_LED_4. */ void wiiuse_set_leds(struct wiimote_t* wm, int leds) { byte buf; if (!wm || !WIIMOTE_IS_CONNECTED(wm)) { return; } /* remove the lower 4 bits because they control rumble */ wm->leds = (leds & 0xF0); /* make sure if the rumble is on that we keep it on */ if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_RUMBLE)) { wm->leds |= 0x01; } buf = wm->leds; wiiuse_send(wm, WM_CMD_LED, &buf, 1); }
int wiiuse_write_streamdata(struct wiimote_t *wm,ubyte *data,ubyte len,cmd_blk_cb cb) { struct cmd_blk_t *cmd; if(!wm || !WIIMOTE_IS_CONNECTED(wm)) return 0; if(!data || !len || len>20) return 0; cmd = (struct cmd_blk_t*)__lwp_queue_get(&wm->cmdq); if(!cmd) return 0; cmd->cb = cb; cmd->len = 22; cmd->data[0] = WM_CMD_STREAM_DATA; cmd->data[1] = (len<<3); memcpy(cmd->data+2,data,len); __wiiuse_push_command(wm,cmd); return 1; }
/** * @brief Write data to the wiimote (callback version). * * @param wm Pointer to a wiimote_t structure. * @param addr The address to write to. * @param data The data to be written to the memory location. * @param len The length of the block to be written. * @param cb Function pointer to call when the data arrives from the wiimote. * * The library can only handle one data read request at a time * because it must keep track of the buffer and other * events that are specific to that request. So if a request * has already been made, subsequent requests will be added * to a pending list and be sent out when the previous * finishes. */ int wiiuse_write_data_cb(struct wiimote_t *wm, unsigned int addr, byte *data, byte len, wiiuse_write_cb write_cb) { struct data_req_t* req; if (!wm || !WIIMOTE_IS_CONNECTED(wm)) { return 0; } if (!data || !len) { return 0; } req = (struct data_req_t*)malloc(sizeof(struct data_req_t)); req->cb = write_cb; req->len = len; memcpy(req->data, data, req->len); req->state = REQ_READY; req->addr = addr;/* BIG_ENDIAN_LONG(addr); */ req->next = NULL; /* add this to the request list */ if (!wm->data_req) { /* root node */ wm->data_req = req; WIIUSE_DEBUG("Data write request can be sent out immediately."); /* send the request out immediately */ wiiuse_send_next_pending_write_request(wm); } else { struct data_req_t* nptr = wm->data_req; WIIUSE_DEBUG("chaud2fois"); for (; nptr->next; nptr = nptr->next) { ; } nptr->next = req; WIIUSE_DEBUG("Added pending data write request."); } return 1; }
/** * @brief Send the next pending data write request to the wiimote. * * @param wm Pointer to a wiimote_t structure. * * @see wiiuse_write_data() * * This function is not part of the wiiuse API. */ void wiiuse_send_next_pending_write_request(struct wiimote_t* wm) { struct data_req_t* req; if (!wm || !WIIMOTE_IS_CONNECTED(wm)) { return; } req = wm->data_req; if (!req) { return; } if (!req->data || !req->len) { return; } if (req->state != REQ_READY) { return; } wiiuse_write_data(wm, req->addr, req->data, req->len); req->state = REQ_SENT; return; }
int wiiuse_io_read(struct wiimote_t* wm) { DWORD b, r; if (!wm || !WIIMOTE_IS_CONNECTED(wm)) return 0; if (!ReadFile(wm->dev_handle, wm->event_buf, sizeof(wm->event_buf), &b, &wm->hid_overlap)) { /* partial read */ b = GetLastError(); if ((b == ERROR_HANDLE_EOF) || (b == ERROR_DEVICE_NOT_CONNECTED)) { /* remote disconnect */ wiiuse_disconnected(wm); return 0; } r = WaitForSingleObject(wm->hid_overlap.hEvent, wm->timeout); if (r == WAIT_TIMEOUT) { /* timeout - cancel and continue */ if (*wm->event_buf) WIIUSE_WARNING("Packet ignored. This may indicate a problem (timeout is %i ms).", wm->timeout); CancelIo(wm->dev_handle); ResetEvent(wm->hid_overlap.hEvent); return 0; } else if (r == WAIT_FAILED) { WIIUSE_WARNING("A wait error occured on reading from wiimote %i.", wm->unid); return 0; } if (!GetOverlappedResult(wm->dev_handle, &wm->hid_overlap, &b, 0)) return 0; } ResetEvent(wm->hid_overlap.hEvent); return 1; }
/** * @brief Write data to the wiimote. * * @param wm Pointer to a wiimote_t structure. * @param addr The address to write to. * @param data The data to be written to the memory location. * @param len The length of the block to be written. */ int wiiuse_write_data(struct wiimote_t* wm, unsigned int addr, const byte* data, byte len) { byte buf[21] = {0}; /* the payload is always 23 */ byte * bufPtr = buf; if (!wm || !WIIMOTE_IS_CONNECTED(wm)) { WIIUSE_ERROR("Attempt to write, but no wiimote available or not connected!"); return 0; } if (!data || !len) { WIIUSE_ERROR("Attempt to write, but no data or length == 0"); return 0; } WIIUSE_DEBUG("Writing %i bytes to memory location 0x%x...", len, addr); #ifdef WITH_WIIUSE_DEBUG { int i = 0; printf("Write data is: "); for (; i < len; ++i) { printf("%x ", data[i]); } printf("\n"); } #endif /* the offset is in big endian */ buffer_big_endian_uint32_t(&bufPtr, (uint32_t)addr); /* length */ buffer_big_endian_uint8_t(&bufPtr, len); /* data */ memcpy(bufPtr, data, len); wiiuse_send(wm, WM_CMD_WRITE_DATA, buf, 21); return 1; }
int wiiuse_read_data(struct wiimote_t *wm,ubyte *buffer,uint addr,uword len,cmd_blk_cb cb) { struct op_t *op; struct cmd_blk_t *cmd; if(!wm || !WIIMOTE_IS_CONNECTED(wm)) return 0; if(!buffer || !len) return 0; cmd = (struct cmd_blk_t*)__lwp_queue_get(&wm->cmdq); if(!cmd) return 0; cmd->cb = cb; cmd->len = 7; op = (struct op_t*)cmd->data; op->cmd = WM_CMD_READ_DATA; op->buffer = buffer; op->wait = len; op->readdata.addr = BIG_ENDIAN_LONG(addr); op->readdata.size = BIG_ENDIAN_SHORT(len); __wiiuse_push_command(wm,cmd); return 1; }
int wiiuse_os_poll(struct wiimote_t** wm, int wiimotes) { int evnt; struct timeval tv; fd_set fds; int r; int i; byte read_buffer[MAX_PAYLOAD]; int highest_fd = -1; evnt = 0; if (!wm) { return 0; } /* block select() for 1/2000th of a second */ tv.tv_sec = 0; tv.tv_usec = 500; FD_ZERO(&fds); for (i = 0; i < wiimotes; ++i) { /* only poll it if it is connected */ if (WIIMOTE_IS_SET(wm[i], WIIMOTE_STATE_CONNECTED)) { FD_SET(wm[i]->in_sock, &fds); /* find the highest fd of the connected wiimotes */ if (wm[i]->in_sock > highest_fd) { highest_fd = wm[i]->in_sock; } } wm[i]->event = WIIUSE_NONE; } if (highest_fd == -1) /* nothing to poll */ { return 0; } if (select(highest_fd + 1, &fds, NULL, NULL, &tv) == -1) { WIIUSE_ERROR("Unable to select() the wiimote interrupt socket(s)."); perror("Error Details"); return 0; } /* check each socket for an event */ for (i = 0; i < wiimotes; ++i) { /* if this wiimote is not connected, skip it */ if (!WIIMOTE_IS_CONNECTED(wm[i])) { continue; } if (FD_ISSET(wm[i]->in_sock, &fds)) { /* clear out the event buffer */ memset(read_buffer, 0, sizeof(read_buffer)); /* clear out any old read data */ clear_dirty_reads(wm[i]); /* read the pending message into the buffer */ r = wiiuse_os_read(wm[i], read_buffer, sizeof(read_buffer)); if (r > 0) { /* propagate the event */ propagate_event(wm[i], read_buffer[0], read_buffer + 1); evnt += (wm[i]->event != WIIUSE_NONE); } } else { /* send out any waiting writes */ wiiuse_send_next_pending_write_request(wm[i]); idle_cycle(wm[i]); } } return evnt; }
/** * @brief Connect to a wiimote with a known address. * * @param wm Pointer to a wiimote_t structure. * @param address The address of the device to connect to. * If NULL, use the address in the struct set by wiiuse_find(). * * @return 1 on success, 0 on failure */ static int wiiuse_connect_single(struct wiimote_t* wm, char* address) { struct sockaddr_l2 addr={0} ; //char dest[18]="00:25:A0:B0:96:8A" ; if (!wm || WIIMOTE_IS_CONNECTED(wm)) return 0; wm->out_sock = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP); if (wm->out_sock == -1) return 0; addr.l2_family = AF_BLUETOOTH; addr.l2_psm = htobs(WM_OUTPUT_CHANNEL); // =0x11, le port -> Wiimote. //str2ba(dest, &addr.l2_bdaddr) ; if( address ) // Use provided address. str2ba(address, &addr.l2_bdaddr) ; else // Use address of device discovered. str2ba(wm->bdaddr_str, &addr.l2_bdaddr) ; /* * OUTPUT CHANNEL */ /* connect to wiimote */ if( connect(wm->out_sock, (struct sockaddr*)&addr, sizeof(addr)) < 0 ) { perror("connect() output sock"); return 0; } /* * INPUT CHANNEL */ wm->in_sock = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP); if (wm->in_sock == -1) { close(wm->out_sock); wm->out_sock = -1; return 0; } addr.l2_psm = htobs(WM_INPUT_CHANNEL); /* connect to wiimote */ if ( connect(wm->in_sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) { perror("connect() interrupt sock"); close(wm->out_sock); wm->out_sock = -1; return 0; } WIIUSE_INFO("Connected to wiimote [id %i].", wm->unid); /* do the handshake */ WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_CONNECTED); wiiuse_handshake(wm, NULL, 0); wiiuse_set_report_type(wm); return 1; }
void FWiimoteInputDevice::SendControllerEvents() { /* * Maybe I'm interested in the battery power of the 0th * wiimote. This should be WIIMOTE_ID_1 but to be sure * you can get the wiimote associated with WIIMOTE_ID_1 * using the wiiuse_get_by_id() function. * * A status request will return other things too, like * if any expansions are plugged into the wiimote or * what LEDs are lit. */ /* wiiuse_status(wiimotes[0]); */ /* * This is the main loop * * wiiuse_poll() needs to be called with the wiimote array * and the number of wiimote structures in that array * (it doesn't matter if some of those wiimotes are not used * or are not connected). * * This function will set the event flag for each wiimote * when the wiimote has things to report. */ if (AnyWiimoteConnected()) { if (wiiuse_poll(GWiimotes, MAX_WIIMOTES)) { /* * This happens if something happened on any wiimote. * So go through each one and check if anything happened. */ const double CurrentTime = FPlatformTime::Seconds(); for (int i = 0; i < MAX_WIIMOTES; ++i) { FControllerState& ControllerState = ControllerStates[i]; ControllerState.Wiimote = GWiimotes[i]; if (ControllerState.Wiimote && WIIMOTE_IS_CONNECTED(ControllerState.Wiimote)) { // Check Analog state if (ControllerState.Wiimote->exp.type == EXP_NUNCHUK || ControllerState.Wiimote->exp.type == EXP_MOTION_PLUS_NUNCHUK) { /* nunchuk */ struct nunchuk_t* nc = (nunchuk_t*)&ControllerState.Wiimote->exp.nunchuk; if (ControllerState.LeftXAnalog != nc->js.x) { MessageHandler->OnControllerAnalog(FGamepadKeyNames::LeftAnalogX, ControllerState.ControllerId, nc->js.x); ControllerState.LeftXAnalog = nc->js.x; } if (ControllerState.LeftYAnalog != nc->js.y) { MessageHandler->OnControllerAnalog(FGamepadKeyNames::LeftAnalogY, ControllerState.ControllerId, nc->js.y); ControllerState.LeftYAnalog = nc->js.y; } } } FMemory::Memzero(CurrentStates); switch (ControllerState.Wiimote->event) { case WIIUSE_EVENT: /* a generic event occurred */ handle_event(ControllerState.Wiimote, i); break; case WIIUSE_STATUS: /* a status event occurred */ handle_ctrl_status(ControllerState.Wiimote, i); break; case WIIUSE_DISCONNECT: case WIIUSE_UNEXPECTED_DISCONNECT: /* the wiimote disconnected */ handle_disconnect(ControllerState.Wiimote, i); break; case WIIUSE_READ_DATA: /* * Data we requested to read was returned. * Take a look at ControllerState.Wiimote>read_req * for the data. */ break; case WIIUSE_NUNCHUK_INSERTED: /* * a nunchuk was inserted * This is a good place to set any nunchuk specific * threshold values. By default they are the same * as the wiimote. */ /* wiiuse_set_nunchuk_orient_threshold((struct nunchuk_t*)&wiimotes[i]->exp.nunchuk, 90.0f); */ /* wiiuse_set_nunchuk_accel_threshold((struct nunchuk_t*)&wiimotes[i]->exp.nunchuk, 100); */ UE_LOG(LogWiimote, Log, TEXT("Nunchuk inserted.")); break; case WIIUSE_MOTION_PLUS_ACTIVATED: UE_LOG(LogWiimote, Log, TEXT("Motion+ was activated")); break; case WIIUSE_NUNCHUK_REMOVED: case WIIUSE_MOTION_PLUS_REMOVED: /* some expansion was removed */ handle_ctrl_status(ControllerState.Wiimote, i); UE_LOG(LogWiimote, Log, TEXT("An expansion was removed.")); break; default: break; } // For each button check against the previous state and send the correct message if any for (int32 ButtonIndex = 0; ButtonIndex < MAX_NUM_WIIMOTE_BUTTONS; ++ButtonIndex) { if (CurrentStates[ButtonIndex] != ControllerState.ButtonStates[ButtonIndex]) { if (CurrentStates[ButtonIndex]) { MessageHandler->OnControllerButtonPressed(Buttons[ButtonIndex], ControllerState.ControllerId, false); } else { MessageHandler->OnControllerButtonReleased(Buttons[ButtonIndex], ControllerState.ControllerId, false); } if (CurrentStates[ButtonIndex] != 0) { // this button was pressed - set the button's NextRepeatTime to the InitialButtonRepeatDelay ControllerState.NextRepeatTime[ButtonIndex] = CurrentTime + InitialButtonRepeatDelay; } } else if (CurrentStates[ButtonIndex] != 0 && ControllerState.NextRepeatTime[ButtonIndex] <= CurrentTime) { MessageHandler->OnControllerButtonPressed(Buttons[ButtonIndex], ControllerState.ControllerId, true); // set the button's NextRepeatTime to the ButtonRepeatDelay ControllerState.NextRepeatTime[ButtonIndex] = CurrentTime + ButtonRepeatDelay; } // Update the state for next time ControllerState.ButtonStates[ButtonIndex] = CurrentStates[ButtonIndex]; } } } } }
/** * @brief Connect to a wiimote with a known address. * * @param wm Pointer to a wiimote_t structure. * @param address The address of the device to connect to. * If NULL, use the address in the struct set by wiic_find(). * * @return 1 on success, 0 on failure */ static int wiic_connect_single(struct wiimote_t* wm, char* address) { struct sockaddr_l2 addr; memset(&addr, 0, sizeof(addr)); if (!wm || WIIMOTE_IS_CONNECTED(wm)) return 0; addr.l2_family = AF_BLUETOOTH; if (address) /* use provided address */ str2ba(address, &addr.l2_bdaddr); else /* use address of device discovered */ addr.l2_bdaddr = wm->bdaddr; /* * OUTPUT CHANNEL */ wm->out_sock = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP); if (wm->out_sock == -1) return 0; addr.l2_psm = htobs(WM_OUTPUT_CHANNEL); /* connect to wiimote */ if (connect(wm->out_sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) { perror("connect() output sock"); return 0; } /* * INPUT CHANNEL */ wm->in_sock = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP); if (wm->in_sock == -1) { close(wm->out_sock); wm->out_sock = -1; return 0; } addr.l2_psm = htobs(WM_INPUT_CHANNEL); /* connect to wiimote */ if (connect(wm->in_sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) { perror("connect() interrupt sock"); close(wm->out_sock); wm->out_sock = -1; return 0; } WIIC_INFO("Connected to wiimote [id %i].", wm->unid); /* do the handshake */ WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_CONNECTED); wiic_handshake(wm, NULL, 0); wiic_set_report_type(wm); return 1; }
/** * Launch wiimote detection and add the corresponding gamepad devices to the * device manager. * TODO: this should be done in a separate thread, to not block the UI... */ void WiimoteManager::launchDetection(int timeout) { // It's only needed on systems with bluez, because wiiuse_find does not find alredy connected wiimotes #ifdef WIIUSE_BLUEZ //Cleans up the config and the disconnected wiimotes int number_previous_wiimotes = 0; wiimote_t** previous_wiimotes = (wiimote_t**) malloc(sizeof(struct wiimote_t*) * MAX_WIIMOTES); memset(previous_wiimotes,0,sizeof(struct wiimote_t*) * MAX_WIIMOTES); for (unsigned int i = 0; i < m_wiimotes.size(); i++) { if (WIIMOTE_IS_CONNECTED(m_all_wiimote_handles[i])) { previous_wiimotes[i]=m_all_wiimote_handles[i]; m_all_wiimote_handles[i] = NULL; number_previous_wiimotes++; } } //To prevent segmentation fault, have to delete NULLs wiimote_t** deletable_wiimotes = (wiimote_t**) malloc(sizeof(struct wiimote_t*) * (m_wiimotes.size()-number_previous_wiimotes)); memset(deletable_wiimotes,0,sizeof(struct wiimote_t*) * (m_wiimotes.size()-number_previous_wiimotes)); int number_deletables = 0; for (unsigned int i = 0; i < m_wiimotes.size(); i++) { if (m_all_wiimote_handles[i] != NULL) { deletable_wiimotes[number_deletables++] = m_all_wiimote_handles[i]; } } m_all_wiimote_handles = wiiuse_init(MAX_WIIMOTES); wiiuse_cleanup(deletable_wiimotes, number_deletables); #endif // Stop WiiUse, remove wiimotes, gamepads, gamepad configs. cleanup(); m_all_wiimote_handles = wiiuse_init(MAX_WIIMOTES); // Detect wiimotes int nb_found_wiimotes = wiiuse_find(m_all_wiimote_handles, MAX_WIIMOTES, timeout); #ifndef WIIUSE_BLUEZ // Couldn't find any wiimote? if(nb_found_wiimotes == 0) return; #endif #ifdef WIIUSE_BLUEZ // Couldn't find any wiimote? if(nb_found_wiimotes + number_previous_wiimotes == 0) return; #endif // Try to connect to all found wiimotes int nb_wiimotes = wiiuse_connect(m_all_wiimote_handles, nb_found_wiimotes); #ifndef WIIUSE_BLUEZ // Couldn't connect to any wiimote? if(nb_wiimotes == 0) return; #endif #ifdef WIIUSE_BLUEZ // Couldn't connect to any wiimote? if(nb_wiimotes + number_previous_wiimotes == 0) return; //Merges previous and new wiimote's list int number_merged_wiimotes = 0; for (int i = 0; i < number_previous_wiimotes && i + nb_wiimotes < MAX_WIIMOTES; i++) { m_all_wiimote_handles[i+nb_wiimotes] = previous_wiimotes[i]; previous_wiimotes[i] = NULL; m_all_wiimote_handles[i]->unid = nb_wiimotes+i+1; number_merged_wiimotes++; } nb_wiimotes += number_merged_wiimotes; //To prevent segmentation fault, have to delete NULLs number_deletables = 0; deletable_wiimotes = (wiimote_t**) malloc(sizeof(struct wiimote_t*) * (number_previous_wiimotes-number_merged_wiimotes)); memset(deletable_wiimotes,0,sizeof(struct wiimote_t*) * (number_previous_wiimotes-number_merged_wiimotes)); for (int i = 0; i < number_previous_wiimotes; i++) { if (previous_wiimotes[i] != NULL) { deletable_wiimotes[number_deletables++] = previous_wiimotes[i]; } } // Cleans up wiimotes which ones didn't fit in limit wiiuse_cleanup(deletable_wiimotes, number_deletables); #endif // --------------------------------------------------- // Create or find a GamepadConfig for all wiimotes DeviceManager* device_manager = input_manager->getDeviceManager(); GamepadConfig* gamepad_config = NULL; device_manager->getConfigForGamepad(WIIMOTE_START_IRR_ID, "Wiimote", &gamepad_config); int num_buttons = (int)( log((float)WIIMOTE_BUTTON_ALL) / log((float)2.0f))+1; gamepad_config->setNumberOfButtons(num_buttons); gamepad_config->setNumberOfAxis(1); setWiimoteBindings(gamepad_config); // Initialize all Wiimotes, which in turn create their // associated GamePadDevices for(int i=0 ; i < nb_wiimotes ; i++) { m_wiimotes.push_back(new Wiimote(m_all_wiimote_handles[i], i, gamepad_config )); } // end for // --------------------------------------------------- // Set the LEDs and rumble for 0.2s int leds[] = {WIIMOTE_LED_1, WIIMOTE_LED_2, WIIMOTE_LED_3, WIIMOTE_LED_4}; for(unsigned int i=0 ; i < m_wiimotes.size(); i++) { wiimote_t* wiimote_handle = m_wiimotes[i]->getWiimoteHandle(); wiiuse_set_leds(wiimote_handle, leds[i]); wiiuse_rumble(wiimote_handle, 1); } StkTime::sleep(200); for(unsigned int i=0 ; i < m_wiimotes.size(); i++) { wiimote_t* wiimote_handle = m_wiimotes[i]->getWiimoteHandle(); wiiuse_rumble(wiimote_handle, 0); } // TODO: only enable accelerometer during race enableAccelerometer(true); // --------------------------------------------------- // Launch the update thread #ifdef WIIMOTE_THREADING m_shut = false; pthread_create(&m_thread, NULL, &threadFuncWrapper, this); #endif } // launchDetection