1 /*---------------------------------------------------------------------------*
2   Project:  Game controller utilities
3   File:     cont.c
4 
5   Copyright 2000-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: cont.c,v $
14   Revision 1.2  02/20/2006 04:13:08  mitu
15   changed include path from dolphin/ to revolution/.
16 
17   Revision 1.1  01/31/2006 10:48:30  mitu
18   (none)
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:00 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:00 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     }
98     if (recalibrate)
99     {
100         PADRecalibrate(resetBits);
101     }
102     else
103     {
104         PADReset(resetBits);
105     }
106 }
107 
108 /*---------------------------------------------------------------------------*
109   Name:         ReadCont
110 
111   Description:  Read controllers
112 
113   Arguments:    None.
114 
115   Returns:      None.
116  *---------------------------------------------------------------------------*/
ReadCont(void)117 void ReadCont(void)
118 {
119     PADStatus  pads[PAD_MAX_CONTROLLERS];
120     PADStatus* pad;
121     u32        padBit;
122     int        chan;
123     Cont*      cont;
124     Cont*      contAll;
125     u32        resetBits;
126 
127     PADRead(pads);
128     PADClamp(pads);
129 
130     contAll = &Conts[PAD_MAX_CONTROLLERS];
131     contAll->err = PAD_ERR_NO_CONTROLLER;
132 
133     resetBits = 0;
134     for (chan = 0; chan < PAD_MAX_CONTROLLERS; ++chan)
135     {
136         padBit = PAD_CHAN0_BIT >> chan;
137         switch (pads[chan].err)
138         {
139           case PAD_ERR_NONE:
140             ConnectedBits |= padBit;
141             contAll->err = PAD_ERR_NONE;
142             break;
143           case PAD_ERR_TRANSFER:
144             ConnectedBits |= padBit;
145             if (contAll->err == PAD_ERR_NO_CONTROLLER)
146             {
147                 contAll->err = PAD_ERR_TRANSFER;
148             }
149             break;
150           case PAD_ERR_NO_CONTROLLER:
151             resetBits |= padBit;
152             break;
153           case PAD_ERR_NOT_READY:
154             if (contAll->err == PAD_ERR_NO_CONTROLLER)
155             {
156                 contAll->err = PAD_ERR_NOT_READY;
157             }
158           default:
159             break;
160         }
161     }
162     if (ConnectedBits)
163     {
164         resetBits &= ConnectedBits;
165     }
166     if (resetBits)
167     {
168         PADReset(resetBits);
169     }
170 
171     contAll->buttonLast = contAll->button;
172     contAll->button = contAll->down = contAll->up = contAll->repeat = 0;
173     contAll->stickX = contAll->stickY = contAll->substickX = contAll->substickY = 0;
174     contAll->triggerLeft = contAll->triggerRight = 0;
175     contAll->analogA = contAll->analogB = 0;
176 
177     for (chan = 0; chan < PAD_MAX_CONTROLLERS; ++chan)
178     {
179         cont = &Conts[chan];
180         pad = &pads[chan];
181         cont->err = pad->err;
182 
183         cont->buttonLast = cont->button;    // not to generate up/down twice
184         if (cont->err != PAD_ERR_TRANSFER)
185         {
186             cont->button = pad->button;
187             cont->stickX = pad->stickX;
188             cont->stickY = pad->stickY;
189             cont->substickX = pad->substickX;
190             cont->substickY = pad->substickY;
191             cont->triggerLeft  = pad->triggerLeft;
192             cont->triggerRight = pad->triggerRight;
193             cont->analogA = pad->analogA;
194             cont->analogB = pad->analogB;
195         }
196 
197         if (cont->stickX < 0)
198         {
199             cont->button |= PAD_BUTTON_LEFT;
200         }
201         else if (0 < cont->stickX)
202         {
203             cont->button |= PAD_BUTTON_RIGHT;
204         }
205         if (cont->stickY < 0)
206         {
207             cont->button |= PAD_BUTTON_DOWN;
208         }
209         else if (0 < cont->stickY)
210         {
211             cont->button |= PAD_BUTTON_UP;
212         }
213 
214         cont->down = PADButtonDown(cont->buttonLast, cont->button);
215         cont->up   = PADButtonUp(cont->buttonLast, cont->button);
216 
217         cont->repeat = (u16) ((cont->button & cont->buttonLast) &
218                        (PAD_BUTTON_A | PAD_BUTTON_B | PAD_BUTTON_X | PAD_BUTTON_Y |
219                         PAD_TRIGGER_Z | PAD_TRIGGER_R | PAD_TRIGGER_L |
220                         PAD_BUTTON_LEFT | PAD_BUTTON_RIGHT |
221                         PAD_BUTTON_DOWN | PAD_BUTTON_UP |
222                         PAD_BUTTON_START));
223         if (cont->repeat)
224         {
225             ++cont->count;
226             if (cont->count < RepeatDelay)
227             {
228                 cont->repeat = 0;
229             }
230             else if (cont->count % RepeatRate)
231             {
232                 cont->repeat = 0;
233             }
234         }
235         else
236         {
237             cont->count = 0;
238         }
239         cont->repeat |= cont->down;
240 
241         contAll->down   |= cont->down;
242         contAll->up     |= cont->up;
243         contAll->button |= cont->button;
244         contAll->repeat |= cont->repeat;
245 
246         if (abs(contAll->stickX) < abs(cont->stickX))
247         {
248             contAll->stickX = cont->stickX;
249         }
250         if (abs(contAll->stickY) < abs(cont->stickY))
251         {
252             contAll->stickY = cont->stickY;
253         }
254         if (abs(contAll->substickX) < abs(cont->substickX))
255         {
256             contAll->substickX = cont->substickX;
257         }
258         if (abs(contAll->substickY) < abs(cont->substickY))
259         {
260             contAll->substickY = cont->substickY;
261         }
262         if (contAll->triggerLeft < cont->triggerLeft)
263         {
264             contAll->triggerLeft = cont->triggerLeft;
265         }
266         if (contAll->triggerRight < cont->triggerRight)
267         {
268             contAll->triggerRight = cont->triggerRight;
269         }
270         if (contAll->analogA < cont->analogA)
271         {
272             contAll->analogA = cont->analogA;
273         }
274         if (contAll->analogB < cont->analogB)
275         {
276             contAll->analogB = cont->analogB;
277         }
278     }
279 }
280