/** * @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); }
/** * @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); }
/** * @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 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); }
/** * @brief Read memory/register data synchronously * * @param wm Pointer to a wiimote_t structure. * @param memory If set to non-zero, reads EEPROM, otherwise registers * @param addr Address offset to read from * @param size How many bytes to read * @param data Pre-allocated memory to store the received data * * Synchronous/blocking read, this function will not return until it receives the specified * amount of data from the Wiimote. * */ void wiiuse_read_data_sync(struct wiimote_t *wm, byte memory, unsigned addr, unsigned short size, byte *data) { byte pkt[6]; byte buf[MAX_PAYLOAD]; unsigned n_full_reports; unsigned last_report; byte *output; unsigned int i; /* * address in big endian first, the leading byte will * be overwritten (only 3 bytes are sent) */ to_big_endian_uint32_t(pkt, addr); /* read from registers or memory */ pkt[0] = (memory != 0) ? 0x00 : 0x04; /* length in big endian */ to_big_endian_uint16_t(pkt + 4, size); /* send */ wiiuse_send(wm, WM_CMD_READ_DATA, pkt, sizeof(pkt)); /* calculate how many 16B packets we have to get back */ n_full_reports = size / 16; last_report = size % 16; output = data; for (i = 0; i < n_full_reports; ++i) { wiiuse_wait_report(wm, WM_RPT_READ, buf, MAX_PAYLOAD); memmove(output, buf + 6, 16); output += 16; } /* read the last incomplete packet */ if (last_report) { wiiuse_wait_report(wm, WM_RPT_READ, buf, MAX_PAYLOAD); memmove(output, buf + 6, last_report); } }
/** * @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); }