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