GCC Code Coverage Report


Directory: main/
File: adapter/wireless/sw2.c
Date: 2025-10-04 14:03:00
Exec Total Coverage
Lines: 0 142 0.0%
Functions: 0 5 0.0%
Branches: 0 45 0.0%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2025, Jacques Gagnon
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6 #include <stdio.h>
7 #include <string.h>
8 #include "zephyr/types.h"
9 #include "tools/util.h"
10 #include "adapter/config.h"
11 #include "adapter/mapping_quirks.h"
12 #include "tests/cmds.h"
13 #include "bluetooth/mon.h"
14 #include "bluetooth/hidp/sw2.h"
15 #include "sw2.h"
16
17 #define SW2_AXES_MAX 4
18
19 enum {
20 SW2_Y = 0,
21 SW2_X,
22 SW2_B,
23 SW2_A,
24 SW2_R_SR,
25 SW2_R_SL,
26 SW2_R,
27 SW2_ZR,
28 SW2_MINUS,
29 SW2_PLUS,
30 SW2_RJ,
31 SW2_LJ,
32 SW2_HOME,
33 SW2_CAPTURE,
34 SW2_C,
35 SW2_UNKNOWN,
36 SW2_DOWN,
37 SW2_UP,
38 SW2_RIGHT,
39 SW2_LEFT,
40 SW2_L_SR,
41 SW2_L_SL,
42 SW2_L,
43 SW2_ZL,
44 SW2_GR,
45 SW2_GL,
46 };
47
48 static const uint8_t sw2_axes_idx[ADAPTER_MAX_AXES] =
49 {
50 /* AXIS_LX, AXIS_LY, AXIS_RX, AXIS_RY, TRIG_L, TRIG_R */
51 0, 1, 2, 3, 4, 5
52 };
53
54 static const struct ctrl_meta sw2_pro_axes_meta[ADAPTER_MAX_AXES] =
55 {
56 {.neutral = 0x800, .abs_max = 1610, .abs_min = 1610},
57 {.neutral = 0x800, .abs_max = 1610, .abs_min = 1610},
58 {.neutral = 0x800, .abs_max = 1610, .abs_min = 1610},
59 {.neutral = 0x800, .abs_max = 1610, .abs_min = 1610},
60 {.neutral = 0x00, .abs_max = 0xFF, .abs_min = 0x00},
61 {.neutral = 0x00, .abs_max = 0xFF, .abs_min = 0x00},
62 };
63
64 static const struct ctrl_meta sw2_gc_axes_meta[ADAPTER_MAX_AXES] =
65 {
66 {.neutral = 0x800, .abs_max = 1225, .abs_min = 1225},
67 {.neutral = 0x800, .abs_max = 1225, .abs_min = 1225},
68 {.neutral = 0x800, .abs_max = 1120, .abs_min = 1120},
69 {.neutral = 0x800, .abs_max = 1120, .abs_min = 1120},
70 {.neutral = 30, .abs_max = 195, .abs_min = 0x00},
71 {.neutral = 30, .abs_max = 195, .abs_min = 0x00},
72 };
73
74 struct sw2_map {
75 uint8_t tbd[4];
76 uint32_t buttons;
77 uint8_t tbd1[2];
78 uint8_t axes[6];
79 uint8_t tbd2[44];
80 uint8_t triggers[2];
81 uint8_t tbd3;
82 } __packed;
83
84 static const uint32_t sw2_pro_mask[4] = {0xFFFF1FFF, 0x00000000, 0x00000000, 0x00000000};
85 static const uint32_t sw2_pro_desc[4] = {0x000000FF, 0x00000000, 0x00000000, 0x00000000};
86 static const uint32_t sw2_pro_btns_mask[32] = {
87 0, 0, 0, 0,
88 0, 0, 0, 0,
89 BIT(SW2_LEFT), BIT(SW2_RIGHT), BIT(SW2_DOWN), BIT(SW2_UP),
90 BIT(SW2_C), 0, 0, 0,
91 BIT(SW2_Y), BIT(SW2_A), BIT(SW2_B), BIT(SW2_X),
92 BIT(SW2_PLUS), BIT(SW2_MINUS), BIT(SW2_HOME), BIT(SW2_CAPTURE),
93 BIT(SW2_ZL), BIT(SW2_L), BIT(SW2_GL), BIT(SW2_LJ),
94 BIT(SW2_ZR), BIT(SW2_R), BIT(SW2_GR), BIT(SW2_RJ),
95 };
96
97 static const uint32_t sw2_gc_mask[4] = {0x77FF0FFF, 0x00000000, 0x00000000, 0x00000000};
98 static const uint32_t sw2_gc_desc[4] = {0x110000FF, 0x00000000, 0x00000000, 0x00000000};
99 static const uint32_t sw2_gc_btns_mask[32] = {
100 0, 0, 0, 0,
101 0, 0, 0, 0,
102 BIT(SW2_LEFT), BIT(SW2_RIGHT), BIT(SW2_DOWN), BIT(SW2_UP),
103 0, 0, 0, 0,
104 BIT(SW2_B), BIT(SW2_X), BIT(SW2_A), BIT(SW2_Y),
105 BIT(SW2_PLUS), BIT(SW2_C), BIT(SW2_HOME), BIT(SW2_CAPTURE),
106 0, BIT(SW2_ZL), BIT(SW2_L), 0,
107 0, BIT(SW2_ZR), BIT(SW2_R), 0,
108 };
109
110 static int32_t sw2_pad_init(struct bt_data *bt_data) {
111 struct bt_hid_sw2_ctrl_calib *calib = NULL;
112 const uint8_t *axes_idx = sw2_axes_idx;
113 struct ctrl_meta *meta = bt_data->raw_src_mappings[PAD].meta;
114 const struct ctrl_meta *sw2_axes_meta = sw2_pro_axes_meta;
115
116 mapping_quirks_apply(bt_data);
117
118 bt_hid_sw2_get_calib(bt_data->base.pids->id, &calib);
119
120 switch (bt_data->base.pid) {
121 case SW2_LJC_PID:
122 {
123 // memcpy(bt_data->raw_src_mappings[PAD].btns_mask, &sw_jc_btns_mask[report_type],
124 // sizeof(bt_data->raw_src_mappings[PAD].btns_mask));
125
126 // meta[0].polarity = 1;
127 // meta[1].polarity = 0;
128 // axes_idx = sw_jc_axes_idx;
129 // memcpy(bt_data->raw_src_mappings[PAD].mask, sw_jc_mask,
130 // sizeof(bt_data->raw_src_mappings[PAD].mask));
131 // memcpy(bt_data->raw_src_mappings[PAD].desc, desc,
132 // sizeof(bt_data->raw_src_mappings[PAD].desc));
133 break;
134 }
135 case SW2_RJC_PID:
136 {
137 // memcpy(bt_data->raw_src_mappings[PAD].btns_mask, &sw_jc_btns_mask[report_type],
138 // sizeof(bt_data->raw_src_mappings[PAD].btns_mask));
139
140 // meta[0].polarity = 0;
141 // meta[1].polarity = 1;
142 // axes_idx = sw_jc_axes_idx;
143 // memcpy(bt_data->raw_src_mappings[PAD].mask, sw_jc_mask,
144 // sizeof(bt_data->raw_src_mappings[PAD].mask));
145 // memcpy(bt_data->raw_src_mappings[PAD].desc, desc,
146 // sizeof(bt_data->raw_src_mappings[PAD].desc));
147 break;
148 }
149 case SW2_GC_PID:
150 {
151 memcpy(bt_data->raw_src_mappings[PAD].btns_mask, sw2_gc_btns_mask,
152 sizeof(bt_data->raw_src_mappings[PAD].btns_mask));
153 meta[0].polarity = 0;
154 meta[1].polarity = 0;
155 meta[2].polarity = 0;
156 meta[3].polarity = 0;
157 axes_idx = sw2_axes_idx;
158 sw2_axes_meta = sw2_gc_axes_meta;
159 memcpy(bt_data->raw_src_mappings[PAD].mask, sw2_gc_mask,
160 sizeof(bt_data->raw_src_mappings[PAD].mask));
161 memcpy(bt_data->raw_src_mappings[PAD].desc, sw2_gc_desc,
162 sizeof(bt_data->raw_src_mappings[PAD].desc));
163
164 meta[TRIG_L].neutral = sw2_gc_axes_meta[TRIG_L].neutral;
165 meta[TRIG_L].abs_max = sw2_gc_axes_meta[TRIG_L].abs_max;
166 meta[TRIG_L].abs_min = sw2_gc_axes_meta[TRIG_L].abs_min;
167 meta[TRIG_R].neutral = sw2_gc_axes_meta[TRIG_R].neutral;
168 meta[TRIG_R].abs_max = sw2_gc_axes_meta[TRIG_R].abs_max;
169 meta[TRIG_R].abs_min = sw2_gc_axes_meta[TRIG_R].abs_min;
170 break;
171 }
172 case SW2_PRO2_PID:
173 default:
174 {
175 memcpy(bt_data->raw_src_mappings[PAD].btns_mask, sw2_pro_btns_mask,
176 sizeof(bt_data->raw_src_mappings[PAD].btns_mask));
177 meta[0].polarity = 0;
178 meta[1].polarity = 0;
179 meta[2].polarity = 0;
180 meta[3].polarity = 0;
181 axes_idx = sw2_axes_idx;
182 memcpy(bt_data->raw_src_mappings[PAD].mask, sw2_pro_mask,
183 sizeof(bt_data->raw_src_mappings[PAD].mask));
184 memcpy(bt_data->raw_src_mappings[PAD].desc, sw2_pro_desc,
185 sizeof(bt_data->raw_src_mappings[PAD].desc));
186 break;
187 }
188 }
189
190 for (uint32_t i = 0; i < SW2_AXES_MAX; i++) {
191 if (calib && calib->sticks[i / 2].axes[i % 2].neutral) {
192 meta[axes_idx[i]].neutral = calib->sticks[i / 2].axes[i % 2].neutral;
193 meta[axes_idx[i]].abs_max = calib->sticks[i / 2].axes[i % 2].rel_max * MAX_PULL_BACK;
194 meta[axes_idx[i]].abs_min = calib->sticks[i / 2].axes[i % 2].rel_min * MAX_PULL_BACK;
195 meta[axes_idx[i]].deadzone = calib->sticks[i / 2].deadzone;
196 printf("# %s: controller calib loaded\n", __FUNCTION__);
197 }
198 else {
199 meta[axes_idx[i]].neutral = sw2_axes_meta[i].neutral;
200 meta[axes_idx[i]].abs_max = sw2_axes_meta[i].abs_max * MAX_PULL_BACK;
201 meta[axes_idx[i]].abs_min = sw2_axes_meta[i].abs_min * MAX_PULL_BACK;
202 meta[axes_idx[i]].deadzone = sw2_axes_meta[i].deadzone;
203 printf("# %s: no calib, using default\n", __FUNCTION__);
204 }
205 bt_data->base.axes_cal[i] = 0;
206 }
207
208 atomic_set_bit(&bt_data->base.flags[PAD], BT_INIT);
209 return 0;
210 }
211
212 static int32_t sw2_pro_to_generic(struct bt_data *bt_data, struct wireless_ctrl *ctrl_data) {
213 struct sw2_map *map = (struct sw2_map *)bt_data->base.input;
214 struct ctrl_meta *meta = bt_data->raw_src_mappings[PAD].meta;
215 uint16_t axes[4];
216
217 if (!atomic_test_bit(&bt_data->base.flags[PAD], BT_INIT)) {
218 if (sw2_pad_init(bt_data)) {
219 return -1;
220 }
221 }
222
223 memset((void *)ctrl_data, 0, sizeof(*ctrl_data));
224
225 ctrl_data->mask = (uint32_t *)sw2_pro_mask;
226 ctrl_data->desc = (uint32_t *)sw2_pro_desc;
227
228 for (uint32_t i = 0; i < ARRAY_SIZE(generic_btns_mask); i++) {
229 if (map->buttons & sw2_pro_btns_mask[i]) {
230 ctrl_data->btns[0].value |= generic_btns_mask[i];
231 }
232 }
233
234 axes[0] = map->axes[0] | ((map->axes[1] & 0xF) << 8);
235 axes[1] = (map->axes[1] >> 4) | (map->axes[2] << 4);
236 axes[2] = map->axes[3] | ((map->axes[4] & 0xF) << 8);
237 axes[3] = (map->axes[4] >> 4) | (map->axes[5] << 4);
238
239 TESTS_CMDS_LOG("\"wireless_input\": {\"axes\": [%u, %u, %u, %u], \"btns\": %lu},\n",
240 axes[0], axes[1], axes[2], axes[3], map->buttons);
241
242 for (uint32_t i = 0; i < SW2_AXES_MAX; i++) {
243 ctrl_data->axes[i].meta = &meta[i];
244 ctrl_data->axes[i].value = axes[i] - meta[i].neutral;
245 }
246 return 0;
247 }
248
249 static int32_t sw2_gc_to_generic(struct bt_data *bt_data, struct wireless_ctrl *ctrl_data) {
250
251 struct sw2_map *map = (struct sw2_map *)bt_data->base.input;
252 struct ctrl_meta *meta = bt_data->raw_src_mappings[PAD].meta;
253 uint16_t axes[4];
254
255 if (!atomic_test_bit(&bt_data->base.flags[PAD], BT_INIT)) {
256 if (sw2_pad_init(bt_data)) {
257 return -1;
258 }
259 }
260
261 memset((void *)ctrl_data, 0, sizeof(*ctrl_data));
262
263 ctrl_data->mask = (uint32_t *)sw2_gc_mask;
264 ctrl_data->desc = (uint32_t *)sw2_gc_desc;
265
266 for (uint32_t i = 0; i < ARRAY_SIZE(generic_btns_mask); i++) {
267 if (map->buttons & sw2_gc_btns_mask[i]) {
268 ctrl_data->btns[0].value |= generic_btns_mask[i];
269 }
270 }
271
272 axes[0] = map->axes[0] | ((map->axes[1] & 0xF) << 8);
273 axes[1] = (map->axes[1] >> 4) | (map->axes[2] << 4);
274 axes[2] = map->axes[3] | ((map->axes[4] & 0xF) << 8);
275 axes[3] = (map->axes[4] >> 4) | (map->axes[5] << 4);
276
277 TESTS_CMDS_LOG("\"wireless_input\": {\"axes\": [%u, %u, %u, %u], \"btns\": %lu},\n",
278 axes[0], axes[1], axes[2], axes[3], map->buttons);
279
280 for (uint32_t i = 0; i < SW2_AXES_MAX; i++) {
281 ctrl_data->axes[i].meta = &meta[i];
282 ctrl_data->axes[i].value = axes[i] - meta[i].neutral;
283 }
284 for (uint32_t i = 4; i < ADAPTER_MAX_AXES; i++) {
285 ctrl_data->axes[i].meta = &meta[i];
286 ctrl_data->axes[i].value = map->triggers[i - 4] - meta[i].neutral;
287 }
288 return 0;
289 }
290
291 int32_t sw2_to_generic(struct bt_data *bt_data, struct wireless_ctrl *ctrl_data) {
292 switch (bt_data->base.pid) {
293 case SW2_LJC_PID:
294 case SW2_RJC_PID:
295 case SW2_PRO2_PID:
296 return sw2_pro_to_generic(bt_data, ctrl_data);
297 case SW2_GC_PID:
298 return sw2_gc_to_generic(bt_data, ctrl_data);
299 default:
300 printf("# Unknown pid : %04X\n", bt_data->base.pid);
301 return -1;
302 }
303 return 0;
304 }
305
306 bool sw2_fb_from_generic(struct generic_fb *fb_data, struct bt_data *bt_data) {
307 struct bt_hidp_sw2_out *out = (struct bt_hidp_sw2_out *)bt_data->base.output;
308 bool ret = true;
309
310 switch (bt_data->base.pid) {
311 case SW2_LJC_PID:
312 case SW2_RJC_PID:
313 case SW2_PRO2_PID:
314 switch (fb_data->type) {
315 case FB_TYPE_RUMBLE:
316 if (fb_data->hf_pwr || fb_data->lf_pwr) {
317 out->r_lra.ops[0].hf_freq = BT_HIDP_SW2_LRA_R_HF_FREQ;
318 out->r_lra.ops[0].hf_amp = (uint8_t)((float)fb_data->hf_pwr / 2.68);
319 out->r_lra.ops[0].lf_freq = BT_HIDP_SW2_LRA_R_LF_FREQ;
320 out->r_lra.ops[0].lf_amp = (uint16_t)((float)fb_data->hf_pwr / 0.3156);
321 out->r_lra.ops[0].enable = 1;
322
323 out->l_lra.ops[0].hf_freq = BT_HIDP_SW2_LRA_L_HF_FREQ;
324 out->l_lra.ops[0].hf_amp = (uint8_t)((float)fb_data->lf_pwr / 2.68);
325 out->l_lra.ops[0].lf_freq = BT_HIDP_SW2_LRA_L_LF_FREQ;
326 out->l_lra.ops[0].lf_amp = (uint16_t)((float)fb_data->lf_pwr / 0.3156);
327 out->l_lra.ops[0].enable = 1;
328 }
329 else {
330 out->l_lra.ops[0].val = BT_HIDP_SW2_LRA_IDLE_32;
331 out->l_lra.ops[0].hf_amp = BT_HIDP_SW2_LRA_IDLE_8;
332 out->r_lra.ops[0].val = BT_HIDP_SW2_LRA_IDLE_32;
333 out->r_lra.ops[0].hf_amp = BT_HIDP_SW2_LRA_IDLE_8;
334 }
335 //printf("%08lX %02X %08lX %02X\n", out->l_lra.ops[0].val, out->l_lra.ops[0].hf_amp, out->r_lra.ops[0].val, out->r_lra.ops[0].hf_amp);
336 break;
337 case FB_TYPE_PLAYER_LED:
338 bt_data->base.output[41] = bt_hid_led_dev_id_map[bt_data->base.pids->out_idx];
339 break;
340 }
341 break;
342 case SW2_GC_PID:
343 {
344 uint8_t cur_val = bt_data->base.output[2];
345 switch (fb_data->type) {
346 case FB_TYPE_RUMBLE:
347 if (fb_data->state) {
348 bt_data->base.output[2] = 0x01;
349 }
350 else {
351 bt_data->base.output[2] = 0x00;
352 }
353 break;
354 case FB_TYPE_PLAYER_LED:
355 bt_data->base.output[13] = bt_hid_led_dev_id_map[bt_data->base.pids->out_idx];
356 break;
357 }
358 ret = (cur_val != bt_data->base.output[2]);
359 break;
360 }
361 default:
362 printf("# Unknown pid : %04X\n", bt_data->base.pid);
363 }
364 return ret;
365 }
366