This repository has been archived by the owner on Mar 11, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathJoystick.c
236 lines (217 loc) · 7.08 KB
/
Joystick.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
#include "Joystick.h"
#include "Descriptors.h"
#include <LUFA/Drivers/USB/USB.h>
#include <stdbool.h>
#include <stdint.h>
typedef enum {
Y = 0x01,
B = 0x02,
A = 0x04,
X = 0x08,
L = 0x10,
R = 0x20,
ZL = 0x40,
ZR = 0x80,
MINUS = 0x100,
PLUS = 0x200,
LCLICK = 0x400,
RCLICK = 0x800,
HOME = 0x1000,
CAPTURE = 0x2000,
} Button_t;
typedef enum {
HAT_TOP = 0x00,
HAT_TOP_RIGHT = 0x01,
HAT_RIGHT = 0x02,
HAT_BOTTOM_RIGHT = 0x03,
HAT_BOTTOM = 0x04,
HAT_BOTTOM_LEFT = 0x05,
HAT_LEFT = 0x06,
HAT_TOP_LEFT = 0x07,
HAT_CENTER = 0x08,
} Hat_t;
typedef struct __attribute__((packed)) {
uint16_t Button;
uint8_t Hat;
uint8_t LX, LY, RX, RY;
uint8_t VendorSpec;
} Report_t;
static Report_t PrevReport;
USB_ClassInfo_HID_Device_t Joystick_Interface = {
.Config = {
.InterfaceNumber = INTERFACE_ID_Joystick,
.ReportINEndpoint = {
.Address = JOYSTICK_IN_EPADDR,
.Size = JOYSTICK_EPSIZE,
.Banks = 1,
},
.PrevReportINBuffer = &PrevReport,
.PrevReportINBufferSize = sizeof PrevReport,
},
};
typedef struct {
enum {
ACTION_NONE,
ACTION_BUTTON,
ACTION_MOVE,
ACTION_VIEW,
} Type;
union {
uint16_t Button;
struct {
uint8_t X, Y;
};
uint16_t Index;
};
uint16_t Repeat;
} Action_t;
#define NOTHING .Type = ACTION_NONE
#define BUTTON(x) .Type = ACTION_BUTTON, .Button = (x)
#define MOVE(x,y) .Type = ACTION_MOVE, .X = (x), .Y = (y)
#define VIEW(x,y) .Type = ACTION_VIEW, .X = (x), .Y = (y)
#define REPEAT(x) .Repeat = (x)
#define DELAY(x) NOTHING, REPEAT(x)
static uint8_t Index = 0;
static uint16_t Repeat = 0;
#define Finish() _Finish(Report, Sequence, sizeof (Sequence) / sizeof (Sequence)[0])
static bool _Finish(Report_t *Report, const Action_t *Sequence, uint16_t SequenceSize)
{
const Action_t *Action = &Sequence[Index];
// dispatch
switch (Action->Type)
{
case ACTION_BUTTON:
Report->Button = Action->Button;
break;
case ACTION_MOVE:
Report->LX = Action->X;
Report->LY = Action->Y;
break;
case ACTION_VIEW:
Report->RX = Action->X;
Report->RY = Action->Y;
break;
default:
break;
}
// advance
if (++Repeat >= Action->Repeat)
{
Repeat = 0;
if (++Index >= SequenceSize)
{
Index = 0;
return true;
}
}
return false;
}
bool CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const _unused,
uint8_t* const ReportID,
const uint8_t ReportType,
void* ReportData,
uint16_t* const ReportSize)
{
Report_t* Report = (Report_t*)ReportData;
*ReportSize = sizeof(*Report);
// initialize report
Report->Button = 0;
Report->Hat = HAT_CENTER;
Report->LX = 0x80;
Report->LY = 0x80;
Report->RX = 0x80;
Report->RY = 0x80;
Report->VendorSpec = 0;
// state machine
static enum {
INIT,
TEST,
DONE,
} State = INIT;
switch (State)
{
case INIT:
{
static const Action_t Sequence[] = {
{ BUTTON(B) }, // (new controller)
{ NOTHING },
{ BUTTON(B) },
{ DELAY(1000) }, // (UI pop-up)
{ BUTTON(B) }, // (select controller)
{ NOTHING },
{ BUTTON(A) }, // Press A when you're ready
{ DELAY(1200) }, // (return to game)
};
if (Finish())
{
State = TEST;
}
break;
}
case TEST:
{
static const Action_t Sequence[] = {
{ BUTTON(A) }, // Talk
{ DELAY( 421) },
{ BUTTON(B) }, // (skip) Hallooooo, kiddums! If you wanted to try a round of Snowball Bowling, then you're in luck, because this is the place!
{ DELAY( 385) },
{ BUTTON(A) }, // I'll try it!
{ DELAY( 257) },
{ BUTTON(B) }, // (skip) Ah, the sweet music of "yes"! There's a catch, though. One game costs a cool 20 rupees to play. Still up for a round?
{ DELAY( 385) },
{ BUTTON(A) }, // OK!
{ DELAY( 257) },
{ BUTTON(B) }, // (skip) Aha! Play bells are ringing! I gotta set up the pins, but I'll be back in a flurry.
{ BUTTON(A) }, // (continue)
{ DELAY(7900) }, // (loading)
{ BUTTON(B) }, // (skip) This is the snowball you'll use. It might not look like much, but it's snow joke. You get two rolls. Knock 'em flat!
{ BUTTON(A) }, // (continue)
{ DELAY(1153) },
{ BUTTON(B) }, // (skip) If you can knock over all 10 pins in one roll, that's a strike. Only the most snowtorious bowlers can pull that off!
{ BUTTON(A) }, // (continue)
{ DELAY( 257) },
{ BUTTON(B) }, // (skip) A spare is when it takes both tries to finish the job. Not as good as a strike, but nothing to sneeze at!
{ BUTTON(A) }, // (continue)
{ DELAY( 385) },
{ BUTTON(B) }, // (skip) Well, good luck!
{ BUTTON(A) }, // (continue)
{ DELAY( 500) },
{ MOVE(0x00,0x80), REPEAT(200) },
{ DELAY(500) },
{ BUTTON(A) }, // Pick up
{ DELAY(1000) },
{ MOVE(0xA0,0x00), REPEAT(1500) },
{ MOVE(0x87,0x00), REPEAT( 500) },
// { MOVE(0xFF,0x00), REPEAT( 500) }, // always fail
// { VIEW(0x80,0xFF), REPEAT( 500) }, // DEBUG
{ BUTTON(A) }, // Put down
{ DELAY(15000) },
{ BUTTON(A) },
{ DELAY(1000) },
{ BUTTON(A) },
{ DELAY(10000) },
{ BUTTON(A) },
{ DELAY(1000) },
{ MOVE(0xFF,0x90), REPEAT(1200) }, // move to talk to Pondo
{ BUTTON(A) }, // ack / talk
{ DELAY(4000) },
{ BUTTON(A) }, // question(A)
{ DELAY(5000) },
{ BUTTON(B) }, // question(B) / ack
{ DELAY(4000) },
{ BUTTON(A) }, // ack / question(A)
{ DELAY(8000) },
};
if (Finish())
{
// State = DONE;
}
break;
}
default:
{
break;
}
}
return false;
}