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