1 /*---------------------------------------------------------------------------*
2   Project:  Game controller utilities
3   File:     cont.c
4 
5   Copyright (C) 2000-2006 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: cont.c,v $
14   Revision 1.2  2006/10/24 12:32:40  yasuh-to
15   Fixed hot plug bug.
16 
17   Revision 1.1  2006/02/02 06:11:49  yasuh-to
18   Initial import
19 
20 
21     8     8/06/01 18:29 Shiki
22     Revised ReadCont().
23 
24     7     01/03/27 13:16 Shiki
25     Fixed ReadCont().
26 
27     6     01/03/23 15:06 Shiki
28     Fixed resetBits handling.
29 
30     5     01/03/22 21:07 Shiki
31     Revised.
32 
33     4     01/03/06 17:18 Shiki
34     Modified InitCont() to support controller recalibration.
35 
36     3     01/03/06 15:51 Shiki
37     Fixed ReadCont() so it can work even if no controller is connected
38     initially.
39 
40     2     11/14/00 3:02p Shiki
41     Fixed MAC build error.
42 
43     1     11/13/00 6:02p Shiki
44     Initial check-in.
45   $NoKeywords: $
46  *---------------------------------------------------------------------------*/
47 
48 #include <stdlib.h>
49 #include <revolution.h>
50 #include "cont.h"
51 
52 Cont Conts[PAD_MAX_CONTROLLERS+1];
53 static int RepeatDelay;
54 static int RepeatRate;
55 static u32 ConnectedBits;
56 
57 /*---------------------------------------------------------------------------*
58   Name:         InitCont
59 
60   Description:  Reinitializes controllers
61 
62   Arguments:    connectBits     Set PAD_CHANn_BIT(s) to try to connect to the
63                                 specified controller ports at every frame no
64                                 matter what.
65                                 Set zero to use controllers that initially
66                                 connected to the controller ports to minimize
67                                 extra processor overhead.
68                 recalibrate     Set TRUE to recalibrate controllers. (Should
69                                 be set TRUE only when the reset button on the
70                                 console is pushed.)
71 
72   Returns:      None.
73  *---------------------------------------------------------------------------*/
InitCont(u32 connectBits,BOOL recalibrate)74 void InitCont(u32 connectBits, BOOL recalibrate)
75 {
76     u32 resetBits;
77 
78     if (VIGetTvFormat() == VI_PAL)
79     {
80         // 50Hz
81         RepeatDelay = 25;
82         RepeatRate  = 5;
83     }
84     else    // VI_NTSC, VI_MPAL
85     {
86         // 60Hz
87         RepeatDelay = 30;
88         RepeatRate  = 6;
89     }
90 
91     ConnectedBits = connectBits;
92     resetBits = PAD_CHAN0_BIT | PAD_CHAN1_BIT |
93                 PAD_CHAN2_BIT | PAD_CHAN3_BIT;
94     if (ConnectedBits)
95     {
96 //        resetBits &= ConnectedBits;
97         resetBits &= ~ConnectedBits;
98     }
99     if (recalibrate)
100     {
101         PADRecalibrate(resetBits);
102     }
103     else
104     {
105         PADReset(resetBits);
106     }
107 }
108 
109 /*---------------------------------------------------------------------------*
110   Name:         ReadCont
111 
112   Description:  Read controllers
113 
114   Arguments:    None.
115 
116   Returns:      None.
117  *---------------------------------------------------------------------------*/
ReadCont(void)118 void ReadCont(void)
119 {
120     PADStatus  pads[PAD_MAX_CONTROLLERS];
121     PADStatus* pad;
122     u32        padBit;
123     int        chan;
124     Cont*      cont;
125     Cont*      contAll;
126     u32        resetBits;
127 
128     PADRead(pads);
129     PADClamp(pads);
130 
131     contAll = &Conts[PAD_MAX_CONTROLLERS];
132     contAll->err = PAD_ERR_NO_CONTROLLER;
133 
134     resetBits = 0;
135     for (chan = 0; chan < PAD_MAX_CONTROLLERS; ++chan)
136     {
137         padBit = PAD_CHAN0_BIT >> chan;
138         switch (pads[chan].err)
139         {
140           case PAD_ERR_NONE:
141             ConnectedBits |= padBit;
142             contAll->err = PAD_ERR_NONE;
143             break;
144           case PAD_ERR_TRANSFER:
145             ConnectedBits |= padBit;
146             if (contAll->err == PAD_ERR_NO_CONTROLLER)
147             {
148                 contAll->err = PAD_ERR_TRANSFER;
149             }
150             break;
151           case PAD_ERR_NO_CONTROLLER:
152             ConnectedBits &= ~padBit;
153             resetBits |= padBit;
154             break;
155           case PAD_ERR_NOT_READY:
156             if (contAll->err == PAD_ERR_NO_CONTROLLER)
157             {
158                 contAll->err = PAD_ERR_NOT_READY;
159             }
160           default:
161             break;
162         }
163     }
164     if (ConnectedBits)
165     {
166         resetBits &= ~ConnectedBits;
167     }
168     if (resetBits)
169     {
170         PADReset(resetBits);
171     }
172 
173     contAll->buttonLast = contAll->button;
174     contAll->button = contAll->down = contAll->up = contAll->repeat = 0;
175     contAll->stickX = contAll->stickY = contAll->substickX = contAll->substickY = 0;
176     contAll->triggerLeft = contAll->triggerRight = 0;
177     contAll->analogA = contAll->analogB = 0;
178 
179     for (chan = 0; chan < PAD_MAX_CONTROLLERS; ++chan)
180     {
181         cont = &Conts[chan];
182         pad = &pads[chan];
183         cont->err = pad->err;
184 
185         cont->buttonLast = cont->button;    // not to generate up/down twice
186         if (cont->err != PAD_ERR_TRANSFER)
187         {
188             cont->button = pad->button;
189             cont->stickX = pad->stickX;
190             cont->stickY = pad->stickY;
191             cont->substickX = pad->substickX;
192             cont->substickY = pad->substickY;
193             cont->triggerLeft  = pad->triggerLeft;
194             cont->triggerRight = pad->triggerRight;
195             cont->analogA = pad->analogA;
196             cont->analogB = pad->analogB;
197         }
198 
199         if (cont->stickX < 0)
200         {
201             cont->button |= PAD_BUTTON_LEFT;
202         }
203         else if (0 < cont->stickX)
204         {
205             cont->button |= PAD_BUTTON_RIGHT;
206         }
207         if (cont->stickY < 0)
208         {
209             cont->button |= PAD_BUTTON_DOWN;
210         }
211         else if (0 < cont->stickY)
212         {
213             cont->button |= PAD_BUTTON_UP;
214         }
215 
216         cont->down = PADButtonDown(cont->buttonLast, cont->button);
217         cont->up   = PADButtonUp(cont->buttonLast, cont->button);
218 
219         cont->repeat = (u16) ((cont->button & cont->buttonLast) &
220                        (PAD_BUTTON_A | PAD_BUTTON_B | PAD_BUTTON_X | PAD_BUTTON_Y |
221                         PAD_TRIGGER_Z | PAD_TRIGGER_R | PAD_TRIGGER_L |
222                         PAD_BUTTON_LEFT | PAD_BUTTON_RIGHT |
223                         PAD_BUTTON_DOWN | PAD_BUTTON_UP |
224                         PAD_BUTTON_START));
225         if (cont->repeat)
226         {
227             ++cont->count;
228             if (cont->count < RepeatDelay)
229             {
230                 cont->repeat = 0;
231             }
232             else if (cont->count % RepeatRate)
233             {
234                 cont->repeat = 0;
235             }
236         }
237         else
238         {
239             cont->count = 0;
240         }
241         cont->repeat |= cont->down;
242 
243         contAll->down   |= cont->down;
244         contAll->up     |= cont->up;
245         contAll->button |= cont->button;
246         contAll->repeat |= cont->repeat;
247 
248         if (abs(contAll->stickX) < abs(cont->stickX))
249         {
250             contAll->stickX = cont->stickX;
251         }
252         if (abs(contAll->stickY) < abs(cont->stickY))
253         {
254             contAll->stickY = cont->stickY;
255         }
256         if (abs(contAll->substickX) < abs(cont->substickX))
257         {
258             contAll->substickX = cont->substickX;
259         }
260         if (abs(contAll->substickY) < abs(cont->substickY))
261         {
262             contAll->substickY = cont->substickY;
263         }
264         if (contAll->triggerLeft < cont->triggerLeft)
265         {
266             contAll->triggerLeft = cont->triggerLeft;
267         }
268         if (contAll->triggerRight < cont->triggerRight)
269         {
270             contAll->triggerRight = cont->triggerRight;
271         }
272         if (contAll->analogA < cont->analogA)
273         {
274             contAll->analogA = cont->analogA;
275         }
276         if (contAll->analogB < cont->analogB)
277         {
278             contAll->analogB = cont->analogB;
279         }
280     }
281 }
282