[9780] | 1 | /* |
---|
| 2 | * ir.c |
---|
| 3 | * |
---|
| 4 | * This file is part of WiiC, written by: |
---|
| 5 | * Gabriele Randelli |
---|
| 6 | * Email: randelli@dis.uniroma1.it |
---|
| 7 | * |
---|
| 8 | * Copyright 2010 |
---|
| 9 | * |
---|
| 10 | * This file is based on Wiiuse, written By: |
---|
| 11 | * Michael Laforest < para > |
---|
| 12 | * Email: < thepara (--AT--) g m a i l [--DOT--] com > |
---|
| 13 | * |
---|
| 14 | * Copyright 2006-2007 |
---|
| 15 | * |
---|
| 16 | * This program is free software; you can redistribute it and/or modify |
---|
| 17 | * it under the terms of the GNU General Public License as published by |
---|
| 18 | * the Free Software Foundation; either version 3 of the License, or |
---|
| 19 | * (at your option) any later version. |
---|
| 20 | * |
---|
| 21 | * This program is distributed in the hope that it will be useful, |
---|
| 22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
| 23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
| 24 | * GNU General Public License for more details. |
---|
| 25 | * |
---|
| 26 | * You should have received a copy of the GNU General Public License |
---|
| 27 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
---|
| 28 | * |
---|
| 29 | * $Header$ |
---|
| 30 | */ |
---|
| 31 | |
---|
| 32 | /** |
---|
| 33 | * @file |
---|
| 34 | * @brief Handles IR data. |
---|
| 35 | */ |
---|
| 36 | |
---|
| 37 | #include <stdio.h> |
---|
| 38 | #include <math.h> |
---|
| 39 | #include <unistd.h> |
---|
| 40 | |
---|
| 41 | #include "definitions.h" |
---|
| 42 | #include "wiic_internal.h" |
---|
| 43 | #include "ir.h" |
---|
| 44 | |
---|
| 45 | static int get_ir_sens(struct wiimote_t* wm, char** block1, char** block2); |
---|
| 46 | static void interpret_ir_data(struct wiimote_t* wm); |
---|
| 47 | static void fix_rotated_ir_dots(struct ir_dot_t* dot, float ang); |
---|
| 48 | static void get_ir_dot_avg(struct ir_dot_t* dot, int* x, int* y); |
---|
| 49 | static void reorder_ir_dots(struct ir_dot_t* dot); |
---|
| 50 | static float ir_distance(struct ir_dot_t* dot); |
---|
| 51 | static int ir_correct_for_bounds(int* x, int* y, enum aspect_t aspect, int offset_x, int offset_y); |
---|
| 52 | static void ir_convert_to_vres(int* x, int* y, enum aspect_t aspect, int vx, int vy); |
---|
| 53 | |
---|
| 54 | |
---|
| 55 | /** |
---|
| 56 | * @brief Set if the wiimote should track IR targets. |
---|
| 57 | * |
---|
| 58 | * @param wm Pointer to a wiimote_t structure. |
---|
| 59 | * @param status 1 to enable, 0 to disable. |
---|
| 60 | */ |
---|
| 61 | void wiic_set_ir(struct wiimote_t* wm, int status) { |
---|
| 62 | byte buf; |
---|
| 63 | char* block1 = NULL; |
---|
| 64 | char* block2 = NULL; |
---|
| 65 | int ir_level; |
---|
| 66 | |
---|
| 67 | if (!wm) |
---|
| 68 | return; |
---|
| 69 | |
---|
| 70 | /* |
---|
| 71 | * Wait for the handshake to finish first. |
---|
| 72 | * When it handshake finishes and sees that |
---|
| 73 | * IR is enabled, it will call this function |
---|
| 74 | * again to actually enable IR. |
---|
| 75 | */ |
---|
| 76 | if (!WIIMOTE_IS_SET(wm, WIIMOTE_STATE_HANDSHAKE_COMPLETE)) { |
---|
| 77 | WIIC_DEBUG("Tried to enable IR, will wait until handshake finishes."); |
---|
| 78 | WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_IR); |
---|
| 79 | return; |
---|
| 80 | } |
---|
| 81 | |
---|
| 82 | /* |
---|
| 83 | * Check to make sure a sensitivity setting is selected. |
---|
| 84 | */ |
---|
| 85 | ir_level = get_ir_sens(wm, &block1, &block2); |
---|
| 86 | if (!ir_level) { |
---|
| 87 | WIIC_ERROR("No IR sensitivity setting selected."); |
---|
| 88 | return; |
---|
| 89 | } |
---|
| 90 | |
---|
| 91 | if (status) { |
---|
| 92 | /* if already enabled then stop */ |
---|
| 93 | if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR)) |
---|
| 94 | return; |
---|
| 95 | WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_IR); |
---|
| 96 | } else { |
---|
| 97 | /* if already disabled then stop */ |
---|
| 98 | if (!WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR)) |
---|
| 99 | return; |
---|
| 100 | WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_IR); |
---|
| 101 | } |
---|
| 102 | |
---|
| 103 | /* set camera 1 and 2 */ |
---|
| 104 | buf = (status ? 0x04 : 0x00); |
---|
| 105 | wiic_send(wm, WM_CMD_IR, &buf, 1); |
---|
| 106 | wiic_send(wm, WM_CMD_IR_2, &buf, 1); |
---|
| 107 | |
---|
| 108 | if (!status) { |
---|
| 109 | WIIC_DEBUG("Disabled IR cameras for wiimote id %i.", wm->unid); |
---|
| 110 | wiic_set_report_type(wm); |
---|
| 111 | return; |
---|
| 112 | } |
---|
| 113 | |
---|
| 114 | /* enable IR, set sensitivity */ |
---|
| 115 | buf = 0x08; |
---|
| 116 | wiic_write_data(wm, WM_REG_IR, &buf, 1); |
---|
| 117 | |
---|
| 118 | /* wait for the wiimote to catch up */ |
---|
| 119 | usleep(50000); |
---|
| 120 | |
---|
| 121 | /* write sensitivity blocks */ |
---|
| 122 | wiic_write_data(wm, WM_REG_IR_BLOCK1, (byte*)block1, 9); |
---|
| 123 | wiic_write_data(wm, WM_REG_IR_BLOCK2, (byte*)block2, 2); |
---|
| 124 | |
---|
| 125 | /* set the IR mode */ |
---|
| 126 | if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_EXP)) |
---|
| 127 | buf = WM_IR_TYPE_BASIC; |
---|
| 128 | else |
---|
| 129 | buf = WM_IR_TYPE_EXTENDED; |
---|
| 130 | wiic_write_data(wm, WM_REG_IR_MODENUM, &buf, 1); |
---|
| 131 | |
---|
| 132 | usleep(50000); |
---|
| 133 | |
---|
| 134 | /* set the wiimote report type */ |
---|
| 135 | wiic_set_report_type(wm); |
---|
| 136 | |
---|
| 137 | WIIC_DEBUG("Enabled IR camera for wiimote id %i (sensitivity level %i).", wm->unid, ir_level); |
---|
| 138 | } |
---|
| 139 | |
---|
| 140 | |
---|
| 141 | /** |
---|
| 142 | * @brief Get the IR sensitivity settings. |
---|
| 143 | * |
---|
| 144 | * @param wm Pointer to a wiimote_t structure. |
---|
| 145 | * @param block1 [out] Pointer to where block1 will be set. |
---|
| 146 | * @param block2 [out] Pointer to where block2 will be set. |
---|
| 147 | * |
---|
| 148 | * @return Returns the sensitivity level. |
---|
| 149 | */ |
---|
| 150 | static int get_ir_sens(struct wiimote_t* wm, char** block1, char** block2) { |
---|
| 151 | if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR_SENS_LVL1)) { |
---|
| 152 | *block1 = WM_IR_BLOCK1_LEVEL1; |
---|
| 153 | *block2 = WM_IR_BLOCK2_LEVEL1; |
---|
| 154 | return 1; |
---|
| 155 | } else if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR_SENS_LVL2)) { |
---|
| 156 | *block1 = WM_IR_BLOCK1_LEVEL2; |
---|
| 157 | *block2 = WM_IR_BLOCK2_LEVEL2; |
---|
| 158 | return 2; |
---|
| 159 | } else if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR_SENS_LVL3)) { |
---|
| 160 | *block1 = WM_IR_BLOCK1_LEVEL3; |
---|
| 161 | *block2 = WM_IR_BLOCK2_LEVEL3; |
---|
| 162 | return 3; |
---|
| 163 | } else if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR_SENS_LVL4)) { |
---|
| 164 | *block1 = WM_IR_BLOCK1_LEVEL4; |
---|
| 165 | *block2 = WM_IR_BLOCK2_LEVEL4; |
---|
| 166 | return 4; |
---|
| 167 | } else if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR_SENS_LVL5)) { |
---|
| 168 | *block1 = WM_IR_BLOCK1_LEVEL5; |
---|
| 169 | *block2 = WM_IR_BLOCK2_LEVEL5; |
---|
| 170 | return 5; |
---|
| 171 | } |
---|
| 172 | |
---|
| 173 | *block1 = NULL; |
---|
| 174 | *block2 = NULL; |
---|
| 175 | return 0; |
---|
| 176 | } |
---|
| 177 | |
---|
| 178 | |
---|
| 179 | /** |
---|
| 180 | * @brief Set the virtual screen resolution for IR tracking. |
---|
| 181 | * |
---|
| 182 | * @param wm Pointer to a wiimote_t structure. |
---|
| 183 | * @param x Screen resolution width. |
---|
| 184 | * @param y Screen resolution height. |
---|
| 185 | */ |
---|
| 186 | void wiic_set_ir_vres(struct wiimote_t* wm, unsigned int x, unsigned int y) { |
---|
| 187 | if (!wm) return; |
---|
| 188 | |
---|
| 189 | wm->ir.vres[0] = (x-1); |
---|
| 190 | wm->ir.vres[1] = (y-1); |
---|
| 191 | } |
---|
| 192 | |
---|
| 193 | |
---|
| 194 | /** |
---|
| 195 | * @brief Set the XY position for the IR cursor. |
---|
| 196 | * |
---|
| 197 | * @param wm Pointer to a wiimote_t structure. |
---|
| 198 | * @param pos The position of the IR emitter (WIIC_IR_ABOVE or WIIC_IR_BELOW) |
---|
| 199 | */ |
---|
| 200 | void wiic_set_ir_position(struct wiimote_t* wm, enum ir_position_t pos) { |
---|
| 201 | if (!wm) return; |
---|
| 202 | |
---|
| 203 | wm->ir.pos = pos; |
---|
| 204 | |
---|
| 205 | switch (pos) { |
---|
| 206 | |
---|
| 207 | case WIIC_IR_ABOVE: |
---|
| 208 | wm->ir.offset[0] = 0; |
---|
| 209 | |
---|
| 210 | if (wm->ir.aspect == WIIC_ASPECT_16_9) |
---|
| 211 | wm->ir.offset[1] = WM_ASPECT_16_9_Y/2 - 70; |
---|
| 212 | else if (wm->ir.aspect == WIIC_ASPECT_4_3) |
---|
| 213 | wm->ir.offset[1] = WM_ASPECT_4_3_Y/2 - 100; |
---|
| 214 | |
---|
| 215 | return; |
---|
| 216 | |
---|
| 217 | case WIIC_IR_BELOW: |
---|
| 218 | wm->ir.offset[0] = 0; |
---|
| 219 | |
---|
| 220 | if (wm->ir.aspect == WIIC_ASPECT_16_9) |
---|
| 221 | wm->ir.offset[1] = -WM_ASPECT_16_9_Y/2 + 100; |
---|
| 222 | else if (wm->ir.aspect == WIIC_ASPECT_4_3) |
---|
| 223 | wm->ir.offset[1] = -WM_ASPECT_4_3_Y/2 + 70; |
---|
| 224 | |
---|
| 225 | return; |
---|
| 226 | |
---|
| 227 | default: |
---|
| 228 | return; |
---|
| 229 | }; |
---|
| 230 | } |
---|
| 231 | |
---|
| 232 | |
---|
| 233 | /** |
---|
| 234 | * @brief Set the aspect ratio of the TV/monitor. |
---|
| 235 | * |
---|
| 236 | * @param wm Pointer to a wiimote_t structure. |
---|
| 237 | * @param aspect Either WIIC_ASPECT_16_9 or WIIC_ASPECT_4_3 |
---|
| 238 | */ |
---|
| 239 | void wiic_set_aspect_ratio(struct wiimote_t* wm, enum aspect_t aspect) { |
---|
| 240 | if (!wm) return; |
---|
| 241 | |
---|
| 242 | wm->ir.aspect = aspect; |
---|
| 243 | |
---|
| 244 | if (aspect == WIIC_ASPECT_4_3) { |
---|
| 245 | wm->ir.vres[0] = WM_ASPECT_4_3_X; |
---|
| 246 | wm->ir.vres[1] = WM_ASPECT_4_3_Y; |
---|
| 247 | } else { |
---|
| 248 | wm->ir.vres[0] = WM_ASPECT_16_9_X; |
---|
| 249 | wm->ir.vres[1] = WM_ASPECT_16_9_Y; |
---|
| 250 | } |
---|
| 251 | |
---|
| 252 | /* reset the position offsets */ |
---|
| 253 | wiic_set_ir_position(wm, wm->ir.pos); |
---|
| 254 | } |
---|
| 255 | |
---|
| 256 | |
---|
| 257 | /** |
---|
| 258 | * @brief Set the IR sensitivity. |
---|
| 259 | * |
---|
| 260 | * @param wm Pointer to a wiimote_t structure. |
---|
| 261 | * @param level 1-5, same as Wii system sensitivity setting. |
---|
| 262 | * |
---|
| 263 | * If the level is < 1, then level will be set to 1. |
---|
| 264 | * If the level is > 5, then level will be set to 5. |
---|
| 265 | */ |
---|
| 266 | void wiic_set_ir_sensitivity(struct wiimote_t* wm, int level) { |
---|
| 267 | char* block1 = NULL; |
---|
| 268 | char* block2 = NULL; |
---|
| 269 | |
---|
| 270 | if (!wm) return; |
---|
| 271 | |
---|
| 272 | if (level > 5) level = 5; |
---|
| 273 | if (level < 1) level = 1; |
---|
| 274 | |
---|
| 275 | WIIMOTE_DISABLE_STATE(wm, (WIIMOTE_STATE_IR_SENS_LVL1 | |
---|
| 276 | WIIMOTE_STATE_IR_SENS_LVL2 | |
---|
| 277 | WIIMOTE_STATE_IR_SENS_LVL3 | |
---|
| 278 | WIIMOTE_STATE_IR_SENS_LVL4 | |
---|
| 279 | WIIMOTE_STATE_IR_SENS_LVL5)); |
---|
| 280 | |
---|
| 281 | switch (level) { |
---|
| 282 | case 1: |
---|
| 283 | WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_IR_SENS_LVL1); |
---|
| 284 | break; |
---|
| 285 | case 2: |
---|
| 286 | WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_IR_SENS_LVL2); |
---|
| 287 | break; |
---|
| 288 | case 3: |
---|
| 289 | WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_IR_SENS_LVL3); |
---|
| 290 | break; |
---|
| 291 | case 4: |
---|
| 292 | WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_IR_SENS_LVL4); |
---|
| 293 | break; |
---|
| 294 | case 5: |
---|
| 295 | WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_IR_SENS_LVL5); |
---|
| 296 | break; |
---|
| 297 | default: |
---|
| 298 | return; |
---|
| 299 | } |
---|
| 300 | |
---|
| 301 | /* set the new sensitivity */ |
---|
| 302 | get_ir_sens(wm, &block1, &block2); |
---|
| 303 | |
---|
| 304 | wiic_write_data(wm, WM_REG_IR_BLOCK1, (byte*)block1, 9); |
---|
| 305 | wiic_write_data(wm, WM_REG_IR_BLOCK2, (byte*)block2, 2); |
---|
| 306 | |
---|
| 307 | WIIC_DEBUG("Set IR sensitivity to level %i (unid %i)", level, wm->unid); |
---|
| 308 | } |
---|
| 309 | |
---|
| 310 | |
---|
| 311 | /** |
---|
| 312 | * @brief Calculate the data from the IR spots. Basic IR mode. |
---|
| 313 | * |
---|
| 314 | * @param wm Pointer to a wiimote_t structure. |
---|
| 315 | * @param data Data returned by the wiimote for the IR spots. |
---|
| 316 | */ |
---|
| 317 | void calculate_basic_ir(struct wiimote_t* wm, byte* data) { |
---|
| 318 | struct ir_dot_t* dot = wm->ir.dot; |
---|
| 319 | int i; |
---|
| 320 | |
---|
| 321 | dot[0].rx = 1023 - (data[0] | ((data[2] & 0x30) << 4)); |
---|
| 322 | dot[0].ry = data[1] | ((data[2] & 0xC0) << 2); |
---|
| 323 | |
---|
| 324 | dot[1].rx = 1023 - (data[3] | ((data[2] & 0x03) << 8)); |
---|
| 325 | dot[1].ry = data[4] | ((data[2] & 0x0C) << 6); |
---|
| 326 | |
---|
| 327 | dot[2].rx = 1023 - (data[5] | ((data[7] & 0x30) << 4)); |
---|
| 328 | dot[2].ry = data[6] | ((data[7] & 0xC0) << 2); |
---|
| 329 | |
---|
| 330 | dot[3].rx = 1023 - (data[8] | ((data[7] & 0x03) << 8)); |
---|
| 331 | dot[3].ry = data[9] | ((data[7] & 0x0C) << 6); |
---|
| 332 | |
---|
| 333 | /* set each IR spot to visible if spot is in range */ |
---|
| 334 | for (i = 0; i < 4; ++i) { |
---|
| 335 | if (dot[i].ry == 1023) |
---|
| 336 | dot[i].visible = 0; |
---|
| 337 | else { |
---|
| 338 | dot[i].visible = 1; |
---|
| 339 | dot[i].size = 0; /* since we don't know the size, set it as 0 */ |
---|
| 340 | } |
---|
| 341 | } |
---|
| 342 | |
---|
| 343 | interpret_ir_data(wm); |
---|
| 344 | } |
---|
| 345 | |
---|
| 346 | |
---|
| 347 | /** |
---|
| 348 | * @brief Calculate the data from the IR spots. Extended IR mode. |
---|
| 349 | * |
---|
| 350 | * @param wm Pointer to a wiimote_t structure. |
---|
| 351 | * @param data Data returned by the wiimote for the IR spots. |
---|
| 352 | */ |
---|
| 353 | void calculate_extended_ir(struct wiimote_t* wm, byte* data) { |
---|
| 354 | struct ir_dot_t* dot = wm->ir.dot; |
---|
| 355 | int i; |
---|
| 356 | |
---|
| 357 | for (i = 0; i < 4; ++i) { |
---|
| 358 | dot[i].rx = 1023 - (data[3*i] | ((data[(3*i)+2] & 0x30) << 4)); |
---|
| 359 | dot[i].ry = data[(3*i)+1] | ((data[(3*i)+2] & 0xC0) << 2); |
---|
| 360 | |
---|
| 361 | dot[i].size = data[(3*i)+2] & 0x0F; |
---|
| 362 | |
---|
| 363 | /* if in range set to visible */ |
---|
| 364 | if (dot[i].ry == 1023) |
---|
| 365 | dot[i].visible = 0; |
---|
| 366 | else |
---|
| 367 | dot[i].visible = 1; |
---|
| 368 | } |
---|
| 369 | |
---|
| 370 | interpret_ir_data(wm); |
---|
| 371 | } |
---|
| 372 | |
---|
| 373 | |
---|
| 374 | /** |
---|
| 375 | * @brief Interpret IR data into more user friendly variables. |
---|
| 376 | * |
---|
| 377 | * @param wm Pointer to a wiimote_t structure. |
---|
| 378 | */ |
---|
| 379 | static void interpret_ir_data(struct wiimote_t* wm) { |
---|
| 380 | struct ir_dot_t* dot = wm->ir.dot; |
---|
| 381 | int i; |
---|
| 382 | float roll = 0.0f; |
---|
| 383 | int last_num_dots = wm->ir.num_dots; |
---|
| 384 | |
---|
| 385 | if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_ACC)) |
---|
| 386 | roll = wm->orient.angle.roll; |
---|
| 387 | |
---|
| 388 | /* count visible dots */ |
---|
| 389 | wm->ir.num_dots = 0; |
---|
| 390 | for (i = 0; i < 4; ++i) { |
---|
| 391 | if (dot[i].visible) |
---|
| 392 | wm->ir.num_dots++; |
---|
| 393 | } |
---|
| 394 | |
---|
| 395 | switch (wm->ir.num_dots) { |
---|
| 396 | case 0: |
---|
| 397 | { |
---|
| 398 | wm->ir.state = 0; |
---|
| 399 | |
---|
| 400 | /* reset the dot ordering */ |
---|
| 401 | for (i = 0; i < 4; ++i) |
---|
| 402 | dot[i].order = 0; |
---|
| 403 | |
---|
| 404 | wm->ir.x = 0; |
---|
| 405 | wm->ir.y = 0; |
---|
| 406 | wm->ir.z = 0.0f; |
---|
| 407 | |
---|
| 408 | return; |
---|
| 409 | } |
---|
| 410 | case 1: |
---|
| 411 | { |
---|
| 412 | fix_rotated_ir_dots(wm->ir.dot, roll); |
---|
| 413 | |
---|
| 414 | if (wm->ir.state < 2) { |
---|
| 415 | /* |
---|
| 416 | * Only 1 known dot, so use just that. |
---|
| 417 | */ |
---|
| 418 | for (i = 0; i < 4; ++i) { |
---|
| 419 | if (dot[i].visible) { |
---|
| 420 | wm->ir.x = dot[i].x; |
---|
| 421 | wm->ir.y = dot[i].y; |
---|
| 422 | |
---|
| 423 | wm->ir.ax = wm->ir.x; |
---|
| 424 | wm->ir.ay = wm->ir.y; |
---|
| 425 | |
---|
| 426 | /* can't calculate yaw because we don't have the distance */ |
---|
| 427 | //wm->orient.yaw = calc_yaw(&wm->ir); |
---|
| 428 | |
---|
| 429 | ir_convert_to_vres(&wm->ir.x, &wm->ir.y, wm->ir.aspect, wm->ir.vres[0], wm->ir.vres[1]); |
---|
| 430 | break; |
---|
| 431 | } |
---|
| 432 | } |
---|
| 433 | } else { |
---|
| 434 | /* |
---|
| 435 | * Only see 1 dot but know theres 2. |
---|
| 436 | * Try to estimate where the other one |
---|
| 437 | * should be and use that. |
---|
| 438 | */ |
---|
| 439 | for (i = 0; i < 4; ++i) { |
---|
| 440 | if (dot[i].visible) { |
---|
| 441 | int ox = 0; |
---|
| 442 | int x, y; |
---|
| 443 | |
---|
| 444 | if (dot[i].order == 1) |
---|
| 445 | /* visible is the left dot - estimate where the right is */ |
---|
| 446 | ox = dot[i].x + wm->ir.distance; |
---|
| 447 | else if (dot[i].order == 2) |
---|
| 448 | /* visible is the right dot - estimate where the left is */ |
---|
| 449 | ox = dot[i].x - wm->ir.distance; |
---|
| 450 | |
---|
| 451 | x = ((signed int)dot[i].x + ox) / 2; |
---|
| 452 | y = dot[i].y; |
---|
| 453 | |
---|
| 454 | wm->ir.ax = x; |
---|
| 455 | wm->ir.ay = y; |
---|
| 456 | wm->orient.angle.yaw = calc_yaw(&wm->ir); |
---|
| 457 | |
---|
| 458 | if (ir_correct_for_bounds(&x, &y, wm->ir.aspect, wm->ir.offset[0], wm->ir.offset[1])) { |
---|
| 459 | ir_convert_to_vres(&x, &y, wm->ir.aspect, wm->ir.vres[0], wm->ir.vres[1]); |
---|
| 460 | wm->ir.x = x; |
---|
| 461 | wm->ir.y = y; |
---|
| 462 | } |
---|
| 463 | |
---|
| 464 | break; |
---|
| 465 | } |
---|
| 466 | } |
---|
| 467 | } |
---|
| 468 | |
---|
| 469 | break; |
---|
| 470 | } |
---|
| 471 | case 2: |
---|
| 472 | case 3: |
---|
| 473 | case 4: |
---|
| 474 | { |
---|
| 475 | /* |
---|
| 476 | * Two (or more) dots known and seen. |
---|
| 477 | * Average them together to estimate the true location. |
---|
| 478 | */ |
---|
| 479 | int x, y; |
---|
| 480 | wm->ir.state = 2; |
---|
| 481 | |
---|
| 482 | fix_rotated_ir_dots(wm->ir.dot, roll); |
---|
| 483 | |
---|
| 484 | /* if there is at least 1 new dot, reorder them all */ |
---|
| 485 | if (wm->ir.num_dots > last_num_dots) { |
---|
| 486 | reorder_ir_dots(dot); |
---|
| 487 | wm->ir.x = 0; |
---|
| 488 | wm->ir.y = 0; |
---|
| 489 | } |
---|
| 490 | |
---|
| 491 | wm->ir.distance = ir_distance(dot); |
---|
| 492 | wm->ir.z = 1023 - wm->ir.distance; |
---|
| 493 | |
---|
| 494 | get_ir_dot_avg(wm->ir.dot, &x, &y); |
---|
| 495 | |
---|
| 496 | wm->ir.ax = x; |
---|
| 497 | wm->ir.ay = y; |
---|
| 498 | wm->orient.angle.yaw = calc_yaw(&wm->ir); |
---|
| 499 | |
---|
| 500 | if (ir_correct_for_bounds(&x, &y, wm->ir.aspect, wm->ir.offset[0], wm->ir.offset[1])) { |
---|
| 501 | ir_convert_to_vres(&x, &y, wm->ir.aspect, wm->ir.vres[0], wm->ir.vres[1]); |
---|
| 502 | wm->ir.x = x; |
---|
| 503 | wm->ir.y = y; |
---|
| 504 | } |
---|
| 505 | |
---|
| 506 | break; |
---|
| 507 | } |
---|
| 508 | default: |
---|
| 509 | { |
---|
| 510 | break; |
---|
| 511 | } |
---|
| 512 | } |
---|
| 513 | |
---|
| 514 | #ifdef WITH_WIIC_DEBUG |
---|
| 515 | { |
---|
| 516 | int ir_level; |
---|
| 517 | WIIC_GET_IR_SENSITIVITY(wm, &ir_level); |
---|
| 518 | WIIC_DEBUG("IR sensitivity: %i", ir_level); |
---|
| 519 | WIIC_DEBUG("IR visible dots: %i", wm->ir.num_dots); |
---|
| 520 | for (i = 0; i < 4; ++i) |
---|
| 521 | if (dot[i].visible) |
---|
| 522 | WIIC_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); |
---|
| 523 | WIIC_DEBUG("IR[absolute]: (%i, %i)", wm->ir.x, wm->ir.y); |
---|
| 524 | } |
---|
| 525 | #endif |
---|
| 526 | } |
---|
| 527 | |
---|
| 528 | |
---|
| 529 | |
---|
| 530 | /** |
---|
| 531 | * @brief Fix the rotation of the IR dots. |
---|
| 532 | * |
---|
| 533 | * @param dot An array of 4 ir_dot_t objects. |
---|
| 534 | * @param ang The roll angle to correct by (-180, 180) |
---|
| 535 | * |
---|
| 536 | * If there is roll then the dots are rotated |
---|
| 537 | * around the origin and give a false cursor |
---|
| 538 | * position. Correct for the roll. |
---|
| 539 | * |
---|
| 540 | * If the accelerometer is off then obviously |
---|
| 541 | * this will not do anything and the cursor |
---|
| 542 | * position may be inaccurate. |
---|
| 543 | */ |
---|
| 544 | static void fix_rotated_ir_dots(struct ir_dot_t* dot, float ang) { |
---|
| 545 | float s, c; |
---|
| 546 | int x, y; |
---|
| 547 | int i; |
---|
| 548 | |
---|
| 549 | if (!ang) { |
---|
| 550 | for (i = 0; i < 4; ++i) { |
---|
| 551 | dot[i].x = dot[i].rx; |
---|
| 552 | dot[i].y = dot[i].ry; |
---|
| 553 | } |
---|
| 554 | return; |
---|
| 555 | } |
---|
| 556 | |
---|
| 557 | s = sin(DEGREE_TO_RAD(ang)); |
---|
| 558 | c = cos(DEGREE_TO_RAD(ang)); |
---|
| 559 | |
---|
| 560 | /* |
---|
| 561 | * [ cos(theta) -sin(theta) ][ ir->rx ] |
---|
| 562 | * [ sin(theta) cos(theta) ][ ir->ry ] |
---|
| 563 | */ |
---|
| 564 | |
---|
| 565 | for (i = 0; i < 4; ++i) { |
---|
| 566 | if (!dot[i].visible) |
---|
| 567 | continue; |
---|
| 568 | |
---|
| 569 | x = dot[i].rx - (1024/2); |
---|
| 570 | y = dot[i].ry - (768/2); |
---|
| 571 | |
---|
| 572 | dot[i].x = (c * x) + (-s * y); |
---|
| 573 | dot[i].y = (s * x) + (c * y); |
---|
| 574 | |
---|
| 575 | dot[i].x += (1024/2); |
---|
| 576 | dot[i].y += (768/2); |
---|
| 577 | } |
---|
| 578 | } |
---|
| 579 | |
---|
| 580 | |
---|
| 581 | /** |
---|
| 582 | * @brief Average IR dots. |
---|
| 583 | * |
---|
| 584 | * @param dot An array of 4 ir_dot_t objects. |
---|
| 585 | * @param x [out] Average X |
---|
| 586 | * @param y [out] Average Y |
---|
| 587 | */ |
---|
| 588 | static void get_ir_dot_avg(struct ir_dot_t* dot, int* x, int* y) { |
---|
| 589 | int vis = 0, i = 0; |
---|
| 590 | |
---|
| 591 | *x = 0; |
---|
| 592 | *y = 0; |
---|
| 593 | |
---|
| 594 | for (; i < 4; ++i) { |
---|
| 595 | if (dot[i].visible) { |
---|
| 596 | *x += dot[i].x; |
---|
| 597 | *y += dot[i].y; |
---|
| 598 | ++vis; |
---|
| 599 | } |
---|
| 600 | } |
---|
| 601 | |
---|
| 602 | *x /= vis; |
---|
| 603 | *y /= vis; |
---|
| 604 | } |
---|
| 605 | |
---|
| 606 | |
---|
| 607 | /** |
---|
| 608 | * @brief Reorder the IR dots. |
---|
| 609 | * |
---|
| 610 | * @param dot An array of 4 ir_dot_t objects. |
---|
| 611 | */ |
---|
| 612 | static void reorder_ir_dots(struct ir_dot_t* dot) { |
---|
| 613 | int i, j, order; |
---|
| 614 | |
---|
| 615 | /* reset the dot ordering */ |
---|
| 616 | for (i = 0; i < 4; ++i) |
---|
| 617 | dot[i].order = 0; |
---|
| 618 | |
---|
| 619 | for (order = 1; order < 5; ++order) { |
---|
| 620 | i = 0; |
---|
| 621 | |
---|
| 622 | for (; !dot[i].visible || dot[i].order; ++i) |
---|
| 623 | if (i > 4) |
---|
| 624 | return; |
---|
| 625 | |
---|
| 626 | for (j = 0; j < 4; ++j) { |
---|
| 627 | if (dot[j].visible && !dot[j].order && (dot[j].x < dot[i].x)) |
---|
| 628 | i = j; |
---|
| 629 | } |
---|
| 630 | |
---|
| 631 | dot[i].order = order; |
---|
| 632 | } |
---|
| 633 | } |
---|
| 634 | |
---|
| 635 | |
---|
| 636 | /** |
---|
| 637 | * @brief Calculate the distance between the first 2 visible IR dots. |
---|
| 638 | * |
---|
| 639 | * @param dot An array of 4 ir_dot_t objects. |
---|
| 640 | */ |
---|
| 641 | static float ir_distance(struct ir_dot_t* dot) { |
---|
| 642 | int i1, i2; |
---|
| 643 | int xd, yd; |
---|
| 644 | |
---|
| 645 | for (i1 = 0; i1 < 4; ++i1) |
---|
| 646 | if (dot[i1].visible) |
---|
| 647 | break; |
---|
| 648 | if (i1 == 4) |
---|
| 649 | return 0.0f; |
---|
| 650 | |
---|
| 651 | for (i2 = i1+1; i2 < 4; ++i2) |
---|
| 652 | if (dot[i2].visible) |
---|
| 653 | break; |
---|
| 654 | if (i2 == 4) |
---|
| 655 | return 0.0f; |
---|
| 656 | |
---|
| 657 | xd = dot[i2].x - dot[i1].x; |
---|
| 658 | yd = dot[i2].y - dot[i1].y; |
---|
| 659 | |
---|
| 660 | return sqrt(xd*xd + yd*yd); |
---|
| 661 | } |
---|
| 662 | |
---|
| 663 | |
---|
| 664 | /** |
---|
| 665 | * @brief Correct for the IR bounding box. |
---|
| 666 | * |
---|
| 667 | * @param x [out] The current X, it will be updated if valid. |
---|
| 668 | * @param y [out] The current Y, it will be updated if valid. |
---|
| 669 | * @param aspect Aspect ratio of the screen. |
---|
| 670 | * @param offset_x The X offset of the bounding box. |
---|
| 671 | * @param offset_y The Y offset of the bounding box. |
---|
| 672 | * |
---|
| 673 | * @return Returns 1 if the point is valid and was updated. |
---|
| 674 | * |
---|
| 675 | * Nintendo was smart with this bit. They sacrifice a little |
---|
| 676 | * precision for a big increase in usability. |
---|
| 677 | */ |
---|
| 678 | static int ir_correct_for_bounds(int* x, int* y, enum aspect_t aspect, int offset_x, int offset_y) { |
---|
| 679 | int x0, y0; |
---|
| 680 | int xs, ys; |
---|
| 681 | |
---|
| 682 | if (aspect == WIIC_ASPECT_16_9) { |
---|
| 683 | xs = WM_ASPECT_16_9_X; |
---|
| 684 | ys = WM_ASPECT_16_9_Y; |
---|
| 685 | } else { |
---|
| 686 | xs = WM_ASPECT_4_3_X; |
---|
| 687 | ys = WM_ASPECT_4_3_Y; |
---|
| 688 | } |
---|
| 689 | |
---|
| 690 | x0 = ((1024 - xs) / 2) + offset_x; |
---|
| 691 | y0 = ((768 - ys) / 2) + offset_y; |
---|
| 692 | |
---|
| 693 | if ((*x >= x0) |
---|
| 694 | && (*x <= (x0 + xs)) |
---|
| 695 | && (*y >= y0) |
---|
| 696 | && (*y <= (y0 + ys))) |
---|
| 697 | { |
---|
| 698 | *x -= offset_x; |
---|
| 699 | *y -= offset_y; |
---|
| 700 | |
---|
| 701 | return 1; |
---|
| 702 | } |
---|
| 703 | |
---|
| 704 | return 0; |
---|
| 705 | } |
---|
| 706 | |
---|
| 707 | |
---|
| 708 | /** |
---|
| 709 | * @brief Interpolate the point to the user defined virtual screen resolution. |
---|
| 710 | */ |
---|
| 711 | static void ir_convert_to_vres(int* x, int* y, enum aspect_t aspect, int vx, int vy) { |
---|
| 712 | int xs, ys; |
---|
| 713 | |
---|
| 714 | if (aspect == WIIC_ASPECT_16_9) { |
---|
| 715 | xs = WM_ASPECT_16_9_X; |
---|
| 716 | ys = WM_ASPECT_16_9_Y; |
---|
| 717 | } else { |
---|
| 718 | xs = WM_ASPECT_4_3_X; |
---|
| 719 | ys = WM_ASPECT_4_3_Y; |
---|
| 720 | } |
---|
| 721 | |
---|
| 722 | *x -= ((1024-xs)/2); |
---|
| 723 | *y -= ((768-ys)/2); |
---|
| 724 | |
---|
| 725 | *x = (*x / (float)xs) * vx; |
---|
| 726 | *y = (*y / (float)ys) * vy; |
---|
| 727 | } |
---|
| 728 | |
---|
| 729 | |
---|
| 730 | /** |
---|
| 731 | * @brief Calculate yaw given the IR data. |
---|
| 732 | * |
---|
| 733 | * @param ir IR data structure. |
---|
| 734 | */ |
---|
| 735 | float calc_yaw(struct ir_t* ir) { |
---|
| 736 | float x; |
---|
| 737 | |
---|
| 738 | x = ir->ax - 512; |
---|
| 739 | x = x * (ir->z / 1024.0f); |
---|
| 740 | |
---|
| 741 | return RAD_TO_DEGREE( atanf(x / ir->z) ); |
---|
| 742 | } |
---|