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