forked from kolrabi/steamcontroller
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsteamcontroller_setup.c
245 lines (194 loc) · 9.4 KB
/
steamcontroller_setup.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
237
238
239
240
241
242
243
244
245
#include "include/sc.h"
#include "common.h"
void Debug_DumpHex(const void *pData, size_t count) {
const uint8_t *data = (const uint8_t *)pData;
const uint8_t *line = data;
for (size_t i=0; i<count; i++) {
fprintf(stderr, "%02x ", data[i]);
if ((i % 0x10) == 0xF) {
fprintf(stderr, " ");
for (size_t j=0; j<16; j++) {
if (line[j]>31 && line[j]<0x80)
fprintf(stderr, "%c", line[j]);
else
fprintf(stderr, ".");
}
fprintf(stderr, "\n");
line = data+i+1;
}
}
fprintf(stderr, "\n");
}
/** Set up the controller to be usable. */
bool SteamController_Initialize(const SteamControllerDevice *pDevice) {
if (!pDevice) {
return false;
}
SteamController_HIDFeatureReport featureReport;
if (SteamController_IsWirelessDongle(pDevice)) {
memset(&featureReport, 0, sizeof(featureReport));
featureReport.featureId = 0;
SteamController_HIDGetFeatureReport(pDevice, &featureReport);
// Not really sure why the controller needs entropy. Maybe the it is used
// to avoid collision of RF transmissions.
memset(&featureReport, 0, sizeof(featureReport));
featureReport.featureId = STEAMCONTROLLER_SET_PRNG_ENTROPY;
featureReport.dataLen = 16;
for (uint8_t i=0; i<16; i++)
featureReport.data[i] = (uint8_t)rand(); // FIXME
if (!SteamController_HIDSetFeatureReport(pDevice, &featureReport)) {
fprintf(stderr, "SET_PRNG_ENTROPY failed for controller %p\n", pDevice);
return false;
}
// TODO: Find out what this does.
memset(&featureReport, 0, sizeof(featureReport));
featureReport.featureId = STEAMCONTROLLER_UNKNOWN_B1;
featureReport.dataLen = 2;
SteamController_HIDSetFeatureReport(pDevice, &featureReport);
// TODO: Is this neccessary? The results are not used.
memset(&featureReport, 0, sizeof(featureReport));
featureReport.featureId = STEAMCONTROLLER_DONGLE_GET_WIRELESS_STATE;
SteamController_HIDGetFeatureReport(pDevice, &featureReport);
}
// TODO: Is this neccessary? What could these attributes mean? The only
// value ever observed for this is 0.
memset(&featureReport, 0, sizeof(featureReport));
featureReport.featureId = STEAMCONTROLLER_GET_ATTRIBUTES;
if (!SteamController_HIDGetFeatureReport(pDevice, &featureReport)) {
fprintf(stderr, "Failed to get GET_ATTRIBUTES response for controller %p\n", pDevice);
return false;
}
if (featureReport.dataLen < 4) {
fprintf(stderr, "Bad GET_ATTRIBUTES response for controller %p\n", pDevice);
// Don't fail, the controller still works without.
// return false;
}
/*
example data:
0000 83 23 00 00 00 00 00 01 02 11 00 00 02 03 00 00
0010 00 0a 6d 92 d2 55 04 01 8c c7 56 05 6c 4a 42 56
0020 09 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0011 or 0x0021?: board revision (=10)
0x0012: uint32 = Bootloader revision (unix timestamp)
0x0017: uint32 = Controller firmware revision (unix timestamp)
0x001b: uint32 = Radio firmware revision (unix timestamp)
*/
memset(&featureReport, 0, sizeof(featureReport));
featureReport.featureId = STEAMCONTROLLER_CLEAR_MAPPINGS;
if (!SteamController_HIDSetFeatureReport(pDevice, &featureReport)) {
fprintf(stderr, "CLEAR_MAPPINGS failed for controller %p\n", pDevice);
return false;
}
// TODO: Find out more about the chip id.
memset(&featureReport, 0, sizeof(featureReport));
featureReport.featureId = STEAMCONTROLLER_GET_CHIPID;
if (!SteamController_HIDGetFeatureReport(pDevice, &featureReport)) {
fprintf(stderr, "GET_CHIPID failed for controller %p\n", pDevice);
return false;
}
// TODO: Neccessary? Maybe remove like the other boot loaded stuff.
memset(&featureReport, 0, sizeof(featureReport));
featureReport.featureId = STEAMCONTROLLER_DONGLE_GET_VERSION;
if (!SteamController_HIDGetFeatureReport(pDevice, &featureReport)) {
fprintf(stderr, "DONGLE_GET_VERSION failed for controller %p\n", pDevice);
return false;
}
return true;
}
/** Add a settings parameter and value to an SET_SETTINGS feature report. */
static inline void SteamController_FeatureReportAddSetting(SteamController_HIDFeatureReport *featureReport, uint8_t setting, uint16_t value) {
uint8_t offset = featureReport->dataLen;
featureReport->data[offset] = setting;
StoreU16(featureReport->data + offset + 1, value);
featureReport->dataLen += 3;
}
/** Enable or disable specific controller features. */
bool SCAPI SteamController_Configure(const SteamControllerDevice *pDevice, unsigned configFlags) {
SteamController_HIDFeatureReport featureReport;
// observed sequence when changing from desktop to steam:
// 87 15 325802 180000 310200 080700 070700 300000 2e0000 0000000000000000000000000000000000000000000000000000000000000000000000000000000000
memset(&featureReport, 0, sizeof(featureReport));
featureReport.featureId = STEAMCONTROLLER_SET_SETTINGS;
SteamController_FeatureReportAddSetting(&featureReport, 0x32, 300); // 0x012c seconds to controller shutdown
//SteamController_FeatureReportAddSetting(&featureReport, 0x03, 0x2d); // 0x2d, unknown
SteamController_FeatureReportAddSetting(&featureReport, 0x05, (configFlags & STEAMCONTROLLER_CONFIG_RIGHT_PAD_HAPTIC_TOUCH) ? 1 : 0);
SteamController_FeatureReportAddSetting(&featureReport, 0x07, (configFlags & STEAMCONTROLLER_CONFIG_STICK_HAPTIC) ? 0 : 7);
SteamController_FeatureReportAddSetting(&featureReport, 0x08, (configFlags & STEAMCONTROLLER_CONFIG_RIGHT_PAD_HAPTIC_TRACKBALL) ? 0 : 7);
SteamController_FeatureReportAddSetting(&featureReport, 0x18, 0x00); // 0x00, unknown
SteamController_FeatureReportAddSetting(&featureReport, 0x2d, 100); // home button brightness, default to 100
SteamController_FeatureReportAddSetting(&featureReport, 0x2e, 0x00); // 0x00, unknown
SteamController_FeatureReportAddSetting(&featureReport, 0x2f, 0x01); // 0x01, unknown
SteamController_FeatureReportAddSetting(&featureReport, 0x30, (configFlags & 31));
SteamController_FeatureReportAddSetting(&featureReport, 0x31, (configFlags & STEAMCONTROLLER_CONFIG_SEND_BATTERY_STATUS) ? 2 : 0);
if (!SteamController_HIDSetFeatureReport(pDevice, &featureReport)) {
fprintf(stderr, "SET_SETTINGS failed for controller %p\n", pDevice);
return false;
}
//memset(&featureReport, 0, sizeof(featureReport));
//featureReport.featureId = STEAMCONTROLLER_GET_ATTRIBUTES;
//if (!SteamController_HIDGetFeatureReport(pDevice, &featureReport)) {
// fprintf(stderr, "Failed to get GET_ATTRIBUTES response for controller %p\n", pDevice);
// return false;
//}
return true;
}
/** Set the brightness of the home button in percent (0-100). */
bool SCAPI SteamController_SetHomeButtonBrightness(const SteamControllerDevice *pDevice, uint8_t brightness) {
SteamController_HIDFeatureReport featureReport;
memset(&featureReport, 0, sizeof(featureReport));
featureReport.featureId = STEAMCONTROLLER_SET_SETTINGS;
SteamController_FeatureReportAddSetting(&featureReport, 0x2d, brightness);
if (!SteamController_HIDSetFeatureReport(pDevice, &featureReport)) {
fprintf(stderr, "SET_SETTINGS failed for controller %p\n", pDevice);
return false;
}
return true;
}
/** Set the timeout in seconds for turning off automatically when not in use. */
bool SCAPI SteamController_SetTimeOut(const SteamControllerDevice *pDevice, uint16_t timeout) {
SteamController_HIDFeatureReport featureReport;
memset(&featureReport, 0, sizeof(featureReport));
featureReport.featureId = STEAMCONTROLLER_SET_SETTINGS;
SteamController_FeatureReportAddSetting(&featureReport, 0x32, timeout);
if (!SteamController_HIDSetFeatureReport(pDevice, &featureReport)) {
fprintf(stderr, "SET_SETTINGS failed for controller %p\n", pDevice);
return false;
}
return true;
}
/** Turn off the controller (the configured melody will be played). */
bool SCAPI SteamController_TurnOff(const SteamControllerDevice *pDevice) {
if (!pDevice)
return false;
SteamController_HIDFeatureReport featureReport;
memset(&featureReport, 0, sizeof(featureReport));
featureReport.featureId = STEAMCONTROLLER_TURN_OFF_CONTROLLER;
featureReport.dataLen = 4;
memcpy(featureReport.data, "off!", 4);
return SteamController_HIDSetFeatureReport(pDevice, &featureReport);
}
/** Store the startup and shutdown melody in the controller's EEPROM. */
void SCAPI SteamController_SaveMelodies(const SteamControllerDevice *pDevice, uint8_t startupMelody, uint8_t shutdownMelody) {
SteamController_HIDFeatureReport featureReport;
memset(&featureReport, 0, sizeof(featureReport));
featureReport.featureId = STEAMCONTROLLER_WRITE_EEPROM;
featureReport.dataLen = 0x10;
featureReport.data[0] = startupMelody;
featureReport.data[1] = shutdownMelody;
featureReport.data[2] = 0xff; // sometimes 0x06
featureReport.data[3] = 0xff;
featureReport.data[4] = 0x03; // 0x03 TODO: Find out what these mean. There should be a setting in Steam that changes these.
featureReport.data[5] = 0x09; // 0x09
featureReport.data[6] = 0x05; // 0x05
featureReport.data[7] = 0xff;
featureReport.data[8] = 0xff;
featureReport.data[9] = 0xff;
featureReport.data[10] = 0xff;
featureReport.data[11] = 0xff;
featureReport.data[12] = 0xff;
featureReport.data[13] = 0xff;
featureReport.data[14] = 0xff;
featureReport.data[15] = 0xff;
SteamController_HIDSetFeatureReport(pDevice, &featureReport);
}