prevent a crash if the cpu is already in real mode when the app starts (tueidj)
[libogc.git] / wiiuse / events.c
blobb24d99e2d027d1672146d27ac00e26693d3d05c1
1 #include <stdio.h>
3 #ifndef WIN32
4 #include <sys/time.h>
5 #include <unistd.h>
6 #include <errno.h>
7 #else
8 #include <winsock2.h>
9 #endif
11 #include <sys/types.h>
12 #include <stdlib.h>
13 #include <math.h>
14 #include <string.h>
16 #include "dynamics.h"
17 #include "definitions.h"
18 #include "wiiuse_internal.h"
19 #include "events.h"
20 #include "nunchuk.h"
21 #include "classic.h"
22 #include "guitar_hero_3.h"
23 #include "wiiboard.h"
24 #include "motion_plus.h"
25 #include "ir.h"
26 #include "io.h"
29 static void event_data_read(struct wiimote_t *wm,ubyte *msg)
31 ubyte err;
32 ubyte len;
33 uword offset;
34 struct op_t *op;
35 struct cmd_blk_t *cmd = wm->cmd_head;
37 wiiuse_pressed_buttons(wm,msg);
39 if(!cmd) return;
40 if(!(cmd->state==CMD_SENT && cmd->data[0]==WM_CMD_READ_DATA)) return;
42 //printf("event_data_read(%p)\n",cmd);
44 err = msg[2]&0x0f;
45 op = (struct op_t*)cmd->data;
46 if(err) {
47 wm->cmd_head = cmd->next;
49 cmd->state = CMD_DONE;
50 if(cmd->cb!=NULL) cmd->cb(wm,op->buffer,(op->readdata.size - op->wait));
52 __lwp_queue_append(&wm->cmdq,&cmd->node);
53 wiiuse_send_next_command(wm);
54 return;
57 len = ((msg[2]&0xf0)>>4)+1;
58 offset = BIG_ENDIAN_SHORT(*(uword*)(msg+3));
60 //printf("addr: %08x\noffset: %d\nlen: %d\n",req->addr,offset,len);
62 op->readdata.addr = (op->readdata.addr&0xffff);
63 op->wait -= len;
64 if(op->wait>=op->readdata.size) op->wait = 0;
66 memcpy((op->buffer+offset-op->readdata.addr),(msg+5),len);
67 if(!op->wait) {
68 wm->cmd_head = cmd->next;
70 wm->event = WIIUSE_READ_DATA;
71 cmd->state = CMD_DONE;
72 if(cmd->cb!=NULL) cmd->cb(wm,op->buffer,op->readdata.size);
74 __lwp_queue_append(&wm->cmdq,&cmd->node);
75 wiiuse_send_next_command(wm);
79 static void event_data_write(struct wiimote_t *wm,ubyte *msg)
81 struct cmd_blk_t *cmd = wm->cmd_head;
83 wiiuse_pressed_buttons(wm,msg);
85 if(!cmd) return;
86 if(!(cmd->state==CMD_SENT && (cmd->data[0]==WM_CMD_WRITE_DATA || cmd->data[0]==WM_CMD_STREAM_DATA))) return;
88 wm->cmd_head = cmd->next;
90 wm->event = WIIUSE_WRITE_DATA;
91 cmd->state = CMD_DONE;
92 if(cmd->cb) cmd->cb(wm,NULL,0);
94 __lwp_queue_append(&wm->cmdq,&cmd->node);
95 wiiuse_send_next_command(wm);
98 static void event_status(struct wiimote_t *wm,ubyte *msg)
100 int ir = 0;
101 int attachment = 0;
102 int speaker = 0;
103 int led[4]= {0};
104 struct cmd_blk_t *cmd = wm->cmd_head;
106 wiiuse_pressed_buttons(wm,msg);
108 wm->event = WIIUSE_STATUS;
109 if(msg[2]&WM_CTRL_STATUS_BYTE1_LED_1) led[0] = 1;
110 if(msg[2]&WM_CTRL_STATUS_BYTE1_LED_2) led[1] = 1;
111 if(msg[2]&WM_CTRL_STATUS_BYTE1_LED_3) led[2] = 1;
112 if(msg[2]&WM_CTRL_STATUS_BYTE1_LED_4) led[3] = 1;
114 if((msg[2]&WM_CTRL_STATUS_BYTE1_ATTACHMENT)==WM_CTRL_STATUS_BYTE1_ATTACHMENT) attachment = 1;
115 if((msg[2]&WM_CTRL_STATUS_BYTE1_SPEAKER_ENABLED)==WM_CTRL_STATUS_BYTE1_SPEAKER_ENABLED) speaker = 1;
116 if((msg[2]&WM_CTRL_STATUS_BYTE1_IR_ENABLED)==WM_CTRL_STATUS_BYTE1_IR_ENABLED) ir = 1;
118 wm->battery_level = msg[5];
120 if(!ir && WIIMOTE_IS_SET(wm,WIIMOTE_STATE_IR_INIT)) {
121 WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_IR_INIT);
122 wiiuse_set_ir(wm, 1);
123 goto done;
125 if(ir && !WIIMOTE_IS_SET(wm,WIIMOTE_STATE_IR)) WIIMOTE_ENABLE_STATE(wm,WIIMOTE_STATE_IR);
126 else if(!ir && WIIMOTE_IS_SET(wm,WIIMOTE_STATE_IR)) WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_IR);
128 if(!speaker && WIIMOTE_IS_SET(wm,WIIMOTE_STATE_SPEAKER_INIT)) {
129 WIIMOTE_DISABLE_STATE(wm,WIIMOTE_STATE_SPEAKER_INIT);
130 wiiuse_set_speaker(wm,1);
131 goto done;
133 if(speaker && !WIIMOTE_IS_SET(wm,WIIMOTE_STATE_SPEAKER)) WIIMOTE_ENABLE_STATE(wm,WIIMOTE_STATE_SPEAKER);
134 else if(!speaker && WIIMOTE_IS_SET(wm,WIIMOTE_STATE_SPEAKER)) WIIMOTE_DISABLE_STATE(wm,WIIMOTE_STATE_SPEAKER);
136 if(attachment) {
137 if(!WIIMOTE_IS_SET(wm,WIIMOTE_STATE_EXP) && !WIIMOTE_IS_SET(wm,WIIMOTE_STATE_EXP_FAILED) && !WIIMOTE_IS_SET(wm,WIIMOTE_STATE_EXP_HANDSHAKE)) {
138 wiiuse_handshake_expansion_start(wm);
139 goto done;
141 } else {
142 WIIMOTE_DISABLE_STATE(wm,WIIMOTE_STATE_EXP_FAILED);
143 if(WIIMOTE_IS_SET(wm,WIIMOTE_STATE_EXP)) {
144 wiiuse_disable_expansion(wm);
145 goto done;
148 wiiuse_set_report_type(wm,NULL);
150 done:
151 if(!cmd) return;
152 if(!(cmd->state==CMD_SENT && cmd->data[0]==WM_CMD_CTRL_STATUS)) return;
154 wm->cmd_head = cmd->next;
156 cmd->state = CMD_DONE;
157 if(cmd->cb!=NULL) cmd->cb(wm,msg,6);
159 __lwp_queue_append(&wm->cmdq,&cmd->node);
160 wiiuse_send_next_command(wm);
163 static void handle_expansion(struct wiimote_t *wm,ubyte *msg)
165 switch (wm->exp.type) {
166 case EXP_NUNCHUK:
167 nunchuk_event(&wm->exp.nunchuk, msg);
168 break;
169 case EXP_CLASSIC:
170 classic_ctrl_event(&wm->exp.classic, msg);
171 break;
172 case EXP_GUITAR_HERO_3:
173 guitar_hero_3_event(&wm->exp.gh3, msg);
174 break;
175 case EXP_WII_BOARD:
176 wii_board_event(&wm->exp.wb, msg);
177 break;
178 case EXP_MOTION_PLUS:
179 motion_plus_event(&wm->exp.mp, msg);
180 break;
181 default:
182 break;
187 * @brief Called on a cycle where no significant change occurs.
189 * @param wm Pointer to a wiimote_t structure.
191 void idle_cycle(struct wiimote_t* wm)
194 * Smooth the angles.
196 * This is done to make sure that on every cycle the orientation
197 * angles are smoothed. Normally when an event occurs the angles
198 * are updated and smoothed, but if no packet comes in then the
199 * angles remain the same. This means the angle wiiuse reports
200 * is still an old value. Smoothing needs to be applied in this
201 * case in order for the angle it reports to converge to the true
202 * angle of the device.
204 //printf("idle_cycle()\n");///
205 if (WIIUSE_USING_ACC(wm) && WIIMOTE_IS_FLAG_SET(wm, WIIUSE_SMOOTHING)) {
206 apply_smoothing(&wm->accel_calib, &wm->orient, SMOOTH_ROLL);
207 apply_smoothing(&wm->accel_calib, &wm->orient, SMOOTH_PITCH);
211 void parse_event(struct wiimote_t *wm)
213 ubyte event;
214 ubyte *msg;
216 event = wm->event_buf[0];
217 msg = wm->event_buf+1;
218 //printf("parse_event(%02x,%p)\n",event,msg);
219 switch(event) {
220 case WM_RPT_CTRL_STATUS:
221 event_status(wm,msg);
222 return;
223 case WM_RPT_READ:
224 event_data_read(wm,msg);
225 return;
226 case WM_RPT_WRITE:
227 event_data_write(wm,msg);
228 return;
229 case WM_RPT_BTN:
230 wiiuse_pressed_buttons(wm,msg);
231 break;
232 case WM_RPT_BTN_ACC:
233 wiiuse_pressed_buttons(wm,msg);
235 wm->accel.x = (msg[2]<<2)|((msg[0]>>5)&3);
236 wm->accel.y = (msg[3]<<2)|((msg[1]>>4)&2);
237 wm->accel.z = (msg[4]<<2)|((msg[1]>>5)&2);
238 #ifndef GEKKO
239 /* calculate the remote orientation */
240 calculate_orientation(&wm->accel_calib, &wm->accel, &wm->orient, WIIMOTE_IS_FLAG_SET(wm, WIIUSE_SMOOTHING));
242 /* calculate the gforces on each axis */
243 calculate_gforce(&wm->accel_calib, &wm->accel, &wm->gforce);
244 #endif
245 break;
246 case WM_RPT_BTN_ACC_IR:
247 wiiuse_pressed_buttons(wm,msg);
249 wm->accel.x = (msg[2]<<2)|((msg[0]>>5)&3);
250 wm->accel.y = (msg[3]<<2)|((msg[1]>>4)&2);
251 wm->accel.z = (msg[4]<<2)|((msg[1]>>5)&2);
252 #ifndef GEKKO
253 /* calculate the remote orientation */
254 calculate_orientation(&wm->accel_calib, &wm->accel, &wm->orient, WIIMOTE_IS_FLAG_SET(wm, WIIUSE_SMOOTHING));
256 /* calculate the gforces on each axis */
257 calculate_gforce(&wm->accel_calib, &wm->accel, &wm->gforce);
258 #endif
259 calculate_extended_ir(wm, msg+5);
260 break;
261 case WM_RPT_BTN_EXP:
262 wiiuse_pressed_buttons(wm,msg);
263 handle_expansion(wm,msg+2);
264 break;
265 case WM_RPT_BTN_ACC_EXP:
266 /* button - motion - expansion */
267 wiiuse_pressed_buttons(wm, msg);
269 wm->accel.x = (msg[2]<<2)|((msg[0]>>5)&3);
270 wm->accel.y = (msg[3]<<2)|((msg[1]>>4)&2);
271 wm->accel.z = (msg[4]<<2)|((msg[1]>>5)&2);
272 #ifndef GEKKO
273 calculate_orientation(&wm->accel_calib, &wm->accel, &wm->orient, WIIMOTE_IS_FLAG_SET(wm, WIIUSE_SMOOTHING));
274 calculate_gforce(&wm->accel_calib, &wm->accel, &wm->gforce);
275 #endif
276 handle_expansion(wm, msg+5);
277 break;
278 case WM_RPT_BTN_IR_EXP:
279 wiiuse_pressed_buttons(wm,msg);
280 calculate_basic_ir(wm, msg+2);
281 handle_expansion(wm,msg+12);
282 break;
283 case WM_RPT_BTN_ACC_IR_EXP:
284 /* button - motion - ir - expansion */
285 wiiuse_pressed_buttons(wm, msg);
287 wm->accel.x = (msg[2]<<2)|((msg[0]>>5)&3);
288 wm->accel.y = (msg[3]<<2)|((msg[1]>>4)&2);
289 wm->accel.z = (msg[4]<<2)|((msg[1]>>5)&2);
290 #ifndef GEKKO
291 calculate_orientation(&wm->accel_calib, &wm->accel, &wm->orient, WIIMOTE_IS_FLAG_SET(wm, WIIUSE_SMOOTHING));
292 calculate_gforce(&wm->accel_calib, &wm->accel, &wm->gforce);
293 #endif
294 /* ir */
295 calculate_basic_ir(wm, msg+5);
297 handle_expansion(wm, msg+15);
298 break;
299 default:
300 WIIUSE_WARNING("Unknown event, can not handle it [Code 0x%x].", event);
301 return;
304 /* was there an event? */
305 wm->event = WIIUSE_EVENT;
309 * @brief Find what buttons are pressed.
311 * @param wm Pointer to a wiimote_t structure.
312 * @param msg The message specified in the event packet.
314 void wiiuse_pressed_buttons(struct wiimote_t* wm, ubyte* msg) {
315 short now;
317 /* convert to big endian */
318 now = BIG_ENDIAN_SHORT(*(short*)msg) & WIIMOTE_BUTTON_ALL;
320 /* preserve old btns pressed */
321 wm->btns_last = wm->btns;
323 /* pressed now & were pressed, then held */
324 wm->btns_held = (now & wm->btns);
326 /* were pressed or were held & not pressed now, then released */
327 wm->btns_released = ((wm->btns | wm->btns_held) & ~now);
329 /* buttons pressed now */
330 wm->btns = now;