Skip to content

Commit 2269866

Browse files
committed
Ensure need_origin flag is set correctly in both wired and wireless modes
1 parent 1af879b commit 2269866

File tree

4 files changed

+79
-42
lines changed

4 files changed

+79
-42
lines changed

firmware/libsi/include/si/device/gc_controller.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -184,9 +184,11 @@ static inline void si_device_gc_input_valid(struct si_device_gc_controller *devi
184184
}
185185

186186
/**
187-
* Update the origin of the controller, based on an origin packet.
187+
* Update the origin of the controller.
188+
*
189+
* If the origin data differs from the current origin, the "need origin" flag is set.
188190
*
189191
* @param device the device to set the wireless origin for
190-
* @param origin_data pointer to the analog origin data (6 bytes)
192+
* @param new_origin pointer to the new origin data (6 bytes)
191193
*/
192-
void si_device_gc_set_wireless_origin(struct si_device_gc_controller *device, uint8_t *origin_data);
194+
void si_device_gc_set_origin(struct si_device_gc_controller *device, struct si_device_gc_input_state *new_origin);

firmware/libsi/src/device/gc_controller.c

Lines changed: 33 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,22 @@ static uint8_t *pack_input_state(struct si_device_gc_input_state *src, uint8_t a
6868
return packed_state;
6969
}
7070

71+
// Set or clear the "need origin" flag in the input state and device info
72+
static void set_need_origin(struct si_device_gc_controller *device, bool need_origin)
73+
{
74+
// Always set the need_origin flag in the input state
75+
device->input.buttons.need_origin = need_origin;
76+
77+
// Also update the device info for non-wireless controllers
78+
if (!si_device_gc_is_wireless(device)) {
79+
if (need_origin) {
80+
device->info[2] |= SI_NEED_ORIGIN;
81+
} else {
82+
device->info[2] &= ~SI_NEED_ORIGIN;
83+
}
84+
}
85+
}
86+
7187
/**
7288
* Handle "info" commands.
7389
*
@@ -118,8 +134,7 @@ static int handle_short_poll(const uint8_t *command, si_complete_cb_t callback,
118134

119135
if (!si_device_gc_is_wireless(device)) {
120136
// Update the origin flags
121-
device->input.buttons.need_origin = (device->info[2] & SI_NEED_ORIGIN) != 0;
122-
device->input.buttons.use_origin = true;
137+
device->input.buttons.use_origin = true;
123138

124139
// Save the analog mode and motor state
125140
device->info[2] &= ~(SI_MOTOR_STATE_MASK | SI_ANALOG_MODE_MASK);
@@ -154,13 +169,8 @@ static int handle_read_origin(const uint8_t *command, si_complete_cb_t callback,
154169
{
155170
struct si_device_gc_controller *device = (struct si_device_gc_controller *)context;
156171

157-
// Tell the host it no longer needs to fetch the origin
158-
if (!si_device_gc_is_wireless(device)) {
159-
device->info[2] &= ~SI_NEED_ORIGIN;
160-
}
161-
162172
// Clear the "need origin" flag
163-
device->input.buttons.need_origin = false;
173+
set_need_origin(device, false);
164174

165175
// Respond with the origin
166176
si_write_bytes((uint8_t *)(&device->origin), SI_CMD_GC_READ_ORIGIN_RESP, callback);
@@ -186,10 +196,8 @@ static int handle_calibrate(const uint8_t *command, si_complete_cb_t callback, v
186196
device->origin.trigger_left = device->input.trigger_left;
187197
device->origin.trigger_right = device->input.trigger_right;
188198

189-
// Tell the host it no longer needs to fetch the origin
190-
if (!si_device_gc_is_wireless(device)) {
191-
device->info[2] &= ~SI_NEED_ORIGIN;
192-
}
199+
// Clear the "need origin" flag
200+
set_need_origin(device, false);
193201

194202
// Respond with the new origin
195203
si_write_bytes((uint8_t *)(&device->origin), SI_CMD_GC_CALIBRATE_RESP, callback);
@@ -213,18 +221,20 @@ static int handle_long_poll(const uint8_t *command, si_complete_cb_t callback, v
213221
uint8_t analog_mode = command[1] & 0x07;
214222
uint8_t motor_state = command[2] & 0x03;
215223

216-
// Update the origin flags before responding
217-
device->input.buttons.need_origin = (device->info[2] & SI_NEED_ORIGIN) != 0;
218-
device->input.buttons.use_origin = true;
219-
220-
// Save the analog mode and motor state
221224
if (!si_device_gc_is_wireless(device)) {
225+
// Update the origin flags
226+
device->input.buttons.use_origin = true;
227+
228+
// Save the analog mode and motor state
222229
device->info[2] &= ~(SI_MOTOR_STATE_MASK | SI_ANALOG_MODE_MASK);
223230
device->info[2] |= motor_state << 3 | analog_mode;
224231
}
225232

233+
// If the input state is valid, use that for the response, otherwise use the origin
234+
struct si_device_gc_input_state *state = device->input_valid ? &device->input : &device->origin;
235+
226236
// Respond with the current input state
227-
si_write_bytes((uint8_t *)&device->input, SI_CMD_GC_LONG_POLL_RESP, callback);
237+
si_write_bytes((uint8_t *)state, SI_CMD_GC_LONG_POLL_RESP, callback);
228238

229239
return SI_CMD_GC_LONG_POLL_RESP;
230240
}
@@ -296,10 +306,6 @@ void si_device_gc_init(struct si_device_gc_controller *device, uint8_t type)
296306
// Mark the input as valid initially
297307
device->input_valid = true;
298308

299-
// Request the origin on non-wireless controllers
300-
if (!si_device_gc_is_wireless(device))
301-
device->info[2] = SI_NEED_ORIGIN;
302-
303309
// Register the SI commands handled by GameCube controllers
304310
si_command_register(SI_CMD_INFO, SI_CMD_INFO_LEN, handle_info, device);
305311
si_command_register(SI_CMD_RESET, SI_CMD_RESET_LEN, handle_reset, device);
@@ -328,15 +334,15 @@ void si_device_gc_set_wireless_id(struct si_device_gc_controller *device, uint16
328334
device->info[0] |= SI_GC_STANDARD | SI_WIRELESS_RECEIVED;
329335
}
330336

331-
void si_device_gc_set_wireless_origin(struct si_device_gc_controller *device, uint8_t *origin_data)
337+
void si_device_gc_set_origin(struct si_device_gc_controller *device, struct si_device_gc_input_state *new_origin)
332338
{
333339
// Check if the origin packet is different from the last known origin
334-
if (memcmp(&device->origin.stick_x, origin_data, 6) != 0) {
340+
if (memcmp(&device->origin.stick_x, &new_origin->stick_x, 6) != 0) {
335341
// Update the origin state
336-
memcpy(&device->origin.stick_x, origin_data, 6);
342+
memcpy(&device->origin.stick_x, &new_origin->stick_x, 6);
337343

338-
// Set the "need origin" flag to true so the host knows to fetch the new origin
339-
device->input.buttons.need_origin = true;
344+
// Tell the host that new origin data is available
345+
set_need_origin(device, true);
340346
}
341347

342348
// Set the "has wireless origin" flag in the device info

firmware/libsi/test/test_gc_controller.c

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ static void test_gcc_info()
4040
simulate_command(&device, info_command);
4141

4242
// Test device info response is as expected
43-
uint8_t expected_response[] = {0x09, 0x00, 0x20};
43+
uint8_t expected_response[] = {0x09, 0x00, 0x00};
4444
TEST_ASSERT_EQUAL(3, response_len);
4545
TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_response, response_buf, 3);
4646
}
@@ -52,18 +52,37 @@ static void test_gcc_info_after_read_origin()
5252
struct si_device_gc_controller device;
5353
si_device_gc_init(&device, SI_TYPE_GC | SI_GC_STANDARD);
5454

55+
// Set an origin
56+
struct si_device_gc_input_state new_origin = {
57+
.stick_x = 0x81,
58+
.stick_y = 0x82,
59+
.substick_x = 0x83,
60+
.substick_y = 0x84,
61+
.trigger_left = 0x11,
62+
.trigger_right = 0x12,
63+
};
64+
si_device_gc_set_origin(&device, &new_origin);
65+
66+
// Send an info command
67+
uint8_t info_command[] = {SI_CMD_INFO};
68+
simulate_command(&device, info_command);
69+
70+
// Test device info response is as expected
71+
uint8_t expected_response[] = {0x09, 0x00, 0x20};
72+
TEST_ASSERT_EQUAL(3, response_len);
73+
TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_response, response_buf, 3);
74+
5575
// Send a read origin command
5676
uint8_t read_origin_command[] = {SI_CMD_GC_READ_ORIGIN};
5777
simulate_command(&device, read_origin_command);
5878

59-
// Send an info command
60-
uint8_t info_command[] = {SI_CMD_INFO};
79+
// Send another info command
6180
simulate_command(&device, info_command);
6281

6382
// Verify the "need_origin" flag is not present
64-
uint8_t expected_response[] = {0x09, 0x00, 0x00};
83+
uint8_t expected_response_2[] = {0x09, 0x00, 0x00};
6584
TEST_ASSERT_EQUAL(3, response_len);
66-
TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_response, response_buf, 3);
85+
TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_response_2, response_buf, 3);
6786
}
6887

6988
// Test that "analog mode" and "motor state" are saved after a "poll" command
@@ -283,8 +302,15 @@ static void test_set_wireless_origin(void)
283302
TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_info_response_2, response_buf, 3);
284303

285304
// Set the wireless origin
286-
uint8_t origin_data[] = {0x85, 0x86, 0x87, 0x88, 0x11, 0x12};
287-
si_device_gc_set_wireless_origin(&device, origin_data);
305+
struct si_device_gc_input_state origin = {
306+
.stick_x = 0x85,
307+
.stick_y = 0x86,
308+
.substick_x = 0x87,
309+
.substick_y = 0x88,
310+
.trigger_left = 0x11,
311+
.trigger_right = 0x12,
312+
};
313+
si_device_gc_set_origin(&device, &origin);
288314

289315
// Check the origin state is set correctly
290316
TEST_ASSERT_EQUAL_UINT8(0x85, device.origin.stick_x);

firmware/receiver/src/main.c

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -218,14 +218,17 @@ static void handle_wavebird_packet(const uint8_t *packet)
218218
//
219219

220220
// Copy the origin values from the packet
221-
uint8_t new_origin[] = {
222-
wavebird_origin_get_stick_x(message), wavebird_origin_get_stick_y(message),
223-
wavebird_origin_get_substick_x(message), wavebird_origin_get_substick_y(message),
224-
wavebird_origin_get_trigger_left(message), wavebird_origin_get_trigger_right(message),
221+
struct si_device_gc_input_state new_origin = {
222+
.stick_x = wavebird_origin_get_stick_x(message),
223+
.stick_y = wavebird_origin_get_stick_y(message),
224+
.substick_x = wavebird_origin_get_substick_x(message),
225+
.substick_y = wavebird_origin_get_substick_y(message),
226+
.trigger_left = wavebird_origin_get_trigger_left(message),
227+
.trigger_right = wavebird_origin_get_trigger_right(message),
225228
};
226229

227230
// Update the origin state in the SI device
228-
si_device_gc_set_wireless_origin(&si_device, new_origin);
231+
si_device_gc_set_origin(&si_device, &new_origin);
229232
}
230233
}
231234

0 commit comments

Comments
 (0)