/* This source as presented is a modified version of original wiiuse for use * with RetroArch, and must not be confused with the original software. */ #include #ifndef WIN32 #include #include #include #else #include #endif #include #include #include #include #include "dynamics.h" #include "definitions.h" #include "wiiuse_internal.h" #include "events.h" #include "nunchuk.h" #include "classic.h" #include "motion_plus.h" #include "ir.h" #include "io.h" static void event_data_read(struct wiimote_t *wm,ubyte *msg) { ubyte err; ubyte len; uword offset; struct op_t *op; struct cmd_blk_t *cmd = wm->cmd_head; wiiuse_pressed_buttons(wm,msg); if(!cmd) return; if(!(cmd->state==CMD_SENT && cmd->data[0]==WM_CMD_READ_DATA)) return; //printf("event_data_read(%p)\n",cmd); err = msg[2]&0x0f; op = (struct op_t*)cmd->data; if(err) { wm->cmd_head = cmd->next; cmd->state = CMD_DONE; if(cmd->cb!=NULL) cmd->cb(wm,op->buffer,(op->readdata.size - op->wait)); __lwp_queue_append(&wm->cmdq,&cmd->node); wiiuse_send_next_command(wm); return; } len = ((msg[2]&0xf0)>>4)+1; offset = BIG_ENDIAN_SHORT(*(uword*)(msg+3)); //printf("addr: %08x\noffset: %d\nlen: %d\n",req->addr,offset,len); op->readdata.addr = (op->readdata.addr&0xffff); op->wait -= len; if(op->wait>=op->readdata.size) op->wait = 0; memcpy((op->buffer+offset-op->readdata.addr),(msg+5),len); if(!op->wait) { wm->cmd_head = cmd->next; wm->event = WIIUSE_READ_DATA; cmd->state = CMD_DONE; if(cmd->cb!=NULL) cmd->cb(wm,op->buffer,op->readdata.size); __lwp_queue_append(&wm->cmdq,&cmd->node); wiiuse_send_next_command(wm); } } static void event_ack(struct wiimote_t *wm,ubyte *msg) { struct cmd_blk_t *cmd = wm->cmd_head; wiiuse_pressed_buttons(wm,msg); if(!cmd || cmd->state!=CMD_SENT || cmd->data[0]==WM_CMD_READ_DATA || cmd->data[0]==WM_CMD_CTRL_STATUS || cmd->data[0]!=msg[2] || msg[3]) { //WIIUSE_WARNING("Unsolicited event ack: report %02x status %02x", msg[2], msg[3]); return; } //WIIUSE_DEBUG("Received ack for command %02x %02x", cmd->data[0], cmd->data[1]); wm->cmd_head = cmd->next; wm->event = WIIUSE_ACK; cmd->state = CMD_DONE; if(cmd->cb) cmd->cb(wm,NULL,0); __lwp_queue_append(&wm->cmdq,&cmd->node); wiiuse_send_next_command(wm); } static void event_status(struct wiimote_t *wm,ubyte *msg) { int ir = 0; int attachment = 0; #ifdef HAVE_WIIUSE_SPEAKER int speaker = 0; #endif //int led[4]= {0}; struct cmd_blk_t *cmd = wm->cmd_head; wiiuse_pressed_buttons(wm,msg); wm->event = WIIUSE_STATUS; //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; if((msg[2]&WM_CTRL_STATUS_BYTE1_ATTACHMENT)==WM_CTRL_STATUS_BYTE1_ATTACHMENT) attachment = 1; #ifdef HAVE_WIIUSE_SPEAKER if((msg[2]&WM_CTRL_STATUS_BYTE1_SPEAKER_ENABLED)==WM_CTRL_STATUS_BYTE1_SPEAKER_ENABLED) speaker = 1; #endif if((msg[2]&WM_CTRL_STATUS_BYTE1_IR_ENABLED)==WM_CTRL_STATUS_BYTE1_IR_ENABLED) ir = 1; wm->battery_level = msg[5]; if(!ir && WIIMOTE_IS_SET(wm,WIIMOTE_STATE_IR_INIT)) { WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_IR_INIT); wiiuse_set_ir(wm, 1); goto done; } if(ir && !WIIMOTE_IS_SET(wm,WIIMOTE_STATE_IR)) WIIMOTE_ENABLE_STATE(wm,WIIMOTE_STATE_IR); else if(!ir && WIIMOTE_IS_SET(wm,WIIMOTE_STATE_IR)) WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_IR); #ifdef HAVE_WIIUSE_SPEAKER if(!speaker && WIIMOTE_IS_SET(wm,WIIMOTE_STATE_SPEAKER_INIT)) { WIIMOTE_DISABLE_STATE(wm,WIIMOTE_STATE_SPEAKER_INIT); wiiuse_set_speaker(wm,1); goto done; } if(speaker && !WIIMOTE_IS_SET(wm,WIIMOTE_STATE_SPEAKER)) WIIMOTE_ENABLE_STATE(wm,WIIMOTE_STATE_SPEAKER); else if(!speaker && WIIMOTE_IS_SET(wm,WIIMOTE_STATE_SPEAKER)) WIIMOTE_DISABLE_STATE(wm,WIIMOTE_STATE_SPEAKER); #endif if(attachment) { if(!WIIMOTE_IS_SET(wm,WIIMOTE_STATE_EXP) && !WIIMOTE_IS_SET(wm,WIIMOTE_STATE_EXP_FAILED) && !WIIMOTE_IS_SET(wm,WIIMOTE_STATE_EXP_HANDSHAKE)) { wiiuse_handshake_expansion_start(wm); goto done; } } else { WIIMOTE_DISABLE_STATE(wm,WIIMOTE_STATE_EXP_FAILED); if(WIIMOTE_IS_SET(wm,WIIMOTE_STATE_EXP)) { wiiuse_disable_expansion(wm); goto done; } } wiiuse_set_report_type(wm,NULL); done: if(!cmd) return; if(!(cmd->state==CMD_SENT && cmd->data[0]==WM_CMD_CTRL_STATUS)) return; wm->cmd_head = cmd->next; cmd->state = CMD_DONE; if(cmd->cb!=NULL) cmd->cb(wm,msg,6); __lwp_queue_append(&wm->cmdq,&cmd->node); wiiuse_send_next_command(wm); } static void handle_expansion(struct wiimote_t *wm,ubyte *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_MOTION_PLUS: motion_plus_event(&wm->exp.mp, msg); break; default: break; } } /** * @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. */ //printf("idle_cycle()\n");/// 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); } } void parse_event(struct wiimote_t *wm) { ubyte event; ubyte *msg; event = wm->event_buf[0]; msg = wm->event_buf+1; //printf("parse_event(%02x,%p)\n",event,msg); switch(event) { case WM_RPT_CTRL_STATUS: event_status(wm,msg); return; case WM_RPT_READ: event_data_read(wm,msg); return; case WM_RPT_ACK: event_ack(wm,msg); return; case WM_RPT_BTN: wiiuse_pressed_buttons(wm,msg); break; case WM_RPT_BTN_ACC: wiiuse_pressed_buttons(wm,msg); wm->accel.x = (msg[2]<<2)|((msg[0]>>5)&3); wm->accel.y = (msg[3]<<2)|((msg[1]>>4)&2); wm->accel.z = (msg[4]<<2)|((msg[1]>>5)&2); #ifndef GEKKO /* 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); #endif break; case WM_RPT_BTN_ACC_IR: wiiuse_pressed_buttons(wm,msg); wm->accel.x = (msg[2]<<2)|((msg[0]>>5)&3); wm->accel.y = (msg[3]<<2)|((msg[1]>>4)&2); wm->accel.z = (msg[4]<<2)|((msg[1]>>5)&2); #ifndef GEKKO /* 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); #endif calculate_extended_ir(wm, msg+5); break; case WM_RPT_BTN_EXP: 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); wm->accel.x = (msg[2]<<2)|((msg[0]>>5)&3); wm->accel.y = (msg[3]<<2)|((msg[1]>>4)&2); wm->accel.z = (msg[4]<<2)|((msg[1]>>5)&2); #ifndef GEKKO calculate_orientation(&wm->accel_calib, &wm->accel, &wm->orient, WIIMOTE_IS_FLAG_SET(wm, WIIUSE_SMOOTHING)); calculate_gforce(&wm->accel_calib, &wm->accel, &wm->gforce); #endif handle_expansion(wm, msg+5); break; case WM_RPT_BTN_IR_EXP: wiiuse_pressed_buttons(wm,msg); calculate_basic_ir(wm, msg+2); handle_expansion(wm,msg+12); break; case WM_RPT_BTN_ACC_IR_EXP: /* button - motion - ir - expansion */ wiiuse_pressed_buttons(wm, msg); wm->accel.x = (msg[2]<<2)|((msg[0]>>5)&3); wm->accel.y = (msg[3]<<2)|((msg[1]>>4)&2); wm->accel.z = (msg[4]<<2)|((msg[1]>>5)&2); #ifndef GEKKO calculate_orientation(&wm->accel_calib, &wm->accel, &wm->orient, WIIMOTE_IS_FLAG_SET(wm, WIIUSE_SMOOTHING)); calculate_gforce(&wm->accel_calib, &wm->accel, &wm->gforce); #endif /* ir */ calculate_basic_ir(wm, msg+5); handle_expansion(wm, msg+15); break; default: WIIUSE_WARNING("Unknown event, can not handle it [Code 0x%x].", event); return; } /* was there an event? */ 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, ubyte* msg) { short now; /* convert to big endian */ now = BIG_ENDIAN_SHORT(*(short*)msg) & WIIMOTE_BUTTON_ALL; /* preserve old btns pressed */ wm->btns_last = wm->btns; /* 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; }