1 /*---------------------------------------------------------------------------*
2 Project: Dolphin Demo Library
3 File: DEMOPad.c
4
5 Copyright 1998-2001 Nintendo. All rights reserved.
6
7 These coded instructions, statements, and computer programs contain
8 proprietary information of Nintendo of America Inc. and/or Nintendo
9 Company Ltd., and are protected by Federal copyright law. They may
10 not be disclosed to third parties or copied or duplicated in any form,
11 in whole or in part, without the prior written consent of Nintendo.
12
13 $Log: DEMOPad.c,v $
14 Revision 1.2 2006/02/20 04:37:44 mitu
15 Changed include path from dolphin/ to revolution/.
16
17 Revision 1.1.1.1 2005/05/12 02:15:48 yasuh-to
18 transitioned from the Dolphin source tree
19
20
21 10 2001/08/09 9:47 Shiki
22 Fixed to clear pad delta status if PAD_ERR_TRANSFER is occurred.
23
24 9 2001/03/27 13:21 Shiki
25 Detabbed.
26
27 8 2001/03/23 6:06p Yasu
28 Change commented code to introduce pad-queue.
29
30 7 2001/03/22 21:44 Shiki
31 Fixed DEMOPadRead() to conform to GameCube controller spec.
32 Also refer to '/Dolphin/build/demos/paddemo/src/cont.c'.
33
34 6 2001/02/14 1:48a Hirose
35 Deleted first call check for DEMOPadInit( ).
36 Now PadInit( ) can be called more than once.
37
38 5 2000/10/27 3:47p Hirose
39 fixed build flags
40
41 4 2000/06/12 4:39p Hirose
42 reconstructed structure and interface
43
44 3 2000/04/26 4:59p Carl
45 CallBack -> Callback
46
47 2 2000/03/25 12:50a Hirose
48 added some portion from cmn-pad.c
49 added pad connection check
50
51 1 3/23/00 1:21a Hirose
52 Initial version
53
54 $NoKeywords: $
55 *---------------------------------------------------------------------------*/
56
57 #include <revolution.h>
58 #include <demo.h>
59
60 /*---------------------------------------------------------------------------*
61 Global Variables
62 *---------------------------------------------------------------------------*/
63 DEMOPadStatus DemoPad[PAD_MAX_CONTROLLERS];
64 u32 DemoNumValidPads;
65
66 /*---------------------------------------------------------------------------*
67 Local Variables
68 *---------------------------------------------------------------------------*/
69 static PADStatus Pad[PAD_MAX_CONTROLLERS]; // internal use only
70
71 /*---------------------------------------------------------------------------*/
72 static u32 PadChanMask[PAD_MAX_CONTROLLERS] =
73 {
74 PAD_CHAN0_BIT, PAD_CHAN1_BIT, PAD_CHAN2_BIT, PAD_CHAN3_BIT
75 };
76
77 /*---------------------------------------------------------------------------*
78 Name: DEMOPadCopy
79
80 Description: This function copies information of PADStatus into
81 DEMOPadStatus structure. Also attaches some extra
82 information such as down/up, stick direction.
83 This function is internal use only.
84
85 Keeps previous state if PAD_ERR_TRANSFER is returned.
86
87 Arguments: pad : copy source. (PADStatus)
88 dmpad : copy destination. (DEMOPadStatus)
89
90 Returns: None
91 *---------------------------------------------------------------------------*/
DEMOPadCopy(PADStatus * pad,DEMOPadStatus * dmpad)92 static void DEMOPadCopy( PADStatus* pad, DEMOPadStatus* dmpad )
93 {
94 u16 dirs;
95
96 if ( pad->err != PAD_ERR_TRANSFER )
97 {
98 // Detects which direction is the stick(s) pointing.
99 // This can be used when we want to use a stick as direction pad.
100 dirs = 0;
101 if ( pad->stickX < - DEMO_STICK_THRESHOLD )
102 dirs |= DEMO_STICK_LEFT;
103 if ( pad->stickX > DEMO_STICK_THRESHOLD )
104 dirs |= DEMO_STICK_RIGHT;
105 if ( pad->stickY < - DEMO_STICK_THRESHOLD )
106 dirs |= DEMO_STICK_DOWN;
107 if ( pad->stickY > DEMO_STICK_THRESHOLD )
108 dirs |= DEMO_STICK_UP;
109 if ( pad->substickX < - DEMO_STICK_THRESHOLD )
110 dirs |= DEMO_SUBSTICK_LEFT;
111 if ( pad->substickX > DEMO_STICK_THRESHOLD )
112 dirs |= DEMO_SUBSTICK_RIGHT;
113 if ( pad->substickY < - DEMO_STICK_THRESHOLD )
114 dirs |= DEMO_SUBSTICK_DOWN;
115 if ( pad->substickY > DEMO_STICK_THRESHOLD )
116 dirs |= DEMO_SUBSTICK_UP;
117
118 // Get the direction newly detected / released
119 dmpad->dirsNew = PADButtonDown(dmpad->dirs, dirs);
120 dmpad->dirsReleased = PADButtonUp(dmpad->dirs, dirs);
121 dmpad->dirs = dirs;
122
123 // Get DOWN/UP status of all buttons
124 dmpad->buttonDown = PADButtonDown(dmpad->pst.button, pad->button);
125 dmpad->buttonUp = PADButtonUp(dmpad->pst.button, pad->button);
126
127 // Get delta of analogs
128 dmpad->stickDeltaX = (s16)(pad->stickX - dmpad->pst.stickX);
129 dmpad->stickDeltaY = (s16)(pad->stickY - dmpad->pst.stickY);
130 dmpad->substickDeltaX = (s16)(pad->substickX - dmpad->pst.substickX);
131 dmpad->substickDeltaY = (s16)(pad->substickY - dmpad->pst.substickY);
132
133 // Copy current status into DEMOPadStatus field
134 dmpad->pst = *pad;
135 }
136 else
137 {
138 // Get the direction newly detected / released
139 dmpad->dirsNew = dmpad->dirsReleased = 0;
140
141 // Get DOWN/UP status of all buttons
142 dmpad->buttonDown = dmpad->buttonUp = 0;
143
144 // Get delta of analogs
145 dmpad->stickDeltaX = dmpad->stickDeltaY = 0;
146 dmpad->substickDeltaX = dmpad->substickDeltaY = 0;
147 }
148 }
149
150 /*---------------------------------------------------------------------------*
151 Name: DEMOPadRead
152
153 Description: Calls PADRead() and perform clamping. Get information
154 of button down/up and sets them into extended field.
155 This function also checks whether controllers are
156 actually connected.
157
158 Arguments: None
159
160 Returns: None
161 *---------------------------------------------------------------------------*/
DEMOPadRead(void)162 void DEMOPadRead( void )
163 {
164 s32 i;
165 u32 ResetReq = 0; // for error handling
166
167 // Read current PAD status
168 PADRead( Pad );
169
170 // Clamp analog inputs
171 PADClamp( Pad );
172
173 DemoNumValidPads = 0;
174 for ( i = 0 ; i < PAD_MAX_CONTROLLERS ; i++ )
175 {
176 // Connection check
177 if ( Pad[i].err == PAD_ERR_NONE ||
178 Pad[i].err == PAD_ERR_TRANSFER )
179 {
180 ++DemoNumValidPads;
181 }
182 else if ( Pad[i].err == PAD_ERR_NO_CONTROLLER )
183 {
184 ResetReq |= PadChanMask[i];
185 }
186
187 DEMOPadCopy( &Pad[i], &DemoPad[i] );
188 }
189
190 // Try resetting pad channels which have been not valid
191 if ( ResetReq )
192 {
193 // Don't care return status
194 // If FALSE, then reset again in next DEMOPadRead.
195 PADReset( ResetReq );
196 }
197
198 return;
199 }
200
201 /*---------------------------------------------------------------------------*
202 Name: DEMOPadInit
203
204 Description: Initialize PAD library and exported status
205
206 Arguments: None
207
208 Returns: None
209 *---------------------------------------------------------------------------*/
DEMOPadInit(void)210 void DEMOPadInit( void )
211 {
212 s32 i;
213
214 // Initialize pad interface
215 PADInit();
216
217 // Reset exported pad status
218 for ( i = 0 ; i < PAD_MAX_CONTROLLERS ; i++ )
219 {
220 DemoPad[i].pst.button = 0;
221 DemoPad[i].pst.stickX = 0;
222 DemoPad[i].pst.stickY = 0;
223 DemoPad[i].pst.substickX = 0;
224 DemoPad[i].pst.substickY = 0;
225 DemoPad[i].pst.triggerLeft = 0;
226 DemoPad[i].pst.triggerRight = 0;
227 DemoPad[i].pst.analogA = 0;
228 DemoPad[i].pst.analogB = 0;
229 DemoPad[i].pst.err = 0;
230 DemoPad[i].buttonDown = 0;
231 DemoPad[i].buttonUp = 0;
232 DemoPad[i].dirs = 0;
233 DemoPad[i].dirsNew = 0;
234 DemoPad[i].dirsReleased = 0;
235 DemoPad[i].stickDeltaX = 0;
236 DemoPad[i].stickDeltaY = 0;
237 DemoPad[i].substickDeltaX = 0;
238 DemoPad[i].substickDeltaY = 0;
239 }
240
241 }
242
243 #if 0 // Currently this stuff is not used.
244 //============================================================================
245 // PAD-QUEUE Functions: NOW WORKS
246 //
247 // This set of functions helps the game engine with constant animation
248 // rate.
249 //
250 // [Sample Code]
251 //
252 // BOOL isRetraced;
253 // while ( !gameDone )
254 // {
255 // do
256 // {
257 // isQueued = DEMOPadQueueRead( OS_MESSAGE_BLOCK );
258 // Do_animation( );
259 // }
260 // while ( isQueued );
261 //
262 // Do_rendering( );
263 // }
264 //
265
266 //============================================================================
267 #define DEMO_PADQ_DEPTH 8
268
269 void DEMOPadQueueInit ( void );
270 BOOL DEMOPadQueueRead ( s32 );
271 void DEMOPadQueueFlush ( void );
272
273 static PADStatus PadQueue[DEMO_PADQ_DEPTH][PAD_MAX_CONTROLLERS];
274 static OSMessageQueue PadValidMsgQ;
275 static OSMessage PadValidMsg[DEMO_PADQ_DEPTH];
276 static OSMessageQueue PadEmptyMsgQ;
277 static OSMessage PadEmptyMsg[DEMO_PADQ_DEPTH];
278
279 /*---------------------------------------------------------------------------*
280 Name: DEMOPadViCallback
281 Description: This function should be called once every frame.
282 Arguments: None
283 Returns: None
284 *---------------------------------------------------------------------------*/
285 static void DEMOPadViCallback( u32 retraceCount )
286 {
287 #pragma unused (retraceCount)
288
289 PADStatus *padContainer;
290 #ifdef _DEBUG
291 static BOOL caution = FALSE;
292 #endif
293
294 // Get empty container.
295 if ( OSReceiveMessage( &PadEmptyMsgQ,
296 (OSMessage *)&padContainer, OS_MESSAGE_NOBLOCK ) )
297 {
298 // Read the latest pad status into pad container
299 PADRead( padContainer );
300
301 // Send result as message
302 if ( !OSSendMessage( &PadValidMsgQ,
303 (OSMessage)padContainer, OS_MESSAGE_NOBLOCK ) )
304 {
305 // The valid queue never be full.
306 ASSERTMSG( 0, "Logical Error: Valid QUEUE is full." );
307 }
308 #ifdef _DEBUG
309 caution = FALSE;
310 #endif
311 }
312 else
313 {
314 #ifdef _DEBUG
315 ASSERTMSG( caution, "Pad Queue is full." );
316 caution = TRUE;
317 #endif
318 }
319
320 return;
321 }
322
323 /*---------------------------------------------------------------------------*
324 Name: DEMOPadQueueRead
325 Description: Read gamepad state and set to DemoPad[].
326 No need to care controller error.
327 (When error, PADState is set to zero in PADRead.)
328 Arguments: s32 flag: control block/noblock mode.
329 when flag == OS_MESSAGE_BLOCK,
330 wait next padinput if queue is empty.
331 when flag == OS_MESSAGE_NOBLOCK,
332 return immediately if queue is empty.
333
334 Returns: BOOL: FALSE if queue was empty.
335 TRUE if get queued data.
336 *---------------------------------------------------------------------------*/
337 BOOL DEMOPadQueueRead( s32 flag )
338 {
339 PADStatus *padContainer;
340 BOOL isQueued;
341 u32 i;
342
343 // Get pad data from valid data queue
344 isQueued = OSReceiveMessage( &PadValidMsgQ,
345 (OSMessage *)&padContainer, OS_MESSAGE_NOBLOCK );
346
347 // If queue is empty, wait and sleep until coming pad input on v-retrace
348 if ( !isQueued )
349 {
350 if ( flag == OS_MESSAGE_BLOCK )
351 {
352 OSReceiveMessage( &PadValidMsgQ,
353 (OSMessage *)&padContainer, OS_MESSAGE_BLOCK );
354 }
355 else
356 {
357 return FALSE;
358 }
359 }
360
361 // Copy status to DemoPad
362 for ( i = 0 ; i < PAD_MAX_CONTROLLERS ; i ++ )
363 {
364 DEMOPadCopy( &padContainer[i], &DemoPad[i] );
365 }
366
367 // Release pad container
368 if ( !OSSendMessage( &PadEmptyMsgQ,
369 (OSMessage)padContainer, OS_MESSAGE_NOBLOCK ) )
370 {
371 // The valid queue never be full.
372 ASSERTMSG( 0, "Logical Error: Empty QUEUE is full." );
373 }
374
375 return isQueued;
376 }
377
378 /*---------------------------------------------------------------------------*
379 Name: DEMOPadQueueFlush
380 Description: Flush Pad-Queue
381 Arguments: None
382 Returns: None
383 *---------------------------------------------------------------------------*/
384 void DEMOPadQueueFlush( void )
385 {
386 OSMessage msg;
387
388 while ( OSReceiveMessage( &PadValidMsgQ, &msg, OS_MESSAGE_NOBLOCK ) )
389 {
390 OSSendMessage( &PadEmptyMsgQ, msg, OS_MESSAGE_BLOCK );
391 }
392
393 return;
394 }
395
396 /*---------------------------------------------------------------------------*
397 Name: DEMOPadQueueInit
398 Description: Initialize Pad-Queue utility routines
399 Arguments: None
400 Returns: None
401 *---------------------------------------------------------------------------*/
402 void DEMOPadQueueInit( void )
403 {
404 u32 i;
405
406 // Initialize basic pad function
407 DEMOPadInit();
408
409 OSInitMessageQueue( &PadValidMsgQ, &PadValidMsg[0], DEMO_PADQ_DEPTH );
410 OSInitMessageQueue( &PadEmptyMsgQ, &PadEmptyMsg[0], DEMO_PADQ_DEPTH );
411
412 // Entry pad container
413 for ( i = 0; i < DEMO_PADQ_DEPTH; i ++ )
414 {
415 if ( !OSSendMessage( &PadEmptyMsgQ,
416 (OSMessage)&PadQueue[i][0], OS_MESSAGE_NOBLOCK ) )
417 {
418 ASSERTMSG( 0, "Logical Error: Send Message." );
419 }
420 }
421
422 // Reset pad queue and initialize pad HW
423 DEMOPadQueueFlush();
424
425 // Register vi Callback function
426 VISetPostRetraceCallback( DEMOPadViCallback );
427
428 return;
429 }
430 /*---------------------------------------------------------------------------*/
431 #endif // 0
432
433
434 /*===========================================================================*/
435