GCC Code Coverage Report


Directory: main/
File: adapter/wired/gc.c
Date: 2025-10-04 14:03:00
Exec Total Coverage
Lines: 67 108 62.0%
Functions: 5 8 62.5%
Branches: 32 50 64.0%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2019-2025, Jacques Gagnon
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6 #include <string.h>
7 #include "zephyr/types.h"
8 #include "tools/util.h"
9 #include "adapter/adapter.h"
10 #include "adapter/config.h"
11 #include "adapter/wired/wired.h"
12 #include "tests/cmds.h"
13 #include "bluetooth/mon.h"
14 #include "gc.h"
15
16 enum {
17 GC_A,
18 GC_B,
19 GC_X,
20 GC_Y,
21 GC_START,
22 GC_LD_LEFT = 8,
23 GC_LD_RIGHT,
24 GC_LD_DOWN,
25 GC_LD_UP,
26 GC_Z,
27 GC_R,
28 GC_L,
29 };
30
31 static DRAM_ATTR const uint8_t gc_axes_idx[ADAPTER_MAX_AXES] =
32 {
33 /* AXIS_LX, AXIS_LY, AXIS_RX, AXIS_RY, TRIG_L, TRIG_R */
34 0, 1, 2, 3, 4, 5
35 };
36
37 static DRAM_ATTR const struct ctrl_meta gc_axes_meta[ADAPTER_MAX_AXES] =
38 {
39 {.size_min = -128, .size_max = 127, .neutral = 0x80, .abs_max = 0x64, .abs_min = 0x64},
40 {.size_min = -128, .size_max = 127, .neutral = 0x80, .abs_max = 0x64, .abs_min = 0x64},
41 {.size_min = -128, .size_max = 127, .neutral = 0x80, .abs_max = 0x5C, .abs_min = 0x5C},
42 {.size_min = -128, .size_max = 127, .neutral = 0x80, .abs_max = 0x5C, .abs_min = 0x5C},
43 {.size_min = 0, .size_max = 255, .neutral = 0x20, .abs_max = 0xD0, .abs_min = 0x00},
44 {.size_min = 0, .size_max = 255, .neutral = 0x20, .abs_max = 0xD0, .abs_min = 0x00},
45 };
46
47 struct gc_map {
48 uint16_t buttons;
49 uint8_t axes[6];
50 } __packed;
51
52 struct gc_kb_map {
53 uint8_t salt;
54 uint8_t bytes[3];
55 uint8_t key_codes[3];
56 uint8_t xor;
57 } __packed;
58
59 static const uint32_t gc_mask[4] = {0x773F0FFF, 0x00000000, 0x00000000, BR_COMBO_MASK};
60 static const uint32_t gc_desc[4] = {0x110000FF, 0x00000000, 0x00000000, 0x00000000};
61 static DRAM_ATTR const uint32_t gc_btns_mask[32] = {
62 0, 0, 0, 0,
63 0, 0, 0, 0,
64 BIT(GC_LD_LEFT), BIT(GC_LD_RIGHT), BIT(GC_LD_DOWN), BIT(GC_LD_UP),
65 0, 0, 0, 0,
66 BIT(GC_B), BIT(GC_X), BIT(GC_A), BIT(GC_Y),
67 BIT(GC_START), 0, 0, 0,
68 0, BIT(GC_Z), BIT(GC_L), 0,
69 0, BIT(GC_Z), BIT(GC_R), 0,
70 };
71 static DRAM_ATTR const uint32_t gc_btns_mask_alt[32] = {
72 0, 0, 0, 0,
73 0, 0, 0, 0,
74 BIT(GC_LD_LEFT), BIT(GC_LD_RIGHT), BIT(GC_LD_DOWN), BIT(GC_LD_UP),
75 0, 0, 0, 0,
76 BIT(GC_Y), BIT(GC_A), BIT(GC_B), BIT(GC_X),
77 BIT(GC_START), 0, 0, 0,
78 0, BIT(GC_Z), BIT(GC_L), 0,
79 0, BIT(GC_Z), BIT(GC_R), 0,
80 };
81 static DRAM_ATTR const uint32_t *btns_mask[WIRED_MAX_DEV] = {
82 gc_btns_mask, gc_btns_mask, gc_btns_mask, gc_btns_mask,
83 gc_btns_mask, gc_btns_mask, gc_btns_mask, gc_btns_mask,
84 #ifndef CONFIG_BLUERETRO_QEMU
85 gc_btns_mask, gc_btns_mask, gc_btns_mask, gc_btns_mask,
86 #endif
87 };
88
89 static const uint32_t gc_kb_mask[4] = {0xE6FF0F0F, 0xFFFFFFFF, 0x1FBFFFFF, 0x0003C000 | BR_COMBO_MASK};
90 static const uint32_t gc_kb_desc[4] = {0x00000000, 0x00000000, 0x00000000, 0x00000000};
91 static const uint8_t gc_kb_scancode[KBM_MAX] = {
92 /* KB_A, KB_D, KB_S, KB_W, MOUSE_X_LEFT, MOUSE_X_RIGHT, MOUSE_Y_DOWN MOUSE_Y_UP */
93 0x10, 0x13, 0x22, 0x26, 0x00, 0x00, 0x00, 0x00,
94 /* KB_LEFT, KB_RIGHT, KB_DOWN, KB_UP, MOUSE_WX_LEFT, MOUSE_WX_RIGHT, MOUSE_WY_DOWN, MOUSE_WY_UP */
95 0x5C, 0x5F, 0x5D, 0x5E, 0x00, 0x00, 0x00, 0x00,
96 /* KB_Q, KB_R, KB_E, KB_F, KB_ESC, KB_ENTER, KB_LWIN, KB_HASH */
97 0x20, 0x21, 0x14, 0x15, 0x4c, 0x61, 0x58, 0x4f,
98 /* MOUSE_RIGHT, KB_Z, KB_LCTRL, MOUSE_MIDDLE, MOUSE_LEFT, KB_X, KB_LSHIFT, KB_SPACE */
99 0x00, 0x29, 0x56, 0x00, 0x00, 0x27, 0x54, 0x59,
100
101 /* KB_B, KB_C, KB_G, KB_H, KB_I, KB_J, KB_K, KB_L */
102 0x11, 0x12, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B,
103 /* KB_M, KB_N, KB_O, KB_P, KB_T, KB_U, KB_V, KB_Y */
104 0x1C, 0x1D, 0x1E, 0x1F, 0x23, 0x24, 0x25, 0x28,
105 /* KB_1, KB_2, KB_3, KB_4, KB_5, KB_6, KB_7, KB_8 */
106 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31,
107 /* KB_9, KB_0, KB_BACKSPACE, KB_TAB, KB_MINUS, KB_EQUAL, KB_LEFTBRACE, KB_RIGHTBRACE */
108 0x32, 0x33, 0x50, 0x51, 0x34, 0x35, 0x38, 0x3B,
109
110 /* KB_BACKSLASH, KB_SEMICOLON, KB_APOSTROPHE, KB_GRAVE, KB_COMMA, KB_DOT, KB_SLASH, KB_CAPSLOCK */
111 0x3F, 0x39, 0x3A, 0x36, 0x3C, 0x3D, 0x3E, 0x53,
112 /* KB_F1, KB_F2, KB_F3, KB_F4, KB_F5, KB_F6, KB_F7, KB_F8 */
113 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
114 /* KB_F9, KB_F10, KB_F11, KB_F12, KB_PSCREEN, KB_SCROLL, KB_PAUSE, KB_INSERT */
115 0x48, 0x49, 0x4A, 0x4B, 0x37, 0x0A, 0x00, 0x4D,
116 /* KB_HOME, KB_PAGEUP, KB_DEL, KB_END, KB_PAGEDOWN, KB_NUMLOCK, KB_KP_DIV, KB_KP_MULTI */
117 0x06, 0x08, 0x4E, 0x07, 0x09, 0x00, 0x00, 0x00,
118
119 /* KB_KP_MINUS, KB_KP_PLUS, KB_KP_ENTER, KB_KP_1, KB_KP_2, KB_KP_3, KB_KP_4, KB_KP_5 */
120 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
121 /* KB_KP_6, KB_KP_7, KB_KP_8, KB_KP_9, KB_KP_0, KB_KP_DOT, KB_LALT, KB_RCTRL */
122 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0x5B,
123 /* KB_RSHIFT, KB_RALT, KB_RWIN */
124 0x55, 0x5A, 0x00,
125 };
126
127 186 void IRAM_ATTR gc_init_buffer(int32_t dev_mode, struct wired_data *wired_data) {
128
1/2
✗ Branch 0 (2→3) not taken.
✓ Branch 1 (2→5) taken 186 times.
186 switch (dev_mode) {
129 case DEV_KB:
130 {
131 memset(wired_data->output, 0, sizeof(struct gc_kb_map));
132 break;
133 }
134 186 default:
135 {
136 186 struct gc_map *map = (struct gc_map *)wired_data->output;
137 186 struct gc_map *map_mask = (struct gc_map *)wired_data->output_mask;
138
139 186 map->buttons = 0x8020;
140 186 map_mask->buttons = 0xFFFF;
141
2/2
✓ Branch 0 (7→6) taken 1116 times.
✓ Branch 1 (7→8) taken 186 times.
1302 for (uint32_t i = 0; i < ADAPTER_MAX_AXES; i++) {
142 1116 map->axes[gc_axes_idx[i]] = gc_axes_meta[i].neutral;
143 }
144 186 memset(map_mask->axes, 0x00, sizeof(map_mask->axes));
145 186 break;
146 }
147 }
148 186 }
149
150 1294 void gc_meta_init(struct wired_ctrl *ctrl_data) {
151 1294 memset((void *)ctrl_data, 0, sizeof(*ctrl_data)*4);
152
153
2/2
✓ Branch 0 (10→11) taken 10352 times.
✓ Branch 1 (10→12) taken 1294 times.
11646 for (uint32_t i = 0; i < WIRED_MAX_DEV; i++) {
154
2/2
✓ Branch 0 (8→4) taken 62112 times.
✓ Branch 1 (8→9) taken 10352 times.
72464 for (uint32_t j = 0; j < ADAPTER_MAX_AXES; j++) {
155
1/2
✗ Branch 0 (4→5) not taken.
✓ Branch 1 (4→6) taken 62112 times.
62112 switch (config.out_cfg[i].dev_mode) {
156 case DEV_KB:
157 ctrl_data[i].mask = gc_kb_mask;
158 ctrl_data[i].desc = gc_kb_desc;
159 ctrl_data[i].axes[j].meta = NULL;
160 break;
161 62112 default:
162 62112 ctrl_data[i].mask = gc_mask;
163 62112 ctrl_data[i].desc = gc_desc;
164 62112 ctrl_data[i].axes[j].meta = &gc_axes_meta[j];
165 62112 break;
166 }
167 }
168 }
169 1294 }
170
171 1294 static void gc_ctrl_special_action(struct wired_ctrl *ctrl_data, struct wired_data *wired_data) {
172 /* Face buttons mapping convertion toggle between names & positions */
173
2/2
✓ Branch 0 (2→3) taken 1142 times.
✓ Branch 1 (2→14) taken 152 times.
1294 if (ctrl_data->map_mask[0] & generic_btns_mask[PAD_MS]) {
174
2/2
✓ Branch 0 (3→4) taken 80 times.
✓ Branch 1 (3→7) taken 1062 times.
1142 if (ctrl_data->btns[0].value & generic_btns_mask[PAD_MS]) {
175
1/2
✓ Branch 0 (5→6) taken 80 times.
✗ Branch 1 (5→14) not taken.
80 if (!atomic_test_bit(&wired_data->flags, WIRED_WAITING_FOR_RELEASE)) {
176 80 atomic_set_bit(&wired_data->flags, WIRED_WAITING_FOR_RELEASE);
177 }
178 }
179 else {
180
2/2
✓ Branch 0 (8→9) taken 80 times.
✓ Branch 1 (8→14) taken 982 times.
1062 if (atomic_test_bit(&wired_data->flags, WIRED_WAITING_FOR_RELEASE)) {
181 80 atomic_clear_bit(&wired_data->flags, WIRED_WAITING_FOR_RELEASE);
182
183
2/2
✓ Branch 0 (10→11) taken 40 times.
✓ Branch 1 (10→12) taken 40 times.
80 if (btns_mask[ctrl_data->index] == gc_btns_mask) {
184 40 btns_mask[ctrl_data->index] = gc_btns_mask_alt;
185 40 printf("# %s: Names based mapping\n", __FUNCTION__);
186 }
187 else {
188 40 btns_mask[ctrl_data->index] = gc_btns_mask;
189 40 printf("# %s: Position based mapping\n", __FUNCTION__);
190 }
191 80 adapter_toggle_fb(ctrl_data->index, 300000, 0xFF, 0xFF);
192 }
193 }
194 }
195 1294 }
196
197 1294 static void gc_ctrl_from_generic(struct wired_ctrl *ctrl_data, struct wired_data *wired_data) {
198 1294 struct gc_map map_tmp;
199 1294 uint32_t map_mask = 0xFFFF;
200
201 1294 memcpy((void *)&map_tmp, wired_data->output, sizeof(map_tmp));
202
203
2/2
✓ Branch 0 (11→4) taken 41408 times.
✓ Branch 1 (11→12) taken 1294 times.
42702 for (uint32_t i = 0; i < ARRAY_SIZE(generic_btns_mask); i++) {
204
2/2
✓ Branch 0 (4→5) taken 16022 times.
✓ Branch 1 (4→6) taken 25386 times.
41408 if (ctrl_data->map_mask[0] & generic_btns_mask[i]) {
205
2/2
✓ Branch 0 (6→7) taken 1024 times.
✓ Branch 1 (6→8) taken 24362 times.
25386 if (ctrl_data->btns[0].value & generic_btns_mask[i]) {
206 1024 map_tmp.buttons |= btns_mask[ctrl_data->index][i];
207 1024 map_mask &= ~btns_mask[ctrl_data->index][i];
208 1024 wired_data->cnt_mask[i] = ctrl_data->btns[0].cnt_mask[i];
209 }
210
2/2
✓ Branch 0 (8→5) taken 11087 times.
✓ Branch 1 (8→9) taken 13275 times.
24362 else if (map_mask & btns_mask[ctrl_data->index][i]) {
211 13275 map_tmp.buttons &= ~btns_mask[ctrl_data->index][i];
212 13275 wired_data->cnt_mask[i] = 0;
213 }
214 }
215 }
216
217 1294 gc_ctrl_special_action(ctrl_data, wired_data);
218
219
2/2
✓ Branch 0 (23→14) taken 7764 times.
✓ Branch 1 (23→24) taken 1294 times.
9058 for (uint32_t i = 0; i < ADAPTER_MAX_AXES; i++) {
220
2/2
✓ Branch 0 (15→16) taken 6208 times.
✓ Branch 1 (15→21) taken 1556 times.
7764 if (ctrl_data->map_mask[0] & (axis_to_btn_mask(i) & gc_desc[0])) {
221
1/2
✗ Branch 0 (16→17) not taken.
✓ Branch 1 (16→18) taken 6208 times.
6208 if (ctrl_data->axes[i].value > ctrl_data->axes[i].meta->size_max) {
222 map_tmp.axes[gc_axes_idx[i]] = 255;
223 }
224
1/2
✗ Branch 0 (18→19) not taken.
✓ Branch 1 (18→20) taken 6208 times.
6208 else if (ctrl_data->axes[i].value < ctrl_data->axes[i].meta->size_min) {
225 map_tmp.axes[gc_axes_idx[i]] = 0;
226 }
227 else {
228 6208 map_tmp.axes[gc_axes_idx[i]] = (uint8_t)(ctrl_data->axes[i].value + ctrl_data->axes[i].meta->neutral);
229 }
230 }
231 7764 wired_data->cnt_mask[axis_to_btn_id(i)] = ctrl_data->axes[i].cnt_mask;
232 }
233
234 1294 memcpy(wired_data->output, (void *)&map_tmp, sizeof(map_tmp));
235
236 1294 TESTS_CMDS_LOG("\"wired_output\": {\"axes\": [%d, %d, %d, %d, %d, %d], \"btns\": %d},\n",
237 map_tmp.axes[gc_axes_idx[0]], map_tmp.axes[gc_axes_idx[1]], map_tmp.axes[gc_axes_idx[2]],
238 map_tmp.axes[gc_axes_idx[3]], map_tmp.axes[gc_axes_idx[4]], map_tmp.axes[gc_axes_idx[5]], map_tmp.buttons);
239 BT_MON_LOG("\"wired_output\": {\"axes\": [%02X, %02X, %02X, %02X, %02X, %02X], \"btns\": %04X},\n",
240 map_tmp.axes[gc_axes_idx[0]], map_tmp.axes[gc_axes_idx[1]], map_tmp.axes[gc_axes_idx[2]],
241 1294 map_tmp.axes[gc_axes_idx[3]], map_tmp.axes[gc_axes_idx[4]], map_tmp.axes[gc_axes_idx[5]], map_tmp.buttons);
242 1294 }
243
244 static void gc_kb_from_generic(struct wired_ctrl *ctrl_data, struct wired_data *wired_data) {
245 struct gc_kb_map map_tmp = {0};
246 uint32_t code_idx = 0;
247
248 for (uint32_t i = 0; i < KBM_MAX && code_idx < ARRAY_SIZE(map_tmp.key_codes); i++) {
249 if (ctrl_data->map_mask[i / 32] & BIT(i & 0x1F)) {
250 if (ctrl_data->btns[i / 32].value & BIT(i & 0x1F)) {
251 if (gc_kb_scancode[i]) {
252 map_tmp.key_codes[code_idx++] = gc_kb_scancode[i];
253 }
254 }
255 }
256 }
257 map_tmp.salt = (wired_data->output[0] + 1) & 0xF;
258
259 memcpy(wired_data->output, (void *)&map_tmp, sizeof(map_tmp));
260 }
261
262 1294 void gc_from_generic(int32_t dev_mode, struct wired_ctrl *ctrl_data, struct wired_data *wired_data) {
263
1/2
✗ Branch 0 (2→3) not taken.
✓ Branch 1 (2→5) taken 1294 times.
1294 switch (dev_mode) {
264 case DEV_KB:
265 gc_kb_from_generic(ctrl_data, wired_data);
266 break;
267 1294 case DEV_PAD:
268 default:
269 1294 gc_ctrl_from_generic(ctrl_data, wired_data);
270 1294 break;
271 }
272 1294 }
273
274 void gc_fb_to_generic(int32_t dev_mode, struct raw_fb *raw_fb_data, struct generic_fb *fb_data) {
275 fb_data->wired_id = raw_fb_data->header.wired_id;
276 fb_data->type = raw_fb_data->header.type;
277
278 /* This stop rumble when BR timeout trigger */
279 if (raw_fb_data->header.data_len == 0) {
280 fb_data->state = 0;
281 fb_data->lf_pwr = fb_data->hf_pwr = 0;
282 }
283 else {
284 fb_data->state = raw_fb_data->data[0];
285 fb_data->lf_pwr = (fb_data->state) ? 0xFF : 0x00;
286 fb_data->hf_pwr = (fb_data->state) ? 0xFF : 0x00;
287 }
288 }
289
290 void IRAM_ATTR gc_gen_turbo_mask(struct wired_data *wired_data) {
291 struct gc_map *map_mask = (struct gc_map *)wired_data->output_mask;
292
293 map_mask->buttons = 0xFFFF;
294 memset(map_mask->axes, 0x00, sizeof(map_mask->axes));
295
296 wired_gen_turbo_mask_btns16_pos(wired_data, &map_mask->buttons, btns_mask[wired_data->index]);
297 wired_gen_turbo_mask_axes8(wired_data, map_mask->axes, ADAPTER_MAX_AXES, gc_axes_idx, gc_axes_meta);
298 }
299