/** * @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_handshake(struct wiimote_t* wm, byte* data, uint16_t len) { /* send request to wiimote for accelerometer calibration */ byte buf[MAX_PAYLOAD]; /* step 0 - Reset wiimote */ { //wiiuse_set_leds(wm, WIIMOTE_LED_NONE); WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_HANDSHAKE); WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_CONNECTED); WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_ACC); WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_IR); WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_RUMBLE); WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_EXP); WIIMOTE_DISABLE_FLAG(wm, WIIUSE_CONTINUOUS); wiiuse_set_report_type(wm); wiiuse_millisleep(500); WIIUSE_DEBUG("Wiimote reset!\n"); } /* step 1 - calibration of accelerometers */ if(wm->type != WIIUSE_WIIMOTE_MOTION_PLUS_INSIDE) { struct accel_t* accel = &wm->accel_calib; wiiuse_read_data_sync(wm, 1, WM_MEM_OFFSET_CALIBRATION, 8, buf); /* received read data */ accel->cal_zero.x = buf[0]; accel->cal_zero.y = buf[1]; accel->cal_zero.z = buf[2]; accel->cal_g.x = buf[4] - accel->cal_zero.x; accel->cal_g.y = buf[5] - accel->cal_zero.y; accel->cal_g.z = buf[6] - accel->cal_zero.z; WIIUSE_DEBUG("Calibrated wiimote acc\n"); } /* step 2 - re-enable IR and ask for status */ { WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_HANDSHAKE_COMPLETE); WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_HANDSHAKE); /* now enable IR if it was set before the handshake completed */ if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR)) { WIIUSE_DEBUG("Handshake finished, enabling IR."); WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_IR); wiiuse_set_ir(wm, 1); } WIIUSE_DEBUG("Asking for status ...\n"); wm->event = WIIUSE_CONNECT; wiiuse_status(wm); } }
/** * @brief Handle the handshake data from the wiiboard. * * @param wb A pointer to a wii_board_t structure. * @param data The data read in from the device. * @param len The length of the data block, in bytes. * * @return Returns 1 if handshake was successful, 0 if not. */ int wii_board_handshake(struct wiimote_t* wm, struct wii_board_t* wb, ubyte* data, uword len) { int offset = 0; if (data[offset]==0xff) { if (data[offset+16]==0xff) { WIIUSE_DEBUG("Wii Balance Board handshake appears invalid, trying again."); wiiuse_read_data(wm, data, WM_EXP_MEM_CALIBR, EXP_HANDSHAKE_LEN, wiiuse_handshake_expansion); return 0; } offset += 16; } wb->ctr[0] = (data[offset+4]<<8)|data[offset+5]; wb->cbr[0] = (data[offset+6]<<8)|data[offset+7]; wb->ctl[0] = (data[offset+8]<<8)|data[offset+9]; wb->cbl[0] = (data[offset+10]<<8)|data[offset+11]; wb->ctr[1] = (data[offset+12]<<8)|data[offset+13]; wb->cbr[1] = (data[offset+14]<<8)|data[offset+15]; wb->ctl[1] = (data[offset+16]<<8)|data[offset+17]; wb->cbl[1] = (data[offset+18]<<8)|data[offset+19]; wb->ctr[2] = (data[offset+20]<<8)|data[offset+21]; wb->cbr[2] = (data[offset+22]<<8)|data[offset+23]; wb->ctl[2] = (data[offset+24]<<8)|data[offset+25]; wb->cbl[2] = (data[offset+26]<<8)|data[offset+27]; /* handshake done */ wm->event = WIIUSE_WII_BOARD_INSERTED; wm->exp.type = EXP_WII_BOARD; 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_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]; }
/** * @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 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]; }
/** * @brief Wait until specified report arrives and return it * * @param wm Pointer to a wiimote_t structure. * @param buffer Pre-allocated memory to store the received data * @param bufferLength size of buffer in bytes * * Synchronous/blocking, this function will not return until it receives the specified * report from the Wiimote. * */ void wiiuse_wait_report(struct wiimote_t *wm, int report, byte *buffer, int bufferLength) { for (;;) { if (wiiuse_os_read(wm, buffer, bufferLength) > 0) { if (buffer[0] == report) { break; } else { WIIUSE_DEBUG("(id %i) dropping report 0x%x, waiting for 0x%x", wm->unid, buffer[0], report); } } } }
/** * @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 Set the IR sensitivity. * * @param wm Pointer to a wiimote_t structure. * @param level 1-5, same as Wii system sensitivity setting. * * If the level is < 1, then level will be set to 1. * If the level is > 5, then level will be set to 5. */ void wiiuse_set_ir_sensitivity(struct wiimote_t* wm, int level) { char* block1 = NULL; char* block2 = NULL; if (!wm) return; if (level > 5) level = 5; if (level < 1) level = 1; WIIMOTE_DISABLE_STATE(wm, (WIIMOTE_STATE_IR_SENS_LVL1 | WIIMOTE_STATE_IR_SENS_LVL2 | WIIMOTE_STATE_IR_SENS_LVL3 | WIIMOTE_STATE_IR_SENS_LVL4 | WIIMOTE_STATE_IR_SENS_LVL5)); switch (level) { case 1: WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_IR_SENS_LVL1); break; case 2: WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_IR_SENS_LVL2); break; case 3: WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_IR_SENS_LVL3); break; case 4: WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_IR_SENS_LVL4); break; case 5: WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_IR_SENS_LVL5); break; default: return; } /* set the new sensitivity */ get_ir_sens(wm, &block1, &block2); wiiuse_write_data(wm, WM_REG_IR_BLOCK1, (byte*)block1, 9); wiiuse_write_data(wm, WM_REG_IR_BLOCK2, (byte*)block2, 2); WIIUSE_DEBUG("Set IR sensitivity to level %i (unid %i)", level, wm->unid); }
/** * @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; }
/** * @brief Set if the wiimote should track IR targets. * * @param wm Pointer to a wiimote_t structure. * @param status 1 to enable, 0 to disable. */ void wiiuse_set_ir(struct wiimote_t* wm, int status) { byte buf; char* block1 = NULL; char* block2 = NULL; int ir_level; if (!wm) return; /* * Wait for the handshake to finish first. * When it handshake finishes and sees that * IR is enabled, it will call this function * again to actually enable IR. */ if (!WIIMOTE_IS_SET(wm, WIIMOTE_STATE_HANDSHAKE_COMPLETE)) { if(status) { WIIUSE_DEBUG("Tried to enable IR, will wait until handshake finishes."); WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_IR); } // else ignoring request to turn off, since it's turned off by default return; } /* * Check to make sure a sensitivity setting is selected. */ ir_level = get_ir_sens(wm, &block1, &block2); if (!ir_level) { WIIUSE_ERROR("No IR sensitivity setting selected."); return; } if (status) { /* if already enabled then stop */ if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR)) return; WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_IR); } else { /* if already disabled then stop */ if (!WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR)) return; WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_IR); } /* set camera 1 and 2 */ buf = (status ? 0x04 : 0x00); wiiuse_send(wm, WM_CMD_IR, &buf, 1); wiiuse_send(wm, WM_CMD_IR_2, &buf, 1); if (!status) { WIIUSE_DEBUG("Disabled IR cameras for wiimote id %i.", wm->unid); wiiuse_set_report_type(wm); return; } /* enable IR, set sensitivity */ buf = 0x08; wiiuse_write_data(wm, WM_REG_IR, &buf, 1); /* wait for the wiimote to catch up */ #ifndef WIN32 usleep(50000); #else Sleep(50); #endif /* write sensitivity blocks */ wiiuse_write_data(wm, WM_REG_IR_BLOCK1, (byte*)block1, 9); wiiuse_write_data(wm, WM_REG_IR_BLOCK2, (byte*)block2, 2); /* set the IR mode */ if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_EXP)) buf = WM_IR_TYPE_BASIC; else buf = WM_IR_TYPE_EXTENDED; wiiuse_write_data(wm, WM_REG_IR_MODENUM, &buf, 1); #ifndef WIN32 usleep(50000); #else Sleep(50); #endif /* set the wiimote report type */ wiiuse_set_report_type(wm); WIIUSE_DEBUG("Enabled IR camera for wiimote id %i (sensitivity level %i).", wm->unid, ir_level); }
/** * @brief Interpret IR data into more user friendly variables. * * @param wm Pointer to a wiimote_t structure. */ static void interpret_ir_data(struct wiimote_t* wm) { struct ir_dot_t* dot = wm->ir.dot; int i; float roll = 0.0f; int last_num_dots = wm->ir.num_dots; if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_ACC)) roll = wm->orient.roll; /* count visible dots */ wm->ir.num_dots = 0; for (i = 0; i < 4; ++i) { if (dot[i].visible) wm->ir.num_dots++; } switch (wm->ir.num_dots) { case 0: { wm->ir.state = 0; /* reset the dot ordering */ for (i = 0; i < 4; ++i) dot[i].order = 0; wm->ir.x = 0; wm->ir.y = 0; wm->ir.z = 0.0f; return; } case 1: { fix_rotated_ir_dots(wm->ir.dot, roll); if (wm->ir.state < 2) { /* * Only 1 known dot, so use just that. */ for (i = 0; i < 4; ++i) { if (dot[i].visible) { wm->ir.x = dot[i].x; wm->ir.y = dot[i].y; wm->ir.ax = wm->ir.x; wm->ir.ay = wm->ir.y; /* can't calculate yaw because we don't have the distance */ //wm->orient.yaw = calc_yaw(&wm->ir); ir_convert_to_vres(&wm->ir.x, &wm->ir.y, wm->ir.aspect, wm->ir.vres[0], wm->ir.vres[1]); break; } } } else { /* * Only see 1 dot but know theres 2. * Try to estimate where the other one * should be and use that. */ for (i = 0; i < 4; ++i) { if (dot[i].visible) { int ox = 0; int x, y; if (dot[i].order == 1) /* visible is the left dot - estimate where the right is */ ox = dot[i].x + wm->ir.distance; else if (dot[i].order == 2) /* visible is the right dot - estimate where the left is */ ox = dot[i].x - wm->ir.distance; x = ((signed int)dot[i].x + ox) / 2; y = dot[i].y; wm->ir.ax = x; wm->ir.ay = y; wm->orient.yaw = calc_yaw(&wm->ir); if (ir_correct_for_bounds(&x, &y, wm->ir.aspect, wm->ir.offset[0], wm->ir.offset[1])) { ir_convert_to_vres(&x, &y, wm->ir.aspect, wm->ir.vres[0], wm->ir.vres[1]); wm->ir.x = x; wm->ir.y = y; } break; } } } break; } case 2: case 3: case 4: { /* * Two (or more) dots known and seen. * Average them together to estimate the true location. */ int x, y; wm->ir.state = 2; fix_rotated_ir_dots(wm->ir.dot, roll); /* if there is at least 1 new dot, reorder them all */ if (wm->ir.num_dots > last_num_dots) { reorder_ir_dots(dot); wm->ir.x = 0; wm->ir.y = 0; } wm->ir.distance = ir_distance(dot); wm->ir.z = 1023 - wm->ir.distance; get_ir_dot_avg(wm->ir.dot, &x, &y); wm->ir.ax = x; wm->ir.ay = y; wm->orient.yaw = calc_yaw(&wm->ir); if (ir_correct_for_bounds(&x, &y, wm->ir.aspect, wm->ir.offset[0], wm->ir.offset[1])) { ir_convert_to_vres(&x, &y, wm->ir.aspect, wm->ir.vres[0], wm->ir.vres[1]); wm->ir.x = x; wm->ir.y = y; } break; } default: { break; } } #ifdef WITH_WIIUSE_DEBUG { int ir_level; WIIUSE_GET_IR_SENSITIVITY(wm, &ir_level); WIIUSE_DEBUG("IR sensitivity: %i", ir_level); WIIUSE_DEBUG("IR visible dots: %i", wm->ir.num_dots); for (i = 0; i < 4; ++i) if (dot[i].visible) WIIUSE_DEBUG("IR[%i][order %i] (%.3i, %.3i) -> (%.3i, %.3i)", i, dot[i].order, dot[i].rx, dot[i].ry, dot[i].x, dot[i].y); WIIUSE_DEBUG("IR[absolute]: (%i, %i)", wm->ir.x, wm->ir.y); } #endif }
void wiiuse_handshake(struct wiimote_t* wm, byte* data, uint16_t len) { if (!wm) { return; } switch (wm->handshake_state) { case 0: { byte* buf; /* continuous reporting off, report to buttons only */ WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_HANDSHAKE); wiiuse_set_leds(wm, WIIMOTE_LED_NONE); WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_ACC); WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_IR); WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_RUMBLE); WIIMOTE_DISABLE_FLAG(wm, WIIUSE_CONTINUOUS); wiiuse_set_report_type(wm); /* send request to wiimote for accelerometer calibration */ buf = (byte*)malloc(sizeof(byte) * 8); wiiuse_read_data_cb(wm, wiiuse_handshake, buf, WM_MEM_OFFSET_CALIBRATION, 7); wm->handshake_state++; wiiuse_set_leds(wm, WIIMOTE_LED_NONE); break; } case 1: { struct read_req_t* req = wm->read_req; struct accel_t* accel = &wm->accel_calib; byte val; /* received read data */ accel->cal_zero.x = req->buf[0]; accel->cal_zero.y = req->buf[1]; accel->cal_zero.z = req->buf[2]; accel->cal_g.x = req->buf[4] - accel->cal_zero.x; accel->cal_g.y = req->buf[5] - accel->cal_zero.y; accel->cal_g.z = req->buf[6] - accel->cal_zero.z; /* done with the buffer */ free(req->buf); /* handshake is done */ WIIUSE_DEBUG("Handshake finished. Calibration: Idle: X=%x Y=%x Z=%x\t+1g: X=%x Y=%x Z=%x", accel->cal_zero.x, accel->cal_zero.y, accel->cal_zero.z, accel->cal_g.x, accel->cal_g.y, accel->cal_g.z); /* M+ off */ val = 0x55; wiiuse_write_data_cb(wm, WM_EXP_MEM_ENABLE1, &val, 1, wiiuse_disable_motion_plus1); break; } case 2: { /* request the status of the wiimote to check for any expansion */ WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_HANDSHAKE); WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_HANDSHAKE_COMPLETE); wm->handshake_state++; /* now enable IR if it was set before the handshake completed */ if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR)) { WIIUSE_DEBUG("Handshake finished, enabling IR."); WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_IR); wiiuse_set_ir(wm, 1); } wm->event = WIIUSE_CONNECT; wiiuse_status(wm); break; } default: { break; } } }
/** * @brief Handle the handshake data from the nunchuk. * * @param nc A pointer to a nunchuk_t structure. * @param data The data read in from the device. * @param len The length of the data block, in bytes. * * @return Returns 1 if handshake was successful, 0 if not. */ int nunchuk_handshake(struct wiimote_t* wm, struct nunchuk_t* nc, byte* data, unsigned short len) { int i; int offset = 0; nc->btns = 0; nc->btns_held = 0; nc->btns_released = 0; /* set the smoothing to the same as the wiimote */ nc->flags = &wm->flags; nc->accel_calib.st_alpha = wm->accel_calib.st_alpha; /* decrypt data */ for (i = 0; i < len; ++i) data[i] = (data[i] ^ 0x17) + 0x17; if (data[offset] == 0xFF) { /* * Sometimes the data returned here is not correct. * This might happen because the wiimote is lagging * behind our initialization sequence. * To fix this just request the handshake again. * * Other times it's just the first 16 bytes are 0xFF, * but since the next 16 bytes are the same, just use * those. */ if (data[offset + 16] == 0xFF) { /* get the calibration data */ byte* handshake_buf = malloc(EXP_HANDSHAKE_LEN * sizeof(byte)); WIIUSE_DEBUG("Nunchuk handshake appears invalid, trying again."); wiiuse_read_data_cb(wm, handshake_expansion, handshake_buf, WM_EXP_MEM_CALIBR, EXP_HANDSHAKE_LEN); return 0; } else offset += 16; } nc->accel_calib.cal_zero.x = data[offset + 0]; nc->accel_calib.cal_zero.y = data[offset + 1]; nc->accel_calib.cal_zero.z = data[offset + 2]; nc->accel_calib.cal_g.x = data[offset + 4]; nc->accel_calib.cal_g.y = data[offset + 5]; nc->accel_calib.cal_g.z = data[offset + 6]; nc->js.max.x = data[offset + 8]; nc->js.min.x = data[offset + 9]; nc->js.center.x = data[offset + 10]; nc->js.max.y = data[offset + 11]; nc->js.min.y = data[offset + 12]; nc->js.center.y = data[offset + 13]; /* default the thresholds to the same as the wiimote */ nc->orient_threshold = wm->orient_threshold; nc->accel_threshold = wm->accel_threshold; /* handshake done */ wm->exp.type = EXP_NUNCHUK; #ifdef WIN32 wm->timeout = WIIMOTE_DEFAULT_TIMEOUT; #endif return 1; }
void motion_plus_disconnected(struct motion_plus_t* mp) { WIIUSE_DEBUG("Motion plus disconnected"); memset(mp, 0, sizeof(struct motion_plus_t)); }
/** * @brief Get initialization data from the wiimote. * * @param wm Pointer to a wiimote_t structure. * @param data unused * @param len unused * * When first called for a wiimote_t structure, a request * is sent to the wiimote for initialization information. * This includes factory set accelerometer data. * The handshake will be concluded when the wiimote responds * with this data. */ void wiiuse_handshake(struct wiimote_t* wm, byte* data, uint16_t len) { if (!wm) return; switch (wm->handshake_state) { case 0: { /* send request to wiimote for accelerometer calibration */ byte* buf; WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_HANDSHAKE); wiiuse_set_leds(wm, WIIMOTE_LED_NONE); buf = (byte*)malloc(sizeof(byte) * 8); wiiuse_read_data_cb(wm, wiiuse_handshake, buf, WM_MEM_OFFSET_CALIBRATION, 7); wm->handshake_state++; wiiuse_set_leds(wm, WIIMOTE_LED_NONE); break; } case 1: { struct read_req_t* req = wm->read_req; struct accel_t* accel = &wm->accel_calib; /* received read data */ accel->cal_zero.x = req->buf[0]; accel->cal_zero.y = req->buf[1]; accel->cal_zero.z = req->buf[2]; accel->cal_g.x = req->buf[4] - accel->cal_zero.x; accel->cal_g.y = req->buf[5] - accel->cal_zero.y; accel->cal_g.z = req->buf[6] - accel->cal_zero.z; /* done with the buffer */ free(req->buf); /* handshake is done */ WIIUSE_DEBUG("Handshake finished. Calibration: Idle: X=%x Y=%x Z=%x\t+1g: X=%x Y=%x Z=%x", accel->cal_zero.x, accel->cal_zero.y, accel->cal_zero.z, accel->cal_g.x, accel->cal_g.y, accel->cal_g.z); /* request the status of the wiimote to see if there is an expansion */ wiiuse_status(wm); WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_HANDSHAKE); WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_HANDSHAKE_COMPLETE); wm->handshake_state++; /* now enable IR if it was set before the handshake completed */ if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR)) { WIIUSE_DEBUG("Handshake finished, enabling IR."); WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_IR); wiiuse_set_ir(wm, 1); } break; } default: { break; } } }