Compare commits
186 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
16f1c52025 | ||
|
|
f64a336138 | ||
|
|
5947da5f2d | ||
|
|
c68e06a88b | ||
|
|
3834651c0e | ||
|
|
2166c6a337 | ||
|
|
5b007e36d2 | ||
|
|
e3fa85d6c8 | ||
|
|
98e64bb864 | ||
|
|
9da2278640 | ||
|
|
288a1bce18 | ||
|
|
75c19eace1 | ||
|
|
8c8a488466 | ||
|
|
c8e81eb272 | ||
|
|
749b184d13 | ||
|
|
35bbaa4f2d | ||
|
|
1866d65b9e | ||
|
|
f4f638ea24 | ||
|
|
d608d07d89 | ||
|
|
cb9b5e5c4a | ||
|
|
f75351fa36 | ||
|
|
e0d36026e7 | ||
|
|
50d36ba6fe | ||
|
|
5b7b977ec4 | ||
|
|
57ca777219 | ||
|
|
6873e50f00 | ||
|
|
a64c7680fd | ||
|
|
612fb701c5 | ||
|
|
8a97652d05 | ||
|
|
658551fac1 | ||
|
|
4ab34c4547 | ||
|
|
34ba98d12d | ||
|
|
f4a4efd201 | ||
|
|
3bd22ad542 | ||
|
|
0853d0cdc6 | ||
|
|
6055034bf6 | ||
|
|
79fe2cf9dd | ||
|
|
dde8b0f152 | ||
|
|
39cd08d01a | ||
|
|
ee02e47df0 | ||
|
|
ae3fac6301 | ||
|
|
ec2d777245 | ||
|
|
6edf68376d | ||
|
|
479b671733 | ||
|
|
6572e07bcb | ||
|
|
984e735d06 | ||
|
|
1a268f1333 | ||
|
|
ef12d04dc8 | ||
|
|
b27f1778e3 | ||
|
|
43b3871a7a | ||
|
|
eed329b829 | ||
|
|
06454661bf | ||
|
|
42141c3058 | ||
|
|
48e9c261a0 | ||
|
|
bcee26dcfd | ||
|
|
93cfd21f11 | ||
|
|
026e970615 | ||
|
|
d208f5dc2a | ||
|
|
9234403297 | ||
|
|
778082077c | ||
|
|
eec5cadf8c | ||
|
|
b38563243f | ||
|
|
4b6183eeb6 | ||
|
|
2c3d7de0e4 | ||
|
|
7b50fbfca1 | ||
|
|
337244b0de | ||
|
|
d091e54ecb | ||
|
|
358fba86d6 | ||
|
|
bb4ff25130 | ||
|
|
6b5aeaa9ef | ||
|
|
d777f284b0 | ||
|
|
6640812315 | ||
|
|
31fc20de9a | ||
|
|
c68ddd85b8 | ||
|
|
9cf162681e | ||
|
|
1c401c9dbf | ||
|
|
e85322e38c | ||
|
|
f3ac4dc285 | ||
|
|
42832e0b0d | ||
|
|
782865dbb6 | ||
|
|
58d7d7c553 | ||
|
|
c668a9406c | ||
|
|
922dd90831 | ||
|
|
c400ee7d22 | ||
|
|
a755e2a18c | ||
|
|
e36ad2e47d | ||
|
|
e3e2a7e83e | ||
|
|
ae2e50cc2c | ||
|
|
ebf83d6350 | ||
|
|
8870020cab | ||
|
|
72df979cf6 | ||
|
|
62c903830e | ||
|
|
089e289003 | ||
|
|
f7ee474659 | ||
|
|
b9ea79a558 | ||
|
|
6ff835405e | ||
|
|
10c3ce4fe7 | ||
|
|
6f60b53745 | ||
|
|
bca99cefca | ||
|
|
34aa554e29 | ||
|
|
1055f4d796 | ||
|
|
309609a377 | ||
|
|
a0a5eba0f4 | ||
|
|
5b5592b0a7 | ||
|
|
2bcbb4d9fa | ||
|
|
8021eba1e4 | ||
|
|
6abee8e0e8 | ||
|
|
95ce2a687b | ||
|
|
acd59cecf3 | ||
|
|
fe11a9f5b6 | ||
|
|
566ab8b93a | ||
|
|
17afabd24c | ||
|
|
82fab22cff | ||
|
|
cca9a4b375 | ||
|
|
7498f90f1a | ||
|
|
f351427a05 | ||
|
|
458ef9f07d | ||
|
|
4825ee8e17 | ||
|
|
80331fa85a | ||
|
|
6f9a16e694 | ||
|
|
464d257a23 | ||
|
|
2aa79bb180 | ||
|
|
a4981b2ad3 | ||
|
|
a4b98139ee | ||
|
|
8857d30a58 | ||
|
|
8637035ab2 | ||
|
|
628e803834 | ||
|
|
566d89df29 | ||
|
|
646ed984de | ||
|
|
9aa38f416c | ||
|
|
793f9e7e56 | ||
|
|
18c1e27c3a | ||
|
|
0324cd2760 | ||
|
|
23dad1ba60 | ||
|
|
c4b6616675 | ||
|
|
68412b3318 | ||
|
|
8fc2bd42b5 | ||
|
|
e6a940dc4d | ||
|
|
96b47c6e49 | ||
|
|
9397aa2348 | ||
|
|
692ff53ff7 | ||
|
|
0336bf3777 | ||
|
|
89f32b5eb1 | ||
|
|
4623413b5a | ||
|
|
a89d9b5ad1 | ||
|
|
ff7b0d918c | ||
|
|
a9eb18319d | ||
|
|
bc8911e180 | ||
|
|
f6e0173854 | ||
|
|
ea5f026e04 | ||
|
|
6eb6847444 | ||
|
|
71603dc4d6 | ||
|
|
466f1a4db6 | ||
|
|
660f73c26d | ||
|
|
c331a4e139 | ||
|
|
0105251e34 | ||
|
|
c9354dc357 | ||
|
|
c6ecb53bd3 | ||
|
|
046f635de6 | ||
|
|
5e3a1e4e98 | ||
|
|
f9f5b67690 | ||
|
|
00cc6adf7d | ||
|
|
5548eb806f | ||
|
|
587fe7ffcf | ||
|
|
4bdff1a50d | ||
|
|
cc16d4983e | ||
|
|
0b7f888a2f | ||
|
|
6072f88002 | ||
|
|
0797e2e326 | ||
|
|
563da79b2b | ||
|
|
b69d2d7198 | ||
|
|
3ca8c59837 | ||
|
|
13f35d6924 | ||
|
|
75b4bb1912 | ||
|
|
fb36302883 | ||
|
|
8b57c19d0a | ||
|
|
bcabb2732b | ||
|
|
f55c055ad5 | ||
|
|
a3b2eb0e41 | ||
|
|
917ec565f8 | ||
|
|
49ba884623 | ||
|
|
971b661c5e | ||
|
|
c2e3a7704a | ||
|
|
4d2c9c2e36 | ||
|
|
e580cca85c | ||
|
|
f87028f8f7 |
48 changed files with 6117 additions and 1619 deletions
2
80-playstation-no-libinput.rules
Normal file
2
80-playstation-no-libinput.rules
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
ACTION=="add|change", KERNEL=="event[0-9]*", ATTRS{name}=="Wireless Controller Touchpad", ENV{LIBINPUT_IGNORE_DEVICE}="1"
|
||||
ACTION=="add|change", KERNEL=="event[0-9]*", ATTRS{name}=="Wireless Edge Controller Touchpad", ENV{LIBINPUT_IGNORE_DEVICE}="1"
|
||||
1
99-js-block.rules
Normal file
1
99-js-block.rules
Normal file
|
|
@ -0,0 +1 @@
|
|||
KERNEL=="js[0-9]*|event[0-9]*", SUBSYSTEM=="input", ATTRS{idVendor}=="045e", ATTRS{idProduct}=="028e", MODE="000", GROUP="root", TAG="", RUN+="/bin/chmod 000 /dev/input/%k"
|
||||
1
99-xbox360-block.rules
Normal file
1
99-xbox360-block.rules
Normal file
|
|
@ -0,0 +1 @@
|
|||
ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="045E", ATTRS{idProduct}=="028E", RUN+="/bin/sh -c 'echo 0 > /sys$DEVPATH/authorized'"
|
||||
|
|
@ -13,10 +13,13 @@ set(ROGUE_EXECUTABLE_NAME "rogue-enemy")
|
|||
set(STRAY_EXECUTABLE_NAME "stray-ally")
|
||||
set(ALLINONE_EXECUTABLE_NAME "allynone")
|
||||
|
||||
find_package(PkgConfig REQUIRED) # Include functions provided by PkgConfig module.
|
||||
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
add_executable(${ROGUE_EXECUTABLE_NAME}
|
||||
dev_timer.c
|
||||
dev_evdev.c
|
||||
dev_iio.c
|
||||
dev_hidraw.c
|
||||
|
|
@ -35,7 +38,10 @@ add_executable(${STRAY_EXECUTABLE_NAME}
|
|||
settings.c
|
||||
virt_ds4.c
|
||||
virt_ds5.c
|
||||
virt_mouse.c
|
||||
virt_kbd.c
|
||||
devices_status.c
|
||||
rogue_enemy.c
|
||||
)
|
||||
|
||||
add_executable(${ALLINONE_EXECUTABLE_NAME}
|
||||
|
|
@ -44,7 +50,10 @@ add_executable(${ALLINONE_EXECUTABLE_NAME}
|
|||
settings.c
|
||||
virt_ds4.c
|
||||
virt_ds5.c
|
||||
virt_mouse.c
|
||||
virt_kbd.c
|
||||
devices_status.c
|
||||
dev_timer.c
|
||||
dev_evdev.c
|
||||
dev_iio.c
|
||||
dev_hidraw.c
|
||||
|
|
@ -58,7 +67,7 @@ add_executable(${ALLINONE_EXECUTABLE_NAME}
|
|||
|
||||
set_property(TARGET ${ALLINONE_EXECUTABLE_NAME} PROPERTY C_STANDARD 17)
|
||||
|
||||
target_link_libraries(${ALLINONE_EXECUTABLE_NAME} PRIVATE Threads::Threads -levdev -ludev -lconfig -lm)
|
||||
target_link_libraries(${ALLINONE_EXECUTABLE_NAME} PRIVATE Threads::Threads -levdev -ludev -lconfig -lm -lz)
|
||||
|
||||
set_target_properties(${ALLINONE_EXECUTABLE_NAME} PROPERTIES LINKER_LANGUAGE C)
|
||||
|
||||
|
|
@ -74,7 +83,7 @@ install(TARGETS ${ROGUE_EXECUTABLE_NAME} DESTINATION bin)
|
|||
|
||||
set_property(TARGET ${STRAY_EXECUTABLE_NAME} PROPERTY C_STANDARD 17)
|
||||
|
||||
target_link_libraries(${STRAY_EXECUTABLE_NAME} PRIVATE Threads::Threads -levdev -ludev -lconfig -lm)
|
||||
target_link_libraries(${STRAY_EXECUTABLE_NAME} PRIVATE Threads::Threads -levdev -ludev -lconfig -lm -lz)
|
||||
|
||||
set_target_properties(${STRAY_EXECUTABLE_NAME} PROPERTIES LINKER_LANGUAGE C)
|
||||
|
||||
|
|
|
|||
22
References/Ally/left_back_paddle.log
Normal file
22
References/Ally/left_back_paddle.log
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
Event: time 1702734480.395212, type 4 (EV_MSC), code 4 (MSC_SCAN), value 70069
|
||||
Event: time 1702734480.395212, type 1 (EV_KEY), code 184 (KEY_F14), value 1
|
||||
Event: time 1702734480.395212, -------------- SYN_REPORT ------------
|
||||
Event: time 1702734480.666881, type 1 (EV_KEY), code 184 (KEY_F14), value 2
|
||||
Event: time 1702734480.666881, -------------- SYN_REPORT ------------
|
||||
Event: time 1702734480.703572, type 1 (EV_KEY), code 184 (KEY_F14), value 2
|
||||
Event: time 1702734480.703572, -------------- SYN_REPORT ------------
|
||||
Event: time 1702734480.740210, type 1 (EV_KEY), code 184 (KEY_F14), value 2
|
||||
Event: time 1702734480.740210, -------------- SYN_REPORT ------------
|
||||
Event: time 1702734480.776877, type 1 (EV_KEY), code 184 (KEY_F14), value 2
|
||||
Event: time 1702734480.776877, -------------- SYN_REPORT ------------
|
||||
Event: time 1702734480.813547, type 1 (EV_KEY), code 184 (KEY_F14), value 2
|
||||
Event: time 1702734480.813547, -------------- SYN_REPORT ------------
|
||||
Event: time 1702734480.850210, type 1 (EV_KEY), code 184 (KEY_F14), value 2
|
||||
Event: time 1702734480.850210, -------------- SYN_REPORT ------------
|
||||
Event: time 1702734480.890215, type 1 (EV_KEY), code 184 (KEY_F14), value 2
|
||||
Event: time 1702734480.890215, -------------- SYN_REPORT ------------
|
||||
Event: time 1702734480.930212, type 1 (EV_KEY), code 184 (KEY_F14), value 2
|
||||
Event: time 1702734480.930212, -------------- SYN_REPORT ------------
|
||||
Event: time 1702734480.943181, type 4 (EV_MSC), code 4 (MSC_SCAN), value 70069
|
||||
Event: time 1702734480.943181, type 1 (EV_KEY), code 184 (KEY_F14), value 0
|
||||
Event: time 1702734480.943181, -------------- SYN_REPORT ------------
|
||||
18
References/Ally/left_screen_button_long.log
Normal file
18
References/Ally/left_screen_button_long.log
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
Event: time 1702734659.559525, type 4 (EV_MSC), code 4 (MSC_SCAN), value 700e0
|
||||
Event: time 1702734659.559525, type 1 (EV_KEY), code 29 (KEY_LEFTCTRL), value 1
|
||||
Event: time 1702734659.559525, -------------- SYN_REPORT ------------
|
||||
Event: time 1702734659.560490, type 4 (EV_MSC), code 4 (MSC_SCAN), value 700e2
|
||||
Event: time 1702734659.560490, type 1 (EV_KEY), code 56 (KEY_LEFTALT), value 1
|
||||
Event: time 1702734659.560490, -------------- SYN_REPORT ------------
|
||||
Event: time 1702734659.561435, type 4 (EV_MSC), code 4 (MSC_SCAN), value 7004c
|
||||
Event: time 1702734659.561435, type 1 (EV_KEY), code 111 (KEY_DELETE), value 1
|
||||
Event: time 1702734659.561435, -------------- SYN_REPORT ------------
|
||||
Event: time 1702734659.562485, type 4 (EV_MSC), code 4 (MSC_SCAN), value 700e0
|
||||
Event: time 1702734659.562485, type 1 (EV_KEY), code 29 (KEY_LEFTCTRL), value 0
|
||||
Event: time 1702734659.562485, -------------- SYN_REPORT ------------
|
||||
Event: time 1702734659.563486, type 4 (EV_MSC), code 4 (MSC_SCAN), value 700e2
|
||||
Event: time 1702734659.563486, type 1 (EV_KEY), code 56 (KEY_LEFTALT), value 0
|
||||
Event: time 1702734659.563486, -------------- SYN_REPORT ------------
|
||||
Event: time 1702734659.565433, type 4 (EV_MSC), code 4 (MSC_SCAN), value 7004c
|
||||
Event: time 1702734659.565433, type 1 (EV_KEY), code 111 (KEY_DELETE), value 0
|
||||
Event: time 1702734659.565433, -------------- SYN_REPORT ------------
|
||||
6
References/Ally/left_screen_button_short.log
Normal file
6
References/Ally/left_screen_button_short.log
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
Event: time 1702734692.300847, type 4 (EV_MSC), code 4 (MSC_SCAN), value ff3100a6
|
||||
Event: time 1702734692.300847, type 1 (EV_KEY), code 186 (KEY_F16), value 1
|
||||
Event: time 1702734692.300847, -------------- SYN_REPORT ------------
|
||||
Event: time 1702734692.301778, type 4 (EV_MSC), code 4 (MSC_SCAN), value ff3100a6
|
||||
Event: time 1702734692.301778, type 1 (EV_KEY), code 186 (KEY_F16), value 0
|
||||
Event: time 1702734692.301778, -------------- SYN_REPORT ------------
|
||||
14
References/Ally/right_back_paddle.log
Normal file
14
References/Ally/right_back_paddle.log
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
Event: time 1702734541.227670, type 4 (EV_MSC), code 4 (MSC_SCAN), value 7006a
|
||||
Event: time 1702734541.227670, type 1 (EV_KEY), code 185 (KEY_F15), value 1
|
||||
Event: time 1702734541.227670, -------------- SYN_REPORT ------------
|
||||
Event: time 1702734541.490206, type 1 (EV_KEY), code 185 (KEY_F15), value 2
|
||||
Event: time 1702734541.490206, -------------- SYN_REPORT ------------
|
||||
Event: time 1702734541.530208, type 1 (EV_KEY), code 185 (KEY_F15), value 2
|
||||
Event: time 1702734541.530208, -------------- SYN_REPORT ------------
|
||||
Event: time 1702734541.570205, type 1 (EV_KEY), code 185 (KEY_F15), value 2
|
||||
Event: time 1702734541.570205, -------------- SYN_REPORT ------------
|
||||
Event: time 1702734541.606872, type 1 (EV_KEY), code 185 (KEY_F15), value 2
|
||||
Event: time 1702734541.606872, -------------- SYN_REPORT ------------
|
||||
Event: time 1702734541.640678, type 4 (EV_MSC), code 4 (MSC_SCAN), value 7006a
|
||||
Event: time 1702734541.640678, type 1 (EV_KEY), code 185 (KEY_F15), value 0
|
||||
Event: time 1702734541.640678, -------------- SYN_REPORT ------------
|
||||
17
References/Ally/right_screen_button_long.log
Normal file
17
References/Ally/right_screen_button_long.log
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
Event: time 1702734610.835523, type 4 (EV_MSC), code 4 (MSC_SCAN), value ff3100a7
|
||||
Event: time 1702734610.835523, type 1 (EV_KEY), code 187 (KEY_F17), value 1
|
||||
Event: time 1702734610.835523, -------------- SYN_REPORT ------------
|
||||
Event: time 1702734610.836480, type 4 (EV_MSC), code 4 (MSC_SCAN), value ff3100a7
|
||||
Event: time 1702734610.836480, type 1 (EV_KEY), code 187 (KEY_F17), value 0
|
||||
Event: time 1702734610.836480, -------------- SYN_REPORT ------------
|
||||
|
||||
|
||||
F17 appears before release
|
||||
|
||||
|
||||
Event: time 1702734611.433499, type 4 (EV_MSC), code 4 (MSC_SCAN), value ff3100a8
|
||||
Event: time 1702734611.433499, type 1 (EV_KEY), code 188 (KEY_F18), value 1
|
||||
Event: time 1702734611.433499, -------------- SYN_REPORT ------------
|
||||
Event: time 1702734611.434434, type 4 (EV_MSC), code 4 (MSC_SCAN), value ff3100a8
|
||||
Event: time 1702734611.434434, type 1 (EV_KEY), code 188 (KEY_F18), value 0
|
||||
Event: time 1702734611.434434, -------------- SYN_REPORT ------------
|
||||
6
References/Ally/right_screen_button_short.log
Normal file
6
References/Ally/right_screen_button_short.log
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
Event: time 1702734588.908929, type 4 (EV_MSC), code 4 (MSC_SCAN), value ff310038
|
||||
Event: time 1702734588.908929, type 1 (EV_KEY), code 148 (KEY_PROG1), value 1
|
||||
Event: time 1702734588.908929, -------------- SYN_REPORT ------------
|
||||
Event: time 1702734588.909906, type 4 (EV_MSC), code 4 (MSC_SCAN), value ff310038
|
||||
Event: time 1702734588.909906, type 1 (EV_KEY), code 148 (KEY_PROG1), value 0
|
||||
Event: time 1702734588.909906, -------------- SYN_REPORT ------------
|
||||
78
allynone.c
78
allynone.c
|
|
@ -10,51 +10,66 @@
|
|||
#include "rog_ally.h"
|
||||
#include "legion_go.h"
|
||||
|
||||
/*
|
||||
logic_t global_logic;
|
||||
|
||||
static output_dev_t out_gamepadd_dev = {
|
||||
.logic = &global_logic,
|
||||
};
|
||||
|
||||
void sig_handler(int signo)
|
||||
{
|
||||
if (signo == SIGINT) {
|
||||
logic_request_termination(&global_logic);
|
||||
printf("Received SIGINT\n");
|
||||
}
|
||||
}
|
||||
*/
|
||||
#include <sys/mman.h>
|
||||
|
||||
static const char* configuration_file = "/etc/ROGueENEMY/config.cfg";
|
||||
|
||||
controller_settings_t settings;
|
||||
|
||||
int main(int argc, char ** argv) {
|
||||
// Lock all current and future pages from preventing of being paged to swap
|
||||
const int lockall_res = mlockall( MCL_CURRENT | MCL_FUTURE );
|
||||
if (lockall_res) {
|
||||
fprintf(stderr, "mlockall failed: %d", lockall_res);
|
||||
}
|
||||
|
||||
int ret = 0;
|
||||
|
||||
init_config(&settings);
|
||||
fill_config(&settings, configuration_file);
|
||||
// fill in configuration from file: automatic fallback to default
|
||||
dev_in_settings_t in_settings = {
|
||||
.enable_qam = true,
|
||||
.ff_gain = 0xFFFF,
|
||||
.rumble_on_mode_switch = true,
|
||||
.m1m2_mode = 0,
|
||||
.touchbar = true,
|
||||
.enable_thermal_profiles_switching = false,
|
||||
.default_thermal_profile = -1,
|
||||
.enable_leds_commands = false,
|
||||
.enable_imu = true,
|
||||
.imu_polling_interface = true,
|
||||
};
|
||||
|
||||
load_in_config(&in_settings, configuration_file);
|
||||
|
||||
dev_out_settings_t out_settings = {
|
||||
.default_gamepad = 0,
|
||||
.nintendo_layout = false,
|
||||
.gamepad_leds_control = true,
|
||||
.gamepad_rumble_control = true,
|
||||
.controller_bluetooth = false,
|
||||
.dualsense_edge = false,
|
||||
.swap_y_z = false,
|
||||
.invert_x = false,
|
||||
.gyro_to_analog_activation_treshold = 16,
|
||||
.gyro_to_analog_mapping = 4,
|
||||
};
|
||||
|
||||
load_out_config(&out_settings, configuration_file);
|
||||
|
||||
input_dev_composite_t* in_devs = NULL;
|
||||
|
||||
int dmi_name_fd = open("/sys/class/dmi/id/board_name", O_RDONLY | O_NONBLOCK);
|
||||
if (dmi_name_fd < 0) {
|
||||
|
||||
char bname[256];
|
||||
if (dmi_board_name(bname, sizeof(bname)) < 0) {
|
||||
fprintf(stderr, "Cannot get the board name\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
char bname[256];
|
||||
memset(bname, 0, sizeof(bname));
|
||||
read(dmi_name_fd, bname, sizeof(bname));
|
||||
if (strstr(bname, "RC71L") != NULL) {
|
||||
printf("Running in an Asus ROG Ally device\n");
|
||||
in_devs = rog_ally_device_def(&settings);
|
||||
in_devs = rog_ally_device_def(&in_settings);
|
||||
} else if (strstr(bname, "LNVNB161216")) {
|
||||
printf("Running in an Lenovo Legion Go device\n");
|
||||
in_devs = legion_go_device_def(&settings);
|
||||
in_devs = legion_go_device_def();
|
||||
}
|
||||
close(dmi_name_fd);
|
||||
|
||||
|
||||
int dev_in_thread_creation = -1;
|
||||
int dev_out_thread_creation = -1;
|
||||
|
|
@ -105,12 +120,12 @@ int main(int argc, char ** argv) {
|
|||
.out_message_pipe_fd = out_message_pipes[0],
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
.settings = in_settings,
|
||||
};
|
||||
|
||||
// populate the output device thread data
|
||||
dev_out_data_t dev_out_thread_data = {
|
||||
.gamepad = GAMEPAD_DUALSENSE,
|
||||
.flags = 0x00000000U,
|
||||
.communication = {
|
||||
.type = ipc_unix_pipe,
|
||||
|
|
@ -120,7 +135,8 @@ int main(int argc, char ** argv) {
|
|||
.out_message_pipe_fd = out_message_pipes[1],
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
.settings = out_settings,
|
||||
};
|
||||
|
||||
pthread_t dev_in_thread;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,20 @@
|
|||
enable_qam = true;
|
||||
ff_gain = 100;
|
||||
ff_gain = 255;
|
||||
nintendo_layout = false;
|
||||
gamepad_output_device = 1;
|
||||
rumble_dedicated_thread = false;
|
||||
default_gamepad = 1;
|
||||
rumble_on_mode_switch = true;
|
||||
gamepad_rumble_control = true;
|
||||
gamepad_leds_control = true;
|
||||
m1m2_mode = 1;
|
||||
gyro_to_analog_mapping = 5;
|
||||
gyro_to_analog_activation_treshold = 1;
|
||||
touchbar = true;
|
||||
controller_bluetooth = true;
|
||||
dualsense_edge = false;
|
||||
swap_y_z = true;
|
||||
invert_x = true;
|
||||
enable_thermal_profiles_switching = true;
|
||||
default_thermal_profile = 3;
|
||||
enable_leds_commands = true;
|
||||
enable_imu = true;
|
||||
imu_polling_interface = true;
|
||||
31
dev_evdev.c
31
dev_evdev.c
|
|
@ -2,6 +2,7 @@
|
|||
#include <libevdev-1.0/libevdev/libevdev.h>
|
||||
|
||||
static const char *input_path = "/dev/input/";
|
||||
static const char *hidden_input_path = "/dev/input/.hidden/";
|
||||
|
||||
static pthread_mutex_t input_acquire_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
|
|
@ -133,6 +134,17 @@ int dev_evdev_open(
|
|||
|
||||
int open_sysfs_idx = -1;
|
||||
|
||||
struct stat st = {0};
|
||||
|
||||
if (stat(hidden_input_path, &st) == -1) {
|
||||
printf("Directory %s does not exits -- creating it\n", hidden_input_path);
|
||||
if (mkdir(hidden_input_path, 0700) == 0) {
|
||||
printf("Directory %s creates successfully", hidden_input_path);
|
||||
} else {
|
||||
fprintf(stderr, "Error creating %s directory: %d\n", hidden_input_path, errno);
|
||||
}
|
||||
}
|
||||
|
||||
const int mutex_lock_res = pthread_mutex_lock(&input_acquire_mutex);
|
||||
if (mutex_lock_res != 0) {
|
||||
fprintf(stderr, "Cannot lock input mutex: %d\n", mutex_lock_res);
|
||||
|
|
@ -146,6 +158,13 @@ int dev_evdev_open(
|
|||
goto dev_evdev_open_err;
|
||||
}
|
||||
|
||||
char *const hidden_path = malloc(MAX_PATH_LEN);
|
||||
if (path == NULL) {
|
||||
free(path);
|
||||
res = -ENOMEM;
|
||||
goto dev_evdev_open_err;
|
||||
}
|
||||
|
||||
DIR *d;
|
||||
struct dirent *dir;
|
||||
d = opendir(input_path);
|
||||
|
|
@ -159,6 +178,7 @@ int dev_evdev_open(
|
|||
continue;
|
||||
}
|
||||
|
||||
snprintf(hidden_path, MAX_PATH_LEN - 1, "%s%s", hidden_input_path, dir->d_name);
|
||||
snprintf(path, MAX_PATH_LEN - 1, "%s%s", input_path, dir->d_name);
|
||||
|
||||
//printf("Testing for device %s\n", path);
|
||||
|
|
@ -199,6 +219,17 @@ int dev_evdev_open(
|
|||
continue;
|
||||
}
|
||||
|
||||
if (rename(path, hidden_path) != 0) {
|
||||
fprintf(stderr, "Unable to move the device: %d\n", errno);
|
||||
libevdev_free(*out_evdev);
|
||||
close(fd);
|
||||
continue;
|
||||
} else {
|
||||
if (chmod(hidden_path, 000) != 0) {
|
||||
fprintf(stderr, "Unable to perform chmod 000 to opened device\n");
|
||||
}
|
||||
}
|
||||
|
||||
// register the device as being opened already
|
||||
open_paths[open_sysfs_idx].sysfs_path = path;
|
||||
open_paths[open_sysfs_idx].fd = fd;
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ int dev_hidraw_open(
|
|||
//printf("Testing for device %s\n", path);
|
||||
|
||||
// try to open the device, if it cannot be opened to go the next
|
||||
int fd = open(path, O_RDWR);
|
||||
int fd = open(path, O_RDWR | O_NONBLOCK);
|
||||
if (fd < 0) {
|
||||
//fprintf(stderr, "Cannot open %s, device skipped.\n", path);
|
||||
continue;
|
||||
|
|
|
|||
375
dev_in.c
375
dev_in.c
|
|
@ -5,14 +5,16 @@
|
|||
#include "message.h"
|
||||
#include "dev_evdev.h"
|
||||
#include "dev_iio.h"
|
||||
#include <libevdev-1.0/libevdev/libevdev.h>
|
||||
#include <linux/input-event-codes.h>
|
||||
#include "dev_timer.h"
|
||||
|
||||
#include <libconfig.h>
|
||||
|
||||
typedef enum dev_in_type {
|
||||
DEV_IN_TYPE_NONE,
|
||||
DEV_IN_TYPE_HIDRAW,
|
||||
DEV_IN_TYPE_IIO,
|
||||
DEV_IN_TYPE_EV,
|
||||
DEV_IN_TYPE_TIMER,
|
||||
} dev_in_type_t;
|
||||
|
||||
typedef struct dev_in_iio {
|
||||
|
|
@ -23,6 +25,10 @@ typedef struct dev_in_iio {
|
|||
|
||||
typedef struct dev_in_hidraw {
|
||||
dev_hidraw_t *hidrawdev;
|
||||
|
||||
hidraw_callbacks_t callbacks;
|
||||
|
||||
void* user_data;
|
||||
} dev_in_hidraw_t;
|
||||
|
||||
typedef struct dev_in_ev {
|
||||
|
|
@ -40,12 +46,29 @@ typedef struct dev_in_ev {
|
|||
|
||||
struct ff_effect ff_effect;
|
||||
|
||||
ev_callbacks_t callbacks;
|
||||
|
||||
void* user_data;
|
||||
|
||||
} dev_in_ev_t;
|
||||
|
||||
typedef struct dev_in_timer {
|
||||
|
||||
dev_timer_t* timer;
|
||||
|
||||
const char* name;
|
||||
|
||||
timer_callbacks_t callbacks;
|
||||
|
||||
void* user_data;
|
||||
|
||||
} dev_in_timer_t;
|
||||
|
||||
typedef union dev_in_aggr {
|
||||
dev_in_ev_t evdev;
|
||||
dev_in_iio_t iio;
|
||||
dev_in_hidraw_t hidraw;
|
||||
dev_in_timer_t timer;
|
||||
} dev_in_aggr_t;
|
||||
|
||||
typedef struct dev_in {
|
||||
|
|
@ -68,7 +91,30 @@ static int map_message_from_iio(dev_in_iio_t *const in_iio, in_message_t *const
|
|||
goto send_message_from_iio_err;
|
||||
}
|
||||
|
||||
res = 0;
|
||||
if (res != 24) {
|
||||
fprintf(stderr, "Invalid read lenght\n");
|
||||
res = -EIO;
|
||||
goto send_message_from_iio_err;
|
||||
}
|
||||
|
||||
uint16_t *const scan_elements = (uint16_t*)&data[0];
|
||||
int64_t *const timestamp = (int64_t*)&data[16]; // either that or (int64_t*)&data[12]
|
||||
|
||||
messages[0].type = GAMEPAD_SET_ELEMENT;
|
||||
messages[0].data.gamepad_set.element = GAMEPAD_ACCELEROMETER;
|
||||
messages[1].data.gamepad_set.status.accel.sample_timestamp_ns = *timestamp;
|
||||
messages[0].data.gamepad_set.status.accel.x = scan_elements[0];
|
||||
messages[0].data.gamepad_set.status.accel.y = (uint16_t)(-1) * scan_elements[2];
|
||||
messages[0].data.gamepad_set.status.accel.z = scan_elements[1];
|
||||
|
||||
messages[1].type = GAMEPAD_SET_ELEMENT;
|
||||
messages[1].data.gamepad_set.element = GAMEPAD_GYROSCOPE;
|
||||
messages[1].data.gamepad_set.status.gyro.sample_timestamp_ns = *timestamp;
|
||||
messages[1].data.gamepad_set.status.gyro.x = scan_elements[3];
|
||||
messages[1].data.gamepad_set.status.gyro.y = (uint16_t)(-1) * scan_elements[5];
|
||||
messages[1].data.gamepad_set.status.gyro.z = scan_elements[4];
|
||||
|
||||
res = 2;
|
||||
|
||||
send_message_from_iio_err:
|
||||
return res;
|
||||
|
|
@ -120,7 +166,25 @@ fill_message_from_evdev_err_completed:
|
|||
return res;
|
||||
}
|
||||
|
||||
static int timer_open_device(
|
||||
const dev_in_settings_t *const in_settings,
|
||||
const timer_filters_t *const in_filters,
|
||||
dev_in_timer_t *const out_dev
|
||||
) {
|
||||
int res = dev_timer_open(in_filters, &out_dev->timer);
|
||||
if (res != 0) {
|
||||
fprintf(stderr, "Unable to open the timer device: %d\n", res);
|
||||
goto timer_open_device_err;
|
||||
}
|
||||
|
||||
printf("Opened timer device: %s\n", in_filters->name);
|
||||
|
||||
timer_open_device_err:
|
||||
return res;
|
||||
}
|
||||
|
||||
static int hidraw_open_device(
|
||||
const dev_in_settings_t *const in_settings,
|
||||
const hidraw_filters_t *const in_filters,
|
||||
dev_in_hidraw_t *const out_dev
|
||||
) {
|
||||
|
|
@ -141,6 +205,7 @@ iio_open_device_err:
|
|||
}
|
||||
|
||||
static int iio_open_device(
|
||||
const dev_in_settings_t *const in_settings,
|
||||
const iio_filters_t *const in_filters,
|
||||
dev_in_iio_t *const out_dev
|
||||
) {
|
||||
|
|
@ -164,6 +229,7 @@ iio_open_device_err:
|
|||
}
|
||||
|
||||
static int evdev_open_device(
|
||||
const dev_in_settings_t *const in_settings,
|
||||
const uinput_filters_t *const in_filters,
|
||||
dev_in_ev_t *const out_dev
|
||||
) {
|
||||
|
|
@ -196,14 +262,14 @@ static int evdev_open_device(
|
|||
out_dev->ff_effect.type = FF_RUMBLE;
|
||||
out_dev->ff_effect.id = -1;
|
||||
out_dev->ff_effect.replay.delay = 0;
|
||||
out_dev->ff_effect.replay.length = 5000;
|
||||
out_dev->ff_effect.replay.length = 1000;
|
||||
out_dev->ff_effect.u.rumble.strong_magnitude = 0x0000;
|
||||
out_dev->ff_effect.u.rumble.weak_magnitude = 0x0000;
|
||||
|
||||
const struct input_event gain = {
|
||||
.type = EV_FF,
|
||||
.code = FF_GAIN,
|
||||
.value = 0xFFFF, // TODO: give the user the ability to change this
|
||||
.value = in_settings->ff_gain,
|
||||
};
|
||||
|
||||
const int gain_set_res = write(libevdev_get_fd(out_dev->evdev), (const void*)&gain, sizeof(gain));
|
||||
|
|
@ -232,7 +298,11 @@ static void hidraw_close_device(dev_in_hidraw_t *const out_hidraw) {
|
|||
dev_hidraw_close(out_hidraw->hidrawdev);
|
||||
}
|
||||
|
||||
static void handle_rumble_device(dev_in_ev_t *const in_dev, const out_message_rumble_t *const in_rumble_msg) {
|
||||
static void timer_close_device(dev_in_timer_t *const out_hidraw) {
|
||||
dev_timer_close(out_hidraw->timer);
|
||||
}
|
||||
|
||||
static void handle_rumble_device(const dev_in_settings_t *const conf, dev_in_ev_t *const in_dev, const out_message_rumble_t *const in_rumble_msg) {
|
||||
if (!in_dev->has_rumble_support) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -281,10 +351,57 @@ static void handle_rumble_device(dev_in_ev_t *const in_dev, const out_message_ru
|
|||
}
|
||||
}
|
||||
|
||||
static void handle_rumble(dev_in_t *const in_devs, size_t in_devs_count, const out_message_rumble_t *const in_rumble_msg) {
|
||||
static void handle_rumble(const dev_in_settings_t *const conf, dev_in_t *const in_devs, size_t in_devs_count, const out_message_rumble_t *const in_rumble_msg) {
|
||||
for (size_t i = 0; i < in_devs_count; ++i) {
|
||||
if (in_devs[i].type == DEV_IN_TYPE_EV) {
|
||||
handle_rumble_device(&in_devs[i].dev.evdev, in_rumble_msg);
|
||||
handle_rumble_device(
|
||||
conf,
|
||||
&in_devs[i].dev.evdev,
|
||||
in_rumble_msg
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_leds(const dev_in_settings_t *const conf, dev_in_t *const in_devs, size_t in_devs_count, const out_message_leds_t *const in_leds_msg) {
|
||||
for (size_t i = 0; i < in_devs_count; ++i) {
|
||||
if (in_devs[i].type == DEV_IN_TYPE_HIDRAW) {
|
||||
in_devs[i].dev.hidraw.callbacks.leds_callback(
|
||||
conf,
|
||||
in_devs[i].dev.hidraw.hidrawdev->fd,
|
||||
in_leds_msg->r,
|
||||
in_leds_msg->g,
|
||||
in_leds_msg->b,
|
||||
in_devs[i].dev.hidraw.user_data
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_timeout(
|
||||
const dev_in_settings_t *const conf,
|
||||
dev_in_t *const in_devs,
|
||||
size_t in_devs_count,
|
||||
const char* name,
|
||||
uint64_t expirations
|
||||
) {
|
||||
for (size_t i = 0; i < in_devs_count; ++i) {
|
||||
if (in_devs[i].type == DEV_IN_TYPE_EV) {
|
||||
in_devs[i].dev.evdev.callbacks.timeout_callback(
|
||||
conf,
|
||||
in_devs[i].dev.evdev.evdev,
|
||||
name,
|
||||
expirations,
|
||||
in_devs[i].dev.evdev.user_data
|
||||
);
|
||||
} else if (in_devs[i].type == DEV_IN_TYPE_HIDRAW) {
|
||||
in_devs[i].dev.hidraw.callbacks.timeout_callback(
|
||||
conf,
|
||||
dev_hidraw_get_fd(in_devs[i].dev.hidraw.hidrawdev),
|
||||
name,
|
||||
expirations,
|
||||
in_devs[i].dev.hidraw.user_data
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -292,7 +409,7 @@ static void handle_rumble(dev_in_t *const in_devs, size_t in_devs_count, const o
|
|||
static int open_socket(struct sockaddr_un *serveraddr) {
|
||||
int res = -ENODEV;
|
||||
|
||||
int sd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
|
||||
int sd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (sd < 0)
|
||||
{
|
||||
res = sd;
|
||||
|
|
@ -314,23 +431,15 @@ void* dev_in_thread_func(void *ptr) {
|
|||
dev_in_data_t *const dev_in_data = (dev_in_data_t*)ptr;
|
||||
|
||||
void* platform_data;
|
||||
const int platform_init_res = dev_in_data->input_dev_decl->init_fn(&platform_data);
|
||||
const int platform_init_res = dev_in_data->input_dev_decl->init_fn(&dev_in_data->settings, &platform_data);
|
||||
if (platform_init_res != 0) {
|
||||
fprintf(stderr, "Error setting up platform data: %d\n", platform_init_res);
|
||||
}
|
||||
|
||||
struct timeval timeout = {
|
||||
.tv_sec = (__time_t)dev_in_data->timeout_ms / (__time_t)1000,
|
||||
.tv_usec = ((__suseconds_t)dev_in_data->timeout_ms % (__suseconds_t)1000) * (__suseconds_t)1000000,
|
||||
};
|
||||
|
||||
fd_set read_fds;
|
||||
|
||||
const size_t max_devices = dev_in_data->input_dev_decl->dev_count;
|
||||
|
||||
in_message_t* controller_msg = malloc(sizeof(in_message_t) * 4);
|
||||
size_t controller_msg_avail = controller_msg == NULL ? 0 : 4;
|
||||
|
||||
dev_in_t* const devices = malloc(sizeof(dev_in_t) * max_devices);
|
||||
if (devices == NULL) {
|
||||
fprintf(stderr, "Unable to allocate memory to hold devices -- aborting input thread\n");
|
||||
|
|
@ -364,6 +473,8 @@ void* dev_in_thread_func(void *ptr) {
|
|||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
FD_SET(dev_in_data->communication.endpoint.socket.fd, &read_fds);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < max_devices; ++i) {
|
||||
|
|
@ -374,36 +485,86 @@ void* dev_in_thread_func(void *ptr) {
|
|||
FD_SET(dev_iio_get_buffer_fd(devices[i].dev.iio.iiodev), &read_fds);
|
||||
} else if (devices[i].type == DEV_IN_TYPE_HIDRAW) {
|
||||
FD_SET(dev_hidraw_get_fd(devices[i].dev.hidraw.hidrawdev), &read_fds);
|
||||
} else if (devices[i].type == DEV_IN_TYPE_TIMER) {
|
||||
FD_SET(dev_timer_get_fd(devices[i].dev.timer.timer), &read_fds);
|
||||
} else if (devices[i].type == DEV_IN_TYPE_NONE) {
|
||||
const input_dev_type_t d_type = dev_in_data->input_dev_decl->dev[i]->dev_type;
|
||||
if (d_type == input_dev_type_uinput) {
|
||||
fprintf(stderr, "Device (evdev) %zu not found -- Attempt reconnection for device named %s\n", i, dev_in_data->input_dev_decl->dev[i]->filters.ev.name);
|
||||
|
||||
const int open_res = evdev_open_device(&dev_in_data->input_dev_decl->dev[i]->filters.ev, &devices[i].dev.evdev);
|
||||
const int open_res = evdev_open_device(
|
||||
&dev_in_data->settings,
|
||||
&dev_in_data->input_dev_decl->dev[i]->filters.ev,
|
||||
&devices[i].dev.evdev
|
||||
);
|
||||
|
||||
if (open_res == 0) {
|
||||
devices[i].type = DEV_IN_TYPE_EV;
|
||||
devices[i].dev.evdev.user_data = dev_in_data->input_dev_decl->dev[i]->user_data;
|
||||
devices[i].dev.evdev.callbacks = dev_in_data->input_dev_decl->dev[i]->map.ev_callbacks;
|
||||
|
||||
// device is now connected, query it in select
|
||||
FD_SET(libevdev_get_fd(devices[i].dev.evdev.evdev), &read_fds);
|
||||
}
|
||||
} else if (d_type == input_dev_type_iio) {
|
||||
fprintf(stderr, "Device (iio) %zu not found -- Attempt reconnection for device named %s\n", i, dev_in_data->input_dev_decl->dev[i]->filters.iio.name);
|
||||
|
||||
const int open_res = iio_open_device(&dev_in_data->input_dev_decl->dev[i]->filters.iio, &devices[i].dev.iio);
|
||||
|
||||
const int open_res = iio_open_device(
|
||||
&dev_in_data->settings,
|
||||
&dev_in_data->input_dev_decl->dev[i]->filters.iio,
|
||||
&devices[i].dev.iio
|
||||
);
|
||||
|
||||
if (open_res == 0) {
|
||||
devices[i].type = DEV_IN_TYPE_IIO;
|
||||
|
||||
// device is now connected, query it in select
|
||||
FD_SET(dev_iio_get_buffer_fd(devices[i].dev.iio.iiodev), &read_fds);
|
||||
}
|
||||
} else if (d_type == input_dev_type_hidraw) {
|
||||
fprintf(stderr, "Device (hidraw) %zu not found -- Attempt reconnection for device %x:%x\n", i, dev_in_data->input_dev_decl->dev[i]->filters.hidraw.pid, dev_in_data->input_dev_decl->dev[i]->filters.hidraw.vid);
|
||||
|
||||
const int open_res = hidraw_open_device(&dev_in_data->input_dev_decl->dev[i]->filters.hidraw, &devices[i].dev.hidraw);
|
||||
|
||||
const int open_res = hidraw_open_device(
|
||||
&dev_in_data->settings,
|
||||
&dev_in_data->input_dev_decl->dev[i]->filters.hidraw,
|
||||
&devices[i].dev.hidraw
|
||||
);
|
||||
|
||||
if (open_res == 0) {
|
||||
devices[i].dev.hidraw.callbacks = dev_in_data->input_dev_decl->dev[i]->map.hidraw_callbacks;
|
||||
devices[i].dev.hidraw.user_data = dev_in_data->input_dev_decl->dev[i]->user_data;
|
||||
devices[i].type = DEV_IN_TYPE_HIDRAW;
|
||||
|
||||
// device is now connected, query it in select
|
||||
FD_SET(dev_hidraw_get_fd(devices[i].dev.hidraw.hidrawdev), &read_fds);
|
||||
}
|
||||
} else if (d_type == input_dev_type_timer) {
|
||||
fprintf(stderr, "Device (timer) %zu not found -- Attempt to create it with name %s\n", i, dev_in_data->input_dev_decl->dev[i]->filters.timer.name);
|
||||
|
||||
const int open_res = timer_open_device(
|
||||
&dev_in_data->settings,
|
||||
&dev_in_data->input_dev_decl->dev[i]->filters.timer,
|
||||
&devices[i].dev.timer
|
||||
);
|
||||
|
||||
if (open_res == 0) {
|
||||
devices[i].dev.timer.callbacks = dev_in_data->input_dev_decl->dev[i]->map.timer_callbacks;
|
||||
devices[i].dev.timer.user_data = dev_in_data->input_dev_decl->dev[i]->user_data;
|
||||
devices[i].dev.timer.name = dev_in_data->input_dev_decl->dev[i]->filters.timer.name;
|
||||
devices[i].type = DEV_IN_TYPE_TIMER;
|
||||
|
||||
// device is now connected, query it in select
|
||||
FD_SET(dev_timer_get_fd(devices[i].dev.timer.timer), &read_fds);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct timeval timeout = {
|
||||
.tv_sec = (__time_t)dev_in_data->timeout_ms / (__time_t)1000,
|
||||
.tv_usec = ((__suseconds_t)dev_in_data->timeout_ms % (__suseconds_t)1000) * (__suseconds_t)1000000,
|
||||
};
|
||||
|
||||
int ready_fds = select(FD_SETSIZE, &read_fds, NULL, NULL, &timeout);
|
||||
|
||||
if (ready_fds == -1) {
|
||||
|
|
@ -412,6 +573,7 @@ void* dev_in_thread_func(void *ptr) {
|
|||
continue;
|
||||
} else if (ready_fds == 0) {
|
||||
// Timeout... simply retry
|
||||
printf("TIMEOUT\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -428,18 +590,22 @@ void* dev_in_thread_func(void *ptr) {
|
|||
const ssize_t out_message_pipe_read_res = read(out_message_fd, (void*)&out_msg, sizeof(out_message_t));
|
||||
if (out_message_pipe_read_res == sizeof(out_message_t)) {
|
||||
if (out_msg.type == OUT_MSG_TYPE_RUMBLE) {
|
||||
handle_rumble(devices, max_devices, &out_msg.data.rumble);
|
||||
handle_rumble(&dev_in_data->settings, devices, max_devices, &out_msg.data.rumble);
|
||||
} else if (out_msg.type == OUT_MSG_TYPE_LEDS) {
|
||||
// first inform the platform
|
||||
const int platform_leds_res = dev_in_data->input_dev_decl->leds_fn(out_msg.data.leds.r, out_msg.data.leds.g, out_msg.data.leds.b, platform_data);
|
||||
const int platform_leds_res = dev_in_data->input_dev_decl->leds_fn(
|
||||
&dev_in_data->settings,
|
||||
out_msg.data.leds.r, out_msg.data.leds.g,
|
||||
out_msg.data.leds.b, platform_data
|
||||
);
|
||||
if (platform_leds_res != 0) {
|
||||
fprintf(stderr, "Error in changing platform LEDs: %d\n", platform_leds_res);
|
||||
}
|
||||
|
||||
// TODO: handle_leds()
|
||||
handle_leds(&dev_in_data->settings, devices, max_devices, &out_msg.data.leds);
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Error reading from out_message_pipe_fd: got %zu bytes, expected %zu butes\n", out_message_pipe_read_res, sizeof(out_message_t));
|
||||
fprintf(stderr, "Error reading from out_message_pipe_fd: got %zu bytes, expected %zu bytes\n", out_message_pipe_read_res, sizeof(out_message_t));
|
||||
|
||||
// in case of an error reschedule to socket for reconnection
|
||||
if (dev_in_data->communication.type == ipc_client_socket) {
|
||||
|
|
@ -458,6 +624,8 @@ void* dev_in_thread_func(void *ptr) {
|
|||
fd = dev_iio_get_buffer_fd(devices[i].dev.iio.iiodev);
|
||||
} else if (devices[i].type == DEV_IN_TYPE_HIDRAW) {
|
||||
fd = dev_hidraw_get_fd(devices[i].dev.hidraw.hidrawdev);
|
||||
} else if (devices[i].type == DEV_IN_TYPE_TIMER) {
|
||||
fd = dev_timer_get_fd(devices[i].dev.timer.timer);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -466,55 +634,92 @@ void* dev_in_thread_func(void *ptr) {
|
|||
continue;
|
||||
}
|
||||
|
||||
int controller_msg_count = -ENOMEM;
|
||||
while (controller_msg_count == -ENOMEM) {
|
||||
// the following part fills controller_msg and writes in controller_msg_count an error or the number of messages to be sent to the output device
|
||||
if (devices[i].type == DEV_IN_TYPE_EV) {
|
||||
evdev_collected_t coll = {
|
||||
.ev_count = 0
|
||||
};
|
||||
in_message_t controller_msg[MAX_IN_MESSAGES];
|
||||
size_t controller_msg_avail = sizeof(controller_msg) / sizeof(in_message_t);
|
||||
int controller_msg_count = -EIO;
|
||||
|
||||
controller_msg_count = fill_message_from_evdev(&devices[i].dev.evdev, &coll);
|
||||
if (controller_msg_count != 0) {
|
||||
fprintf(stderr, "Unable to fill input_event(s) for device %zd: %d -- Will reconnect the device\n", i, controller_msg_count);
|
||||
evdev_close_device(&devices[i].dev.evdev);
|
||||
devices[i].type = DEV_IN_TYPE_NONE;
|
||||
continue;
|
||||
}
|
||||
// the following part fills controller_msg and writes in controller_msg_count an error or the number of messages to be sent to the output device
|
||||
if (devices[i].type == DEV_IN_TYPE_EV) {
|
||||
evdev_collected_t coll = {
|
||||
.ev_count = 0
|
||||
};
|
||||
|
||||
controller_msg_count = dev_in_data->input_dev_decl->dev[i]->map.ev_input_map_fn(&coll, controller_msg, controller_msg_avail, dev_in_data->input_dev_decl->dev[i]->user_data);
|
||||
} else if (devices[i].type == DEV_IN_TYPE_IIO) {
|
||||
controller_msg_count = map_message_from_iio(&devices[i].dev.iio, controller_msg, controller_msg_avail);
|
||||
if (controller_msg_count != 0) {
|
||||
fprintf(stderr, "Error in performing operations for device %zd: %d -- Will reconnect to the device\n", i, controller_msg_count);
|
||||
iio_close_device(&devices[i].dev.iio);
|
||||
devices[i].type = DEV_IN_TYPE_NONE;
|
||||
continue;
|
||||
}
|
||||
} else if (devices[i].type == DEV_IN_TYPE_HIDRAW) {
|
||||
controller_msg_count = dev_in_data->input_dev_decl->dev[i]->map.hidraw_input_map_fn(dev_hidraw_get_fd(devices[i].dev.hidraw.hidrawdev), controller_msg, controller_msg_avail, dev_in_data->input_dev_decl->dev[i]->user_data);
|
||||
if (controller_msg_count != 0) {
|
||||
fprintf(stderr, "Error in performing operations for device %zd: %d -- Will reconnect to the device\n", i, controller_msg_count);
|
||||
hidraw_close_device(&devices[i].dev.hidraw);
|
||||
devices[i].type = DEV_IN_TYPE_NONE;
|
||||
continue;
|
||||
}
|
||||
controller_msg_count = fill_message_from_evdev(&devices[i].dev.evdev, &coll);
|
||||
if (controller_msg_count != 0) {
|
||||
fprintf(stderr, "Unable to fill input_event(s) for device %zd: %d -- Will reconnect the device\n", i, controller_msg_count);
|
||||
evdev_close_device(&devices[i].dev.evdev);
|
||||
devices[i].type = DEV_IN_TYPE_NONE;
|
||||
continue;
|
||||
}
|
||||
|
||||
// attempt to acquire more memory
|
||||
if (controller_msg_count == -ENOMEM) {
|
||||
printf("Map function reported not enough memory, allocating new one...\n");
|
||||
const size_t tmp_controller_msg_avail = controller_msg_avail * 2;
|
||||
in_message_t *tmp_controller_msg = malloc(sizeof(in_message_t) * tmp_controller_msg_avail);
|
||||
if (tmp_controller_msg == NULL) {
|
||||
fprintf(stderr, "Could not allocate new memory -- will retry\n");
|
||||
} else {
|
||||
printf("Allocated new memory to fill the buffer\n");
|
||||
free(controller_msg);
|
||||
controller_msg = tmp_controller_msg;
|
||||
controller_msg_avail = tmp_controller_msg_avail;
|
||||
}
|
||||
controller_msg_count = devices[i].dev.evdev.callbacks.input_map_fn(
|
||||
&dev_in_data->settings,
|
||||
&coll,
|
||||
&controller_msg[0],
|
||||
controller_msg_avail,
|
||||
devices[i].dev.evdev.user_data
|
||||
);
|
||||
} else if (devices[i].type == DEV_IN_TYPE_IIO) {
|
||||
controller_msg_count = map_message_from_iio(
|
||||
&devices[i].dev.iio,
|
||||
&controller_msg[0],
|
||||
controller_msg_avail
|
||||
);
|
||||
|
||||
if (controller_msg_count < 0) {
|
||||
fprintf(stderr, "Error in reading iio buffer for device %zd: %d -- Will reconnect to the device\n", i, controller_msg_count);
|
||||
iio_close_device(&devices[i].dev.iio);
|
||||
devices[i].type = DEV_IN_TYPE_NONE;
|
||||
continue;
|
||||
}
|
||||
} else if (devices[i].type == DEV_IN_TYPE_HIDRAW) {
|
||||
controller_msg_count = devices[i].dev.hidraw.callbacks.map_callback(
|
||||
&dev_in_data->settings,
|
||||
fd,
|
||||
&controller_msg[0],
|
||||
controller_msg_avail,
|
||||
devices[i].dev.hidraw.user_data
|
||||
);
|
||||
|
||||
if (controller_msg_count < 0) {
|
||||
fprintf(stderr, "Error in performing operations for device %zd: %d -- Will reconnect to the device\n", i, controller_msg_count);
|
||||
hidraw_close_device(&devices[i].dev.hidraw);
|
||||
devices[i].type = DEV_IN_TYPE_NONE;
|
||||
continue;
|
||||
}
|
||||
} else if (devices[i].type == DEV_IN_TYPE_TIMER) {
|
||||
uint64_t expirations;
|
||||
ssize_t num_read = read(fd, &expirations, sizeof(uint64_t));
|
||||
if (num_read != sizeof(uint64_t)) {
|
||||
fprintf(stderr, "Error in reading expirations from timer device %zd: %d -- Will reconnect to the device\n", i, controller_msg_count);
|
||||
timer_close_device(&devices[i].dev.timer);
|
||||
devices[i].type = DEV_IN_TYPE_NONE;
|
||||
continue;
|
||||
}
|
||||
|
||||
controller_msg_count = devices[i].dev.timer.callbacks.map_fn(
|
||||
&dev_in_data->settings,
|
||||
fd,
|
||||
expirations,
|
||||
&controller_msg[0],
|
||||
controller_msg_avail,
|
||||
devices[i].dev.timer.user_data
|
||||
);
|
||||
|
||||
if (controller_msg_count < 0) {
|
||||
fprintf(stderr, "Error in timer device %zd: %d -- Will reconnect to the device\n", i, controller_msg_count);
|
||||
timer_close_device(&devices[i].dev.timer);
|
||||
devices[i].type = DEV_IN_TYPE_NONE;
|
||||
continue;
|
||||
}
|
||||
|
||||
handle_timeout(
|
||||
&dev_in_data->settings,
|
||||
devices,
|
||||
max_devices,
|
||||
devices[i].dev.timer.name,
|
||||
expirations
|
||||
);
|
||||
}
|
||||
|
||||
// send messages (if any)
|
||||
|
|
@ -523,18 +728,22 @@ void* dev_in_thread_func(void *ptr) {
|
|||
}
|
||||
|
||||
if (dev_in_data->communication.type == ipc_client_socket) {
|
||||
const int write_res = write(dev_in_data->communication.endpoint.socket.fd, (void*)&controller_msg[0], sizeof(in_message_t) * controller_msg_count);
|
||||
if (write_res < 0) {
|
||||
fprintf(stderr, "Error in writing input event messages: %d -- connection will be drop and retried\n", write_res);
|
||||
for (int msg_idx = 0; msg_idx < controller_msg_count; ++msg_idx) {
|
||||
const int write_res = write(dev_in_data->communication.endpoint.socket.fd, (void*)&controller_msg[msg_idx], sizeof(in_message_t));
|
||||
if (write_res < 0) {
|
||||
fprintf(stderr, "Error in writing input event messages: %d -- connection will be drop and retried\n", write_res);
|
||||
|
||||
// in case of an error reschedule to socket for reconnection
|
||||
close(dev_in_data->communication.endpoint.socket.fd);
|
||||
dev_in_data->communication.endpoint.socket.fd = -1;
|
||||
// in case of an error reschedule to socket for reconnection
|
||||
close(dev_in_data->communication.endpoint.socket.fd);
|
||||
dev_in_data->communication.endpoint.socket.fd = -1;
|
||||
}
|
||||
}
|
||||
} else if (dev_in_data->communication.type == ipc_unix_pipe) {
|
||||
const int write_res = write(dev_in_data->communication.endpoint.pipe.in_message_pipe_fd, (void*)&controller_msg[0], sizeof(in_message_t) * controller_msg_count);
|
||||
if (write_res < 0) {
|
||||
fprintf(stderr, "Error in writing input event messages: %d\n", write_res);
|
||||
for (int msg_idx = 0; msg_idx < controller_msg_count; ++msg_idx) {
|
||||
const int write_res = write(dev_in_data->communication.endpoint.pipe.in_message_pipe_fd, (void*)&controller_msg[msg_idx], sizeof(in_message_t));
|
||||
if (write_res < 0) {
|
||||
fprintf(stderr, "Error in writing input event messages: %d\n", write_res);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -570,14 +779,16 @@ void* dev_in_thread_func(void *ptr) {
|
|||
} else if (devices[i].type == DEV_IN_TYPE_HIDRAW) {
|
||||
hidraw_close_device(&devices[i].dev.hidraw);
|
||||
devices[i].type = DEV_IN_TYPE_NONE;
|
||||
} else if (devices[i].type == DEV_IN_TYPE_TIMER) {
|
||||
timer_close_device(&devices[i].dev.timer);
|
||||
devices[i].type = DEV_IN_TYPE_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: free every fd
|
||||
free(devices);
|
||||
|
||||
if (platform_init_res != 0) {
|
||||
dev_in_data->input_dev_decl->deinit_fn(&platform_data);
|
||||
dev_in_data->input_dev_decl->deinit_fn(&dev_in_data->settings, &platform_data);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
|
|
|||
5
dev_in.h
5
dev_in.h
|
|
@ -3,6 +3,9 @@
|
|||
#include "ipc.h"
|
||||
#include "message.h"
|
||||
#include "input_dev.h"
|
||||
#include "settings.h"
|
||||
|
||||
#define MAX_IN_MESSAGES 8
|
||||
|
||||
#define DEV_IN_FLAG_EXIT 0x00000001U
|
||||
|
||||
|
|
@ -17,6 +20,8 @@ typedef struct dev_in_data {
|
|||
|
||||
ipc_t communication;
|
||||
|
||||
dev_in_settings_t settings;
|
||||
|
||||
volatile uint32_t flags;
|
||||
|
||||
} dev_in_data_t;
|
||||
|
|
|
|||
684
dev_out.c
684
dev_out.c
|
|
@ -5,8 +5,11 @@
|
|||
#include "message.h"
|
||||
#include "virt_ds4.h"
|
||||
#include "virt_ds5.h"
|
||||
#include "virt_mouse.h"
|
||||
#include "virt_kbd.h"
|
||||
|
||||
static void handle_incoming_message_gamepad_action(
|
||||
const dev_out_settings_t *const in_settings,
|
||||
const in_message_gamepad_action_t *const msg_payload,
|
||||
gamepad_status_t *const inout_gamepad
|
||||
) {
|
||||
|
|
@ -17,25 +20,64 @@ static void handle_incoming_message_gamepad_action(
|
|||
}
|
||||
}
|
||||
|
||||
static void handle_incoming_message_mouse_event(
|
||||
const dev_out_settings_t *const in_settings,
|
||||
const in_message_mouse_event_t *const msg_payload,
|
||||
mouse_status_t *const inout_mouse
|
||||
) {
|
||||
if (msg_payload->type == MOUSE_ELEMENT_X) {
|
||||
inout_mouse->x += msg_payload->value;
|
||||
} else if (msg_payload->type == MOUSE_ELEMENT_Y) {
|
||||
inout_mouse->y += msg_payload->value;
|
||||
} else if (msg_payload->type == MOUSE_BTN_LEFT) {
|
||||
inout_mouse->btn_left = msg_payload->value;
|
||||
} else if (msg_payload->type == MOUSE_BTN_MIDDLE) {
|
||||
inout_mouse->btn_middle = msg_payload->value;
|
||||
} else if (msg_payload->type == MOUSE_BTN_RIGHT) {
|
||||
inout_mouse->btn_right = msg_payload->value;
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_incoming_message_gamepad_set(
|
||||
const dev_out_settings_t *const in_settings,
|
||||
const in_message_gamepad_set_element_t *const msg_payload,
|
||||
gamepad_status_t *const inout_gamepad
|
||||
) {
|
||||
switch (msg_payload->element) {
|
||||
case GAMEPAD_BTN_CROSS: {
|
||||
inout_gamepad->cross = msg_payload->status.btn;
|
||||
if (!in_settings->nintendo_layout) {
|
||||
inout_gamepad->cross = msg_payload->status.btn;
|
||||
} else {
|
||||
inout_gamepad->circle = msg_payload->status.btn;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case GAMEPAD_BTN_CIRCLE: {
|
||||
inout_gamepad->circle = msg_payload->status.btn;
|
||||
if (in_settings->nintendo_layout) {
|
||||
inout_gamepad->cross = msg_payload->status.btn;
|
||||
} else {
|
||||
inout_gamepad->circle = msg_payload->status.btn;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case GAMEPAD_BTN_SQUARE: {
|
||||
inout_gamepad->square = msg_payload->status.btn;
|
||||
if (in_settings->nintendo_layout) {
|
||||
inout_gamepad->triangle = msg_payload->status.btn;
|
||||
} else {
|
||||
inout_gamepad->square = msg_payload->status.btn;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case GAMEPAD_BTN_TRIANGLE: {
|
||||
inout_gamepad->triangle = msg_payload->status.btn;
|
||||
if (!in_settings->nintendo_layout) {
|
||||
inout_gamepad->triangle = msg_payload->status.btn;
|
||||
} else {
|
||||
inout_gamepad->square = msg_payload->status.btn;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case GAMEPAD_BTN_OPTION: {
|
||||
|
|
@ -90,6 +132,14 @@ static void handle_incoming_message_gamepad_set(
|
|||
inout_gamepad->touchpad_press = msg_payload->status.btn;
|
||||
break;
|
||||
}
|
||||
case GAMEPAD_BTN_JOIN_LEFT_ANALOG_AND_GYROSCOPE: {
|
||||
inout_gamepad->join_left_analog_and_gyroscope = msg_payload->status.btn;
|
||||
break;
|
||||
}
|
||||
case GAMEPAD_BTN_JOIN_RIGHT_ANALOG_AND_GYROSCOPE: {
|
||||
inout_gamepad->join_right_analog_and_gyroscope = msg_payload->status.btn;
|
||||
break;
|
||||
}
|
||||
case GAMEPAD_LEFT_JOYSTICK_X: {
|
||||
inout_gamepad->joystick_positions[0][0] = msg_payload->status.joystick_pos;
|
||||
break;
|
||||
|
|
@ -134,6 +184,32 @@ static void handle_incoming_message_gamepad_set(
|
|||
|
||||
break;
|
||||
}
|
||||
case GAMEPAD_GYROSCOPE: {
|
||||
inout_gamepad->last_gyro_motion_timestamp_ns = msg_payload->status.gyro.sample_timestamp_ns;
|
||||
inout_gamepad->raw_gyro[0] = in_settings->invert_x ? (int16_t)(-1) * msg_payload->status.gyro.x : msg_payload->status.gyro.x;
|
||||
inout_gamepad->raw_gyro[1] = in_settings->swap_y_z ? msg_payload->status.gyro.z : msg_payload->status.gyro.y;
|
||||
inout_gamepad->raw_gyro[2] = in_settings->swap_y_z ? msg_payload->status.gyro.y : msg_payload->status.gyro.z;
|
||||
break;
|
||||
}
|
||||
case GAMEPAD_ACCELEROMETER: {
|
||||
inout_gamepad->last_accel_motion_timestamp_ns = msg_payload->status.accel.sample_timestamp_ns;
|
||||
inout_gamepad->raw_accel[0] = in_settings->invert_x ? (int16_t)(-1) * msg_payload->status.accel.x : msg_payload->status.accel.x;
|
||||
inout_gamepad->raw_accel[1] = in_settings->swap_y_z ? msg_payload->status.accel.z : msg_payload->status.accel.y;
|
||||
inout_gamepad->raw_accel[2] = in_settings->swap_y_z ? msg_payload->status.accel.y : msg_payload->status.accel.z;
|
||||
break;
|
||||
}
|
||||
case GAMEPAD_TOUCHPAD_TOUCH_ACTIVE: {
|
||||
inout_gamepad->touchpad_touch_num = msg_payload->status.touchpad_active.status;
|
||||
break;
|
||||
}
|
||||
case GAMEPAD_TOUCHPAD_X: {
|
||||
inout_gamepad->touchpad_x = msg_payload->status.touchpad_x.value;
|
||||
break;
|
||||
}
|
||||
case GAMEPAD_TOUCHPAD_Y: {
|
||||
inout_gamepad->touchpad_y = msg_payload->status.touchpad_y.value;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
fprintf(stderr, "Unknown gamepad element: %d\n", msg_payload->element);
|
||||
break;
|
||||
|
|
@ -141,24 +217,174 @@ static void handle_incoming_message_gamepad_set(
|
|||
}
|
||||
}
|
||||
|
||||
static void handle_incoming_message_keyboard_set(
|
||||
const dev_out_settings_t *const in_settings,
|
||||
const in_message_keyboard_set_element_t *const msg_payload,
|
||||
keyboard_status_t *const inout_kbd
|
||||
) {
|
||||
switch (msg_payload->type) {
|
||||
case KEYBOARD_KEY_Q:
|
||||
inout_kbd->q = msg_payload->value;
|
||||
break;
|
||||
case KEYBOARD_KEY_W:
|
||||
inout_kbd->w = msg_payload->value;
|
||||
break;
|
||||
case KEYBOARD_KEY_E:
|
||||
inout_kbd->e = msg_payload->value;
|
||||
break;
|
||||
case KEYBOARD_KEY_R:
|
||||
inout_kbd->r = msg_payload->value;
|
||||
break;
|
||||
case KEYBOARD_KEY_T:
|
||||
inout_kbd->t = msg_payload->value;
|
||||
break;
|
||||
case KEYBOARD_KEY_Y:
|
||||
inout_kbd->y = msg_payload->value;
|
||||
break;
|
||||
case KEYBOARD_KEY_U:
|
||||
inout_kbd->u = msg_payload->value;
|
||||
break;
|
||||
case KEYBOARD_KEY_I:
|
||||
inout_kbd->i = msg_payload->value;
|
||||
break;
|
||||
case KEYBOARD_KEY_O:
|
||||
inout_kbd->o = msg_payload->value;
|
||||
break;
|
||||
case KEYBOARD_KEY_P:
|
||||
inout_kbd->p = msg_payload->value;
|
||||
break;
|
||||
case KEYBOARD_KEY_A:
|
||||
inout_kbd->a = msg_payload->value;
|
||||
break;
|
||||
case KEYBOARD_KEY_S:
|
||||
inout_kbd->s = msg_payload->value;
|
||||
break;
|
||||
case KEYBOARD_KEY_D:
|
||||
inout_kbd->d = msg_payload->value;
|
||||
break;
|
||||
case KEYBOARD_KEY_F:
|
||||
inout_kbd->f = msg_payload->value;
|
||||
break;
|
||||
case KEYBOARD_KEY_G:
|
||||
inout_kbd->g = msg_payload->value;
|
||||
break;
|
||||
case KEYBOARD_KEY_H:
|
||||
inout_kbd->h = msg_payload->value;
|
||||
break;
|
||||
case KEYBOARD_KEY_J:
|
||||
inout_kbd->j = msg_payload->value;
|
||||
break;
|
||||
case KEYBOARD_KEY_K:
|
||||
inout_kbd->k = msg_payload->value;
|
||||
break;
|
||||
case KEYBOARD_KEY_L:
|
||||
inout_kbd->l = msg_payload->value;
|
||||
break;
|
||||
case KEYBOARD_KEY_Z:
|
||||
inout_kbd->z = msg_payload->value;
|
||||
break;
|
||||
case KEYBOARD_KEY_X:
|
||||
inout_kbd->x = msg_payload->value;
|
||||
break;
|
||||
case KEYBOARD_KEY_C:
|
||||
inout_kbd->c = msg_payload->value;
|
||||
break;
|
||||
case KEYBOARD_KEY_V:
|
||||
inout_kbd->v = msg_payload->value;
|
||||
break;
|
||||
case KEYBOARD_KEY_B:
|
||||
inout_kbd->b = msg_payload->value;
|
||||
break;
|
||||
case KEYBOARD_KEY_N:
|
||||
inout_kbd->n = msg_payload->value;
|
||||
break;
|
||||
case KEYBOARD_KEY_M:
|
||||
inout_kbd->m = msg_payload->value;
|
||||
break;
|
||||
case KEYBOARD_KEY_UP:
|
||||
inout_kbd->up = msg_payload->value;
|
||||
break;
|
||||
case KEYBOARD_KEY_DOWN:
|
||||
inout_kbd->down = msg_payload->value;
|
||||
break;
|
||||
case KEYBOARD_KEY_LEFT:
|
||||
inout_kbd->left = msg_payload->value;
|
||||
break;
|
||||
case KEYBOARD_KEY_RIGHT:
|
||||
inout_kbd->right = msg_payload->value;
|
||||
break;
|
||||
case KEYBOARD_KEY_NUM_0:
|
||||
inout_kbd->num_0 = msg_payload->value;
|
||||
break;
|
||||
case KEYBOARD_KEY_NUM_1:
|
||||
inout_kbd->num_1 = msg_payload->value;
|
||||
break;
|
||||
case KEYBOARD_KEY_NUM_2:
|
||||
inout_kbd->num_2 = msg_payload->value;
|
||||
break;
|
||||
case KEYBOARD_KEY_NUM_3:
|
||||
inout_kbd->num_3 = msg_payload->value;
|
||||
break;
|
||||
case KEYBOARD_KEY_NUM_4:
|
||||
inout_kbd->num_4 = msg_payload->value;
|
||||
break;
|
||||
case KEYBOARD_KEY_NUM_5:
|
||||
inout_kbd->num_5 = msg_payload->value;
|
||||
break;
|
||||
case KEYBOARD_KEY_NUM_6:
|
||||
inout_kbd->num_6 = msg_payload->value;
|
||||
break;
|
||||
case KEYBOARD_KEY_NUM_7:
|
||||
inout_kbd->num_7 = msg_payload->value;
|
||||
break;
|
||||
case KEYBOARD_KEY_NUM_8:
|
||||
inout_kbd->num_8 = msg_payload->value;
|
||||
break;
|
||||
case KEYBOARD_KEY_NUM_9:
|
||||
inout_kbd->num_9 = msg_payload->value;
|
||||
break;
|
||||
case KEYBOARD_KEY_LCRTL:
|
||||
inout_kbd->lctrl = msg_payload->value;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "key not implemented\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_incoming_message(
|
||||
const dev_out_settings_t *const in_settings,
|
||||
const in_message_t *const msg,
|
||||
devices_status_t *const dev_stats
|
||||
) {
|
||||
if (msg->type == GAMEPAD_SET_ELEMENT) {
|
||||
handle_incoming_message_gamepad_set(&msg->data.gamepad_set, &dev_stats->gamepad);
|
||||
handle_incoming_message_gamepad_set(
|
||||
in_settings,
|
||||
&msg->data.gamepad_set,
|
||||
&dev_stats->gamepad
|
||||
);
|
||||
} else if (msg->type == GAMEPAD_ACTION) {
|
||||
handle_incoming_message_gamepad_action(&msg->data.action, &dev_stats->gamepad);
|
||||
handle_incoming_message_gamepad_action(
|
||||
in_settings,
|
||||
&msg->data.action,
|
||||
&dev_stats->gamepad
|
||||
);
|
||||
} else if (msg->type == MOUSE_EVENT) {
|
||||
handle_incoming_message_mouse_event(
|
||||
in_settings,
|
||||
&msg->data.mouse_event,
|
||||
&dev_stats->mouse
|
||||
);
|
||||
} else if (msg->type == KEYBOARD_SET_ELEMENT) {
|
||||
handle_incoming_message_keyboard_set(
|
||||
in_settings,
|
||||
&msg->data.kbd_set,
|
||||
&dev_stats->kbd
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
int64_t get_timediff_usec(const struct timeval *const past, const struct timeval *const now) {
|
||||
struct timeval tdiff;
|
||||
timersub(now, past, &tdiff);
|
||||
|
||||
//const int64_t sgn = ((now->tv_sec > past->tv_sec) || ((now->tv_sec == past->tv_sec) && (now->tv_usec > past->tv_usec))) ? -1 : +1;
|
||||
|
||||
return (int64_t)(tdiff.tv_sec) * (int64_t)1000000 + (int64_t)(tdiff.tv_usec);
|
||||
int64_t get_timediff_nsec(const struct timespec *const start, const struct timespec *const end) {
|
||||
return (end->tv_sec - start->tv_sec) * 1000000000LL + (end->tv_nsec - start->tv_nsec);
|
||||
}
|
||||
|
||||
void *dev_out_thread_func(void *ptr) {
|
||||
|
|
@ -167,41 +393,96 @@ void *dev_out_thread_func(void *ptr) {
|
|||
// Initialize device
|
||||
devices_status_init(&dev_out_data->dev_stats);
|
||||
|
||||
dev_out_gamepad_device_t current_gamepad = dev_out_data->gamepad;
|
||||
dev_out_gamepad_device_t current_gamepad = GAMEPAD_DUALSENSE;
|
||||
|
||||
switch (dev_out_data->settings.default_gamepad) {
|
||||
case 1:
|
||||
current_gamepad = GAMEPAD_DUALSENSE;
|
||||
break;
|
||||
case 2:
|
||||
current_gamepad = GAMEPAD_DUALSHOCK;
|
||||
break;
|
||||
|
||||
default:
|
||||
current_gamepad = GAMEPAD_DUALSENSE;
|
||||
break;
|
||||
}
|
||||
|
||||
int current_gamepad_fd = -1;
|
||||
int current_keyboard_fd = -1;
|
||||
int current_mouse_fd = -1;
|
||||
|
||||
union {
|
||||
virt_dualshock_t ds4;
|
||||
virt_dualsense_t ds5;
|
||||
} controller_data;
|
||||
|
||||
int current_gamepad_fd = -1;
|
||||
//int current_keyboard_fd = -1;
|
||||
//int current_mouse_fd = -1;
|
||||
virt_mouse_t mouse_data;
|
||||
const int mouse_init_res = virt_mouse_init(&mouse_data);
|
||||
if (mouse_init_res < 0) {
|
||||
fprintf(stderr, "Unable to initialize virtual mouse -- will continue regardless\n");
|
||||
} else {
|
||||
current_mouse_fd = virt_mouse_get_fd(&mouse_data);
|
||||
printf("Mouse initialized: fd=%d\n", current_mouse_fd);
|
||||
}
|
||||
|
||||
virt_kbd_t keyboard_data;
|
||||
const int kbd_init_res = virt_kbd_init(&keyboard_data);
|
||||
if (kbd_init_res < 0) {
|
||||
fprintf(stderr, "Unable to initialize virtual keyboard -- will continue regardless\n");
|
||||
} else {
|
||||
current_keyboard_fd = virt_kbd_get_fd(&keyboard_data);
|
||||
printf("Keyboard initialized: fd=%d\n", current_keyboard_fd);
|
||||
}
|
||||
|
||||
bool high_hz_avail = false;
|
||||
const char *const avail_freq = inline_read_file("/sys/bus/iio/devices/iio:device0/", "name");
|
||||
if ((avail_freq != NULL) && (strstr(avail_freq, "1600.0") != NULL)) {
|
||||
printf("High iio sampling frequency available: 1600.0 Hz");
|
||||
high_hz_avail = true;
|
||||
}
|
||||
|
||||
const int64_t kbd_report_timing_us = high_hz_avail ? 1125 : 2025;
|
||||
const int64_t mouse_report_timing_us = high_hz_avail ? 950 : 1650;
|
||||
const int64_t gamepad_report_timing_us = high_hz_avail ? 1250 : 2500;
|
||||
|
||||
if (current_gamepad == GAMEPAD_DUALSENSE) {
|
||||
const int ds5_init_res = virt_dualsense_init(&controller_data.ds5);
|
||||
const int ds5_init_res = virt_dualsense_init(
|
||||
&controller_data.ds5,
|
||||
dev_out_data->settings.controller_bluetooth,
|
||||
dev_out_data->settings.dualsense_edge,
|
||||
dev_out_data->settings.gyro_to_analog_activation_treshold,
|
||||
dev_out_data->settings.gyro_to_analog_mapping
|
||||
);
|
||||
|
||||
if (ds5_init_res != 0) {
|
||||
fprintf(stderr, "Unable to initialize the DualSense device: %d\n", ds5_init_res);
|
||||
} else {
|
||||
current_gamepad_fd = virt_dualsense_get_fd(&controller_data.ds5);
|
||||
printf("DualSense initialized: fd=%d\n", current_gamepad_fd);
|
||||
printf("DualSense initialized: fd=%d, bluetooth=%s\n", current_gamepad_fd, dev_out_data->settings.controller_bluetooth ? "true" : "false");
|
||||
}
|
||||
} else if (current_gamepad == GAMEPAD_DUALSHOCK) {
|
||||
const int ds4_init_res = virt_dualshock_init(&controller_data.ds4);
|
||||
const int ds4_init_res = virt_dualshock_init(
|
||||
&controller_data.ds4,
|
||||
dev_out_data->settings.controller_bluetooth,
|
||||
dev_out_data->settings.gyro_to_analog_activation_treshold,
|
||||
dev_out_data->settings.gyro_to_analog_mapping
|
||||
);
|
||||
|
||||
if (ds4_init_res != 0) {
|
||||
fprintf(stderr, "Unable to initialize the DualShock device: %d\n", ds4_init_res);
|
||||
} else {
|
||||
current_gamepad_fd = virt_dualshock_get_fd(&controller_data.ds4);
|
||||
printf("DualShock initialized: fd=%d\n", current_gamepad_fd);
|
||||
printf("DualShock initialized: fd=%d, bluetooth=%s\n", current_gamepad_fd, dev_out_data->settings.controller_bluetooth ? "true" : "false");
|
||||
}
|
||||
}
|
||||
|
||||
struct timeval now = {0};
|
||||
gettimeofday(&now, NULL);
|
||||
struct timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
|
||||
struct timeval gamepad_last_hid_report_sent = now;
|
||||
//struct timeval mouse_last_hid_report_sent = now;
|
||||
//struct timeval keyboard_last_hid_report_sent = now;
|
||||
struct timespec gamepad_last_hid_report_sent = now;
|
||||
struct timespec mouse_last_hid_report_sent = now;
|
||||
struct timespec keyboard_last_hid_report_sent = now;
|
||||
|
||||
uint8_t tmp_buf[256];
|
||||
|
||||
|
|
@ -212,9 +493,13 @@ void *dev_out_thread_func(void *ptr) {
|
|||
break;
|
||||
}
|
||||
|
||||
gettimeofday(&now, NULL);
|
||||
int64_t gamepad_time_diff_usecs = get_timediff_usec(&gamepad_last_hid_report_sent, &now);
|
||||
if (gamepad_time_diff_usecs >= 1250) {
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
|
||||
const int64_t gamepad_time_diff_usecs = get_timediff_nsec(&gamepad_last_hid_report_sent, &now) / 1000;
|
||||
const int64_t mouse_time_diff_usecs = get_timediff_nsec(&mouse_last_hid_report_sent, &now) / 1000;
|
||||
const int64_t kbd_time_diff_usecs = get_timediff_nsec(&keyboard_last_hid_report_sent, &now) / 1000;
|
||||
|
||||
if ((current_gamepad_fd > 0) && (gamepad_time_diff_usecs >= gamepad_report_timing_us)) {
|
||||
gamepad_last_hid_report_sent = now;
|
||||
|
||||
if (current_gamepad == GAMEPAD_DUALSENSE) {
|
||||
|
|
@ -224,159 +509,234 @@ void *dev_out_thread_func(void *ptr) {
|
|||
virt_dualshock_compose(&controller_data.ds4, &dev_out_data->dev_stats.gamepad, tmp_buf);
|
||||
virt_dualshock_send(&controller_data.ds4, tmp_buf);
|
||||
}
|
||||
} else {
|
||||
FD_ZERO(&read_fds);
|
||||
}
|
||||
|
||||
if ((current_mouse_fd > 0) && (mouse_time_diff_usecs >= mouse_report_timing_us)) {
|
||||
mouse_last_hid_report_sent = now;
|
||||
|
||||
virt_mouse_send(&mouse_data, &dev_out_data->dev_stats.mouse, NULL);
|
||||
|
||||
// reset mouse movements now
|
||||
dev_out_data->dev_stats.mouse.x = 0;
|
||||
dev_out_data->dev_stats.mouse.y = 0;
|
||||
}
|
||||
|
||||
if ((current_keyboard_fd > 0) && (kbd_time_diff_usecs >= kbd_report_timing_us)) {
|
||||
keyboard_last_hid_report_sent = now;
|
||||
|
||||
virt_kbd_send(&keyboard_data, &dev_out_data->dev_stats.kbd, NULL);
|
||||
}
|
||||
|
||||
|
||||
// once here no output device needs to send out its report
|
||||
FD_ZERO(&read_fds);
|
||||
|
||||
if (dev_out_data->communication.type == ipc_unix_pipe) {
|
||||
FD_SET(dev_out_data->communication.endpoint.pipe.in_message_pipe_fd, &read_fds);
|
||||
} else if (dev_out_data->communication.type == ipc_server_sockets) {
|
||||
if (pthread_mutex_lock(&dev_out_data->communication.endpoint.ssocket.mutex) == 0) {
|
||||
for (int i = 0; i < MAX_CONNECTED_CLIENTS; ++i) {
|
||||
const int fd = dev_out_data->communication.endpoint.ssocket.clients[i];
|
||||
if (fd > 0) {
|
||||
FD_SET(fd, &read_fds);
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&dev_out_data->communication.endpoint.ssocket.mutex);
|
||||
}
|
||||
}
|
||||
|
||||
if (current_mouse_fd > 0) {
|
||||
FD_SET(current_mouse_fd, &read_fds);
|
||||
}
|
||||
|
||||
if (current_keyboard_fd > 0) {
|
||||
FD_SET(current_keyboard_fd, &read_fds);
|
||||
}
|
||||
|
||||
if (current_gamepad_fd > 0) {
|
||||
FD_SET(current_gamepad_fd, &read_fds);
|
||||
}
|
||||
|
||||
const int64_t timeout_gamepad_time_diff_usecs = (current_gamepad_fd > 0) ? gamepad_report_timing_us - gamepad_time_diff_usecs : 5000;
|
||||
const int64_t timeout_mouse_time_diff_usecs = (current_mouse_fd > 0) ? mouse_report_timing_us - mouse_time_diff_usecs : 5000;
|
||||
const int64_t timeout_kbd_time_diff_usecs = (current_keyboard_fd > 0) ? kbd_report_timing_us - kbd_time_diff_usecs : 5000;
|
||||
|
||||
int64_t next_timing_out_device_diff_usecs = 5000;
|
||||
|
||||
if ((timeout_kbd_time_diff_usecs > 0) && (timeout_kbd_time_diff_usecs < next_timing_out_device_diff_usecs)) {
|
||||
next_timing_out_device_diff_usecs = timeout_kbd_time_diff_usecs;
|
||||
}
|
||||
|
||||
if ((timeout_mouse_time_diff_usecs > 0) && (timeout_mouse_time_diff_usecs < next_timing_out_device_diff_usecs)) {
|
||||
next_timing_out_device_diff_usecs = timeout_mouse_time_diff_usecs;
|
||||
}
|
||||
|
||||
if ((timeout_gamepad_time_diff_usecs > 0) && (timeout_gamepad_time_diff_usecs < next_timing_out_device_diff_usecs)) {
|
||||
next_timing_out_device_diff_usecs = timeout_gamepad_time_diff_usecs;
|
||||
}
|
||||
|
||||
// calculate the shortest timeout between one of the multiple device will needs to send out its hid report
|
||||
struct timeval timeout = {
|
||||
.tv_sec = (__time_t)next_timing_out_device_diff_usecs / (__time_t)1000000,
|
||||
.tv_usec = (__suseconds_t)next_timing_out_device_diff_usecs % (__suseconds_t)1000000,
|
||||
};
|
||||
|
||||
int ready_fds = select(FD_SETSIZE, &read_fds, NULL, NULL, &timeout);
|
||||
gamepad_status_qam_quirk_ext_time(&dev_out_data->dev_stats.gamepad);
|
||||
|
||||
if (ready_fds == -1) {
|
||||
const int err = errno;
|
||||
fprintf(stderr, "Error reading events for output devices: %d\n", err);
|
||||
usleep(1000);
|
||||
continue;
|
||||
} else if (ready_fds == 0) {
|
||||
// timeout: do nothing but continue. next iteration will take care
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((current_gamepad_fd > 0) && (FD_ISSET(current_gamepad_fd, &read_fds))) {
|
||||
const uint64_t prev_leds_events_count = dev_out_data->dev_stats.gamepad.leds_events_count;
|
||||
const uint64_t prev_motors_events_count = dev_out_data->dev_stats.gamepad.rumble_events_count;
|
||||
|
||||
out_message_t out_msgs[4];
|
||||
size_t out_msgs_count = 0;
|
||||
if (current_gamepad == GAMEPAD_DUALSENSE) {
|
||||
virt_dualsense_event(&controller_data.ds5, &dev_out_data->dev_stats.gamepad);
|
||||
} else if (current_gamepad == GAMEPAD_DUALSHOCK) {
|
||||
virt_dualshock_event(&controller_data.ds4, &dev_out_data->dev_stats.gamepad);
|
||||
}
|
||||
|
||||
const uint64_t current_leds_events_count = dev_out_data->dev_stats.gamepad.leds_events_count;
|
||||
const uint64_t current_motors_events_count = dev_out_data->dev_stats.gamepad.rumble_events_count;
|
||||
|
||||
if (current_leds_events_count != prev_leds_events_count) {
|
||||
const out_message_t msg = {
|
||||
.type = OUT_MSG_TYPE_LEDS,
|
||||
.data = {
|
||||
.leds = {
|
||||
.r = dev_out_data->dev_stats.gamepad.leds_colors[0],
|
||||
.g = dev_out_data->dev_stats.gamepad.leds_colors[1],
|
||||
.b = dev_out_data->dev_stats.gamepad.leds_colors[2],
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (dev_out_data->settings.gamepad_leds_control) {
|
||||
out_msgs[out_msgs_count++] = msg;
|
||||
}
|
||||
}
|
||||
|
||||
if (current_motors_events_count != prev_motors_events_count) {
|
||||
const out_message_t msg = {
|
||||
.type = OUT_MSG_TYPE_RUMBLE,
|
||||
.data = {
|
||||
.rumble = {
|
||||
.motors_left = dev_out_data->dev_stats.gamepad.motors_intensity[0],
|
||||
.motors_right = dev_out_data->dev_stats.gamepad.motors_intensity[1],
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (dev_out_data->settings.gamepad_rumble_control) {
|
||||
out_msgs[out_msgs_count++] = msg;
|
||||
}
|
||||
}
|
||||
|
||||
// send out game-generated events to sockets
|
||||
if (dev_out_data->communication.type == ipc_unix_pipe) {
|
||||
FD_SET(dev_out_data->communication.endpoint.pipe.in_message_pipe_fd, &read_fds);
|
||||
for (int msg_idx = 0; msg_idx < out_msgs_count; ++msg_idx) {
|
||||
const int write_res = write(dev_out_data->communication.endpoint.pipe.out_message_pipe_fd, (void*)&out_msgs[msg_idx], sizeof(out_message_t));
|
||||
if (write_res != sizeof(out_message_t)) {
|
||||
fprintf(stderr, "Error in writing out_message to out_message_pipe: %d\n", write_res);
|
||||
}
|
||||
}
|
||||
} else if (dev_out_data->communication.type == ipc_server_sockets) {
|
||||
if (pthread_mutex_lock(&dev_out_data->communication.endpoint.ssocket.mutex) == 0) {
|
||||
for (int i = 0; i < MAX_CONNECTED_CLIENTS; ++i) {
|
||||
const int fd = dev_out_data->communication.endpoint.ssocket.clients[i];
|
||||
if (fd > 0) {
|
||||
FD_SET(fd, &read_fds);
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&dev_out_data->communication.endpoint.ssocket.mutex);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: FD_SET(current_mouse_fd, &read_fds);
|
||||
// TODO: FD_SET(current_keyboard_fd, &read_fds);
|
||||
FD_SET(current_gamepad_fd, &read_fds);
|
||||
|
||||
// calculate the shortest timeout between one of the multiple device will needs to send out its hid report
|
||||
struct timeval timeout = {
|
||||
.tv_sec = (__time_t)gamepad_time_diff_usecs / (__time_t)1000000,
|
||||
.tv_usec = (__suseconds_t)gamepad_time_diff_usecs % (__suseconds_t)1000000,
|
||||
};
|
||||
|
||||
int ready_fds = select(FD_SETSIZE, &read_fds, NULL, NULL, &timeout);
|
||||
gamepad_status_qam_quirk_ext_time(&dev_out_data->dev_stats.gamepad, &now);
|
||||
|
||||
if (ready_fds == -1) {
|
||||
const int err = errno;
|
||||
fprintf(stderr, "Error reading events for output devices: %d\n", err);
|
||||
continue;
|
||||
} else if (ready_fds == 0) {
|
||||
// timeout: do nothing but continue. next iteration will take care
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (FD_ISSET(current_gamepad_fd, &read_fds)) {
|
||||
const uint64_t prev_leds_events_count = dev_out_data->dev_stats.gamepad.leds_events_count;
|
||||
const uint64_t prev_motors_events_count = dev_out_data->dev_stats.gamepad.rumble_events_count;
|
||||
|
||||
out_message_t out_msgs[4];
|
||||
size_t out_msgs_count = 0;
|
||||
if (current_gamepad == GAMEPAD_DUALSENSE) {
|
||||
virt_dualsense_event(&controller_data.ds5, &dev_out_data->dev_stats.gamepad);
|
||||
} else if (current_gamepad == GAMEPAD_DUALSHOCK) {
|
||||
virt_dualshock_event(&controller_data.ds4, &dev_out_data->dev_stats.gamepad);
|
||||
}
|
||||
|
||||
const uint64_t current_leds_events_count = dev_out_data->dev_stats.gamepad.leds_events_count;
|
||||
const uint64_t current_motors_events_count = dev_out_data->dev_stats.gamepad.rumble_events_count;
|
||||
|
||||
if (current_leds_events_count != prev_leds_events_count) {
|
||||
const out_message_t msg = {
|
||||
.type = OUT_MSG_TYPE_LEDS,
|
||||
.data = {
|
||||
.leds = {
|
||||
.r = dev_out_data->dev_stats.gamepad.leds_colors[0],
|
||||
.g = dev_out_data->dev_stats.gamepad.leds_colors[1],
|
||||
.b = dev_out_data->dev_stats.gamepad.leds_colors[2],
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
out_msgs[out_msgs_count++] = msg;
|
||||
}
|
||||
|
||||
if (current_motors_events_count != prev_motors_events_count) {
|
||||
const out_message_t msg = {
|
||||
.type = OUT_MSG_TYPE_RUMBLE,
|
||||
.data = {
|
||||
.rumble = {
|
||||
.motors_left = dev_out_data->dev_stats.gamepad.motors_intensity[0],
|
||||
.motors_right = dev_out_data->dev_stats.gamepad.motors_intensity[1],
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
out_msgs[out_msgs_count++] = msg;
|
||||
}
|
||||
|
||||
// send out game-generated events to sockets
|
||||
int fd = -1;
|
||||
const size_t bytes_to_send = sizeof(out_message_t) * out_msgs_count;
|
||||
|
||||
if (dev_out_data->communication.type == ipc_unix_pipe) {
|
||||
const int write_res = write(dev_out_data->communication.endpoint.pipe.out_message_pipe_fd, (void*)&out_msgs, bytes_to_send);
|
||||
if (write_res != bytes_to_send) {
|
||||
fprintf(stderr, "Error in writing out_message to out_message_pipe: %d\n", write_res);
|
||||
}
|
||||
} else if (dev_out_data->communication.type == ipc_server_sockets) {
|
||||
if (pthread_mutex_lock(&dev_out_data->communication.endpoint.ssocket.mutex) == 0) {
|
||||
for (int i = 0; i < MAX_CONNECTED_CLIENTS; ++i) {
|
||||
if (dev_out_data->communication.endpoint.ssocket.clients[i] > 0) {
|
||||
const int write_res = write(dev_out_data->communication.endpoint.ssocket.clients[i], (void*)&out_msgs, bytes_to_send);
|
||||
if (write_res != bytes_to_send) {
|
||||
if (dev_out_data->communication.endpoint.ssocket.clients[i] > 0) {
|
||||
for (int msg_idx = 0; msg_idx < out_msgs_count; ++msg_idx) {
|
||||
const int write_res = write(dev_out_data->communication.endpoint.ssocket.clients[i], (void*)&out_msgs[msg_idx], sizeof(out_message_t));
|
||||
if (write_res != sizeof(out_message_t)) {
|
||||
fprintf(stderr, "Error in writing out_message to socket number %d: %d\n", i, write_res);
|
||||
close(dev_out_data->communication.endpoint.ssocket.clients[i]);
|
||||
dev_out_data->communication.endpoint.ssocket.clients[i] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&dev_out_data->communication.endpoint.ssocket.mutex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// read and handle incoming data: this data is packed into in_message_t
|
||||
if (dev_out_data->communication.type == ipc_unix_pipe) {
|
||||
if (FD_ISSET(dev_out_data->communication.endpoint.pipe.in_message_pipe_fd, &read_fds)) {
|
||||
in_message_t incoming_message;
|
||||
const size_t in_message_pipe_read_res = read(dev_out_data->communication.endpoint.pipe.in_message_pipe_fd, (void*)&incoming_message, sizeof(in_message_t));
|
||||
if (in_message_pipe_read_res == sizeof(in_message_t)) {
|
||||
handle_incoming_message(&incoming_message, &dev_out_data->dev_stats);
|
||||
} else {
|
||||
fprintf(stderr, "Error reading from in_message_pipe_fd: got %zu bytes, expected %zu butes\n", in_message_pipe_read_res, sizeof(in_message_t));
|
||||
}
|
||||
}
|
||||
} else if (dev_out_data->communication.type == ipc_server_sockets) {
|
||||
if (pthread_mutex_lock(&dev_out_data->communication.endpoint.ssocket.mutex) == 0) {
|
||||
for (int i = 0; i < MAX_CONNECTED_CLIENTS; ++i) {
|
||||
const int fd = dev_out_data->communication.endpoint.ssocket.clients[i];
|
||||
if ((fd > 0) && (FD_ISSET(fd, &read_fds))) {
|
||||
in_message_t incoming_message;
|
||||
const size_t in_message_pipe_read_res = read(fd, (void*)&incoming_message, sizeof(in_message_t));
|
||||
if (in_message_pipe_read_res == sizeof(in_message_t)) {
|
||||
handle_incoming_message(&incoming_message, &dev_out_data->dev_stats);
|
||||
} else {
|
||||
fprintf(stderr, "Error reading from socket number %d: got %zu bytes, expected %zu butes\n", i, in_message_pipe_read_res, sizeof(in_message_t));
|
||||
close(dev_out_data->communication.endpoint.ssocket.clients[i]);
|
||||
dev_out_data->communication.endpoint.ssocket.clients[i] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&dev_out_data->communication.endpoint.ssocket.mutex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((current_keyboard_fd > 0) && (FD_ISSET(current_keyboard_fd, &read_fds))) {
|
||||
// TODO: read keyboard events
|
||||
}
|
||||
|
||||
if ((current_mouse_fd > 0) && (FD_ISSET(current_mouse_fd, &read_fds))) {
|
||||
// TODO: read mouse events
|
||||
}
|
||||
|
||||
// read and handle incoming data: this data is packed into in_message_t
|
||||
if (dev_out_data->communication.type == ipc_unix_pipe) {
|
||||
if (FD_ISSET(dev_out_data->communication.endpoint.pipe.in_message_pipe_fd, &read_fds)) {
|
||||
in_message_t incoming_message;
|
||||
const size_t in_message_pipe_read_res = read(dev_out_data->communication.endpoint.pipe.in_message_pipe_fd, (void*)&incoming_message, sizeof(in_message_t));
|
||||
if (in_message_pipe_read_res == sizeof(in_message_t)) {
|
||||
handle_incoming_message(
|
||||
&dev_out_data->settings,
|
||||
&incoming_message,
|
||||
&dev_out_data->dev_stats
|
||||
);
|
||||
} else {
|
||||
fprintf(stderr, "Error reading from in_message_pipe_fd: got %zu bytes, expected %zu bytes\n", in_message_pipe_read_res, sizeof(in_message_t));
|
||||
}
|
||||
}
|
||||
} else if (dev_out_data->communication.type == ipc_server_sockets) {
|
||||
if (pthread_mutex_lock(&dev_out_data->communication.endpoint.ssocket.mutex) == 0) {
|
||||
for (int i = 0; i < MAX_CONNECTED_CLIENTS; ++i) {
|
||||
const int fd = dev_out_data->communication.endpoint.ssocket.clients[i];
|
||||
if ((fd > 0) && (FD_ISSET(fd, &read_fds))) {
|
||||
in_message_t incoming_message;
|
||||
const size_t in_message_pipe_read_res = read(fd, (void*)&incoming_message, sizeof(in_message_t));
|
||||
if (in_message_pipe_read_res == sizeof(in_message_t)) {
|
||||
handle_incoming_message(
|
||||
&dev_out_data->settings,
|
||||
&incoming_message,
|
||||
&dev_out_data->dev_stats
|
||||
);
|
||||
} else {
|
||||
fprintf(stderr, "Error reading from socket number %d: got %zu bytes, expected %zu bytes\n", i, in_message_pipe_read_res, sizeof(in_message_t));
|
||||
close(dev_out_data->communication.endpoint.ssocket.clients[i]);
|
||||
dev_out_data->communication.endpoint.ssocket.clients[i] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&dev_out_data->communication.endpoint.ssocket.mutex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// close the output device
|
||||
if (current_gamepad == GAMEPAD_DUALSENSE) {
|
||||
virt_dualsense_close(&controller_data.ds5);
|
||||
} else if (current_gamepad == GAMEPAD_DUALSHOCK) {
|
||||
virt_dualshock_close(&controller_data.ds4);
|
||||
// close the gamepad output device
|
||||
if (current_gamepad_fd > 0) {
|
||||
if (current_gamepad == GAMEPAD_DUALSENSE) {
|
||||
virt_dualsense_close(&controller_data.ds5);
|
||||
} else if (current_gamepad == GAMEPAD_DUALSHOCK) {
|
||||
virt_dualshock_close(&controller_data.ds4);
|
||||
}
|
||||
}
|
||||
|
||||
// close the mouse device
|
||||
if (current_mouse_fd > 0) {
|
||||
virt_mouse_close(&mouse_data);
|
||||
}
|
||||
|
||||
// close the keyboard device
|
||||
if (current_keyboard_fd > 0) {
|
||||
virt_kbd_close(&keyboard_data);
|
||||
}
|
||||
|
||||
// end communication
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include "ipc.h"
|
||||
#include "message.h"
|
||||
#include "devices_status.h"
|
||||
#include "settings.h"
|
||||
|
||||
#define DEV_OUT_FLAG_EXIT 0x00000001U
|
||||
|
||||
|
|
@ -16,10 +17,10 @@ typedef struct dev_out_data {
|
|||
|
||||
ipc_t communication;
|
||||
|
||||
dev_out_gamepad_device_t gamepad;
|
||||
|
||||
devices_status_t dev_stats;
|
||||
|
||||
dev_out_settings_t settings;
|
||||
|
||||
volatile uint32_t flags;
|
||||
|
||||
} dev_out_data_t;
|
||||
|
|
|
|||
67
dev_timer.c
Normal file
67
dev_timer.c
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
#include "dev_timer.h"
|
||||
|
||||
int dev_timer_open(
|
||||
const timer_filters_t *const in_filters,
|
||||
dev_timer_t **const out_dev
|
||||
) {
|
||||
int res = -ENODEV;
|
||||
|
||||
*out_dev = malloc(sizeof(dev_timer_t));
|
||||
if (*out_dev == NULL) {
|
||||
res = -ENOMEM;
|
||||
goto dev_timer_open_err;
|
||||
}
|
||||
|
||||
memset(*out_dev, 0, sizeof(dev_timer_t));
|
||||
|
||||
const int fd = timerfd_create(CLOCK_MONOTONIC, 0);
|
||||
if (fd < 0) {
|
||||
res = errno < 0 ? errno : -1 * errno;
|
||||
if (res == 0) {
|
||||
res = fd;
|
||||
}
|
||||
goto dev_timer_open_err;
|
||||
}
|
||||
|
||||
(*out_dev)->fd = fd;
|
||||
if (in_filters->ticktime_ms != 0) {
|
||||
(*out_dev)->timer_spec.it_value.tv_sec = in_filters->ticktime_ms / (__time_t)1000;
|
||||
(*out_dev)->timer_spec.it_value.tv_nsec = (in_filters->ticktime_ms % (__syscall_slong_t)1000) * (__syscall_slong_t)1000000;
|
||||
(*out_dev)->timer_spec.it_interval.tv_sec = in_filters->ticktime_ms / (__time_t)1000;
|
||||
(*out_dev)->timer_spec.it_interval.tv_nsec = (in_filters->ticktime_ms % (__syscall_slong_t)1000) * (__syscall_slong_t)1000000;
|
||||
} else {
|
||||
(*out_dev)->timer_spec.it_value.tv_sec = 0;
|
||||
(*out_dev)->timer_spec.it_value.tv_nsec = in_filters->ticktime_ns;
|
||||
(*out_dev)->timer_spec.it_interval.tv_sec = 0;
|
||||
(*out_dev)->timer_spec.it_interval.tv_nsec = in_filters->ticktime_ns;
|
||||
}
|
||||
|
||||
if (timerfd_settime((*out_dev)->fd, 0, &(*out_dev)->timer_spec, NULL) < 0) {
|
||||
res = errno < 0 ? errno : -1 * errno;
|
||||
if (res == 0) {
|
||||
res = -EIO;
|
||||
}
|
||||
goto dev_timer_open_err;
|
||||
}
|
||||
|
||||
res = 0;
|
||||
|
||||
dev_timer_open_err:
|
||||
if (res != 0) {
|
||||
if (fd > 0) {
|
||||
close(fd);
|
||||
}
|
||||
|
||||
free(*out_dev);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void dev_timer_close(dev_timer_t *const inout_dev) {
|
||||
close(inout_dev->fd);
|
||||
}
|
||||
|
||||
int dev_timer_get_fd(const dev_timer_t *const in_dev) {
|
||||
return in_dev->fd;
|
||||
}
|
||||
18
dev_timer.h
Normal file
18
dev_timer.h
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
#pragma once
|
||||
|
||||
#include "input_dev.h"
|
||||
|
||||
typedef struct dev_timer {
|
||||
struct itimerspec timer_spec;
|
||||
|
||||
int fd;
|
||||
} dev_timer_t;
|
||||
|
||||
int dev_timer_open(
|
||||
const timer_filters_t *const in_filters,
|
||||
dev_timer_t **const out_dev
|
||||
);
|
||||
|
||||
void dev_timer_close(dev_timer_t *const inout_dev);
|
||||
|
||||
int dev_timer_get_fd(const dev_timer_t *const in_dev);
|
||||
|
|
@ -1,7 +1,63 @@
|
|||
#include "devices_status.h"
|
||||
#include <pthread.h>
|
||||
|
||||
void kbd_status_init(keyboard_status_t *const stats) {
|
||||
stats->connected = true;
|
||||
|
||||
stats->q = 0;
|
||||
stats->w = 0;
|
||||
stats->e = 0;
|
||||
stats->r = 0;
|
||||
stats->t = 0;
|
||||
stats->y = 0;
|
||||
stats->u = 0;
|
||||
stats->i = 0;
|
||||
stats->o = 0;
|
||||
stats->p = 0;
|
||||
stats->a = 0;
|
||||
stats->s = 0;
|
||||
stats->d = 0;
|
||||
stats->f = 0;
|
||||
stats->g = 0;
|
||||
stats->h = 0;
|
||||
stats->j = 0;
|
||||
stats->k = 0;
|
||||
stats->l = 0;
|
||||
stats->z = 0;
|
||||
stats->x = 0;
|
||||
stats->c = 0;
|
||||
stats->v = 0;
|
||||
stats->b = 0;
|
||||
stats->n = 0;
|
||||
stats->m = 0;
|
||||
|
||||
stats->num_1 = 0;
|
||||
stats->num_2 = 0;
|
||||
stats->num_3 = 0;
|
||||
stats->num_4 = 0;
|
||||
stats->num_5 = 0;
|
||||
stats->num_6 = 0;
|
||||
stats->num_7 = 0;
|
||||
stats->num_8 = 0;
|
||||
stats->num_9 = 0;
|
||||
stats->num_0 = 0;
|
||||
|
||||
stats->up = 0;
|
||||
stats->down = 0;
|
||||
stats->left = 0;
|
||||
stats->right = 0;
|
||||
|
||||
stats->lctrl = 0;
|
||||
}
|
||||
|
||||
void mouse_status_init(mouse_status_t *const stats) {
|
||||
stats->connected = true;
|
||||
|
||||
stats->x = 0;
|
||||
stats->y = 0;
|
||||
stats->btn_left = 0;
|
||||
stats->btn_middle = 0;
|
||||
stats->btn_right = 0;
|
||||
}
|
||||
|
||||
void gamepad_status_init(gamepad_status_t *const stats) {
|
||||
|
|
@ -39,13 +95,19 @@ void gamepad_status_init(gamepad_status_t *const stats) {
|
|||
stats->leds_colors[0] = 0;
|
||||
stats->leds_colors[1] = 0;
|
||||
stats->leds_colors[2] = 0;
|
||||
stats->touchpad_touch_num = -1;
|
||||
stats->touchpad_x = 0;
|
||||
stats->touchpad_y = 0;
|
||||
stats->join_left_analog_and_gyroscope = 0;
|
||||
stats->join_right_analog_and_gyroscope = 0;
|
||||
stats->flags = 0;
|
||||
}
|
||||
|
||||
void devices_status_init(devices_status_t *const stats) {
|
||||
pthread_mutex_init(&stats->mutex, NULL);
|
||||
gamepad_status_init(&stats->gamepad);
|
||||
kbd_status_init(&stats->kbd);
|
||||
// TODO: mouse init
|
||||
mouse_status_init(&stats->mouse);
|
||||
}
|
||||
|
||||
void gamepad_status_qam_quirk(gamepad_status_t *const gamepad_stats) {
|
||||
|
|
@ -106,13 +168,15 @@ void gamepad_status_qam_quirk(gamepad_status_t *const gamepad_stats) {
|
|||
}
|
||||
}
|
||||
|
||||
void gamepad_status_qam_quirk_ext_time(gamepad_status_t *const gamepad_stats, struct timeval *now) {
|
||||
void gamepad_status_qam_quirk_ext_time(gamepad_status_t *const gamepad_stats) {
|
||||
static struct timeval press_time;
|
||||
if (gamepad_stats->flags & GAMEPAD_STATUS_FLAGS_PRESS_AND_REALEASE_CENTER) {
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
|
||||
// Calculate elapsed time in milliseconds
|
||||
const int64_t elapsed_time = (now->tv_sec - press_time.tv_sec) * 1000 +
|
||||
(now->tv_usec - press_time.tv_usec) / 1000;
|
||||
const int64_t elapsed_time = (now.tv_sec - press_time.tv_sec) * 1000 +
|
||||
(now.tv_usec - press_time.tv_usec) / 1000;
|
||||
|
||||
if (gamepad_stats->center) {
|
||||
// If the center button is pressed and at least X ms have passed
|
||||
|
|
|
|||
|
|
@ -46,8 +46,12 @@ typedef struct gamepad_status {
|
|||
|
||||
uint8_t touchpad_press;
|
||||
|
||||
struct timeval last_gyro_motion_time;
|
||||
struct timeval last_accel_motion_time;
|
||||
int16_t touchpad_touch_num; // touchpad is inactive when this is -1
|
||||
int16_t touchpad_x; // 0 to 1920
|
||||
int16_t touchpad_y; // 0 to 1080
|
||||
|
||||
int64_t last_gyro_motion_timestamp_ns;
|
||||
int64_t last_accel_motion_timestamp_ns;
|
||||
|
||||
double gyro[3]; // | x, y, z| right-hand-rules -- in rad/s
|
||||
double accel[3]; // | x, y, z| positive: right, up, towards player -- in m/s^2
|
||||
|
|
@ -61,14 +65,39 @@ typedef struct gamepad_status {
|
|||
uint64_t leds_events_count;
|
||||
uint8_t leds_colors[3]; // r | g | b
|
||||
|
||||
uint8_t join_left_analog_and_gyroscope;
|
||||
uint8_t join_right_analog_and_gyroscope;
|
||||
|
||||
volatile uint32_t flags;
|
||||
|
||||
} gamepad_status_t;
|
||||
|
||||
typedef struct keyboard_status {
|
||||
bool connected;
|
||||
|
||||
uint8_t q,w,e,r,t,y,u,i,o,p,a,s,d,f,g,h,j,k,l,z,x,c,v,b,n,m;
|
||||
|
||||
uint8_t num_1, num_2, num_3, num_4, num_5, num_6, num_7, num_8, num_9, num_0;
|
||||
|
||||
uint8_t up, down, left, right;
|
||||
|
||||
uint8_t lctrl;
|
||||
|
||||
} keyboard_status_t;
|
||||
|
||||
|
||||
typedef struct mouse_status {
|
||||
bool connected;
|
||||
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
|
||||
uint8_t btn_left;
|
||||
uint8_t btn_middle;
|
||||
uint8_t btn_right;
|
||||
|
||||
} mouse_status_t;
|
||||
|
||||
typedef struct devices_status {
|
||||
// this mutex MUST be grabbed when reading and/or writing below properties
|
||||
pthread_mutex_t mutex;
|
||||
|
|
@ -77,8 +106,12 @@ typedef struct devices_status {
|
|||
|
||||
keyboard_status_t kbd;
|
||||
|
||||
mouse_status_t mouse;
|
||||
|
||||
} devices_status_t;
|
||||
|
||||
void mouse_status_init(mouse_status_t *const stats);
|
||||
|
||||
void kbd_status_init(keyboard_status_t *const stats);
|
||||
|
||||
void gamepad_status_init(gamepad_status_t *const stats);
|
||||
|
|
@ -87,4 +120,4 @@ void devices_status_init(devices_status_t *const stats);
|
|||
|
||||
void gamepad_status_qam_quirk(gamepad_status_t *const gamepad_stats);
|
||||
|
||||
void gamepad_status_qam_quirk_ext_time(gamepad_status_t *const gamepad_stats, struct timeval *now);
|
||||
void gamepad_status_qam_quirk_ext_time(gamepad_status_t *const gamepad_stats);
|
||||
|
|
|
|||
82
input_dev.h
82
input_dev.h
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "message.h"
|
||||
#include "settings.h"
|
||||
|
||||
#undef INCLUDE_INPUT_DEBUG
|
||||
#undef IGNORE_INPUT_SCAN
|
||||
|
|
@ -17,13 +18,26 @@ typedef struct evdev_collected {
|
|||
* A function with this signature grapbs input_event data and sends to the pipe messages
|
||||
* constructed from that data.
|
||||
*/
|
||||
typedef int (*ev_map)(const evdev_collected_t *const e, in_message_t *const messages, size_t messages_len, void* user_data);
|
||||
typedef int (*hidraw_map)(int hidraw_fd, in_message_t *const messages, size_t messages_len, void* user_data);
|
||||
typedef int (*ev_map)(
|
||||
const dev_in_settings_t *const conf,
|
||||
const evdev_collected_t *const e,
|
||||
in_message_t *const messages,
|
||||
size_t messages_len,
|
||||
void* user_data
|
||||
);
|
||||
typedef void (*ev_timer)(
|
||||
const dev_in_settings_t *const conf,
|
||||
struct libevdev* evdev,
|
||||
const char* const timer_name,
|
||||
uint64_t expired,
|
||||
void* user_data
|
||||
);
|
||||
|
||||
typedef enum input_dev_type {
|
||||
input_dev_type_uinput,
|
||||
input_dev_type_iio,
|
||||
input_dev_type_hidraw,
|
||||
input_dev_type_timer,
|
||||
} input_dev_type_t;
|
||||
|
||||
typedef struct hidraw_filters {
|
||||
|
|
@ -40,13 +54,44 @@ typedef struct iio_filters {
|
|||
const char name[256];
|
||||
} iio_filters_t;
|
||||
|
||||
typedef int (*hidraw_set_leds)(uint8_t r, uint8_t g, uint8_t b, void* user_data);
|
||||
typedef int (*hidraw_map)(
|
||||
const dev_in_settings_t *const conf,
|
||||
int hidraw_fd,
|
||||
in_message_t *const messages,
|
||||
size_t messages_len,
|
||||
void* user_data
|
||||
);
|
||||
|
||||
typedef int (*hidraw_rumble)(uint8_t left_motor, uint8_t right_motor, void* user_data);
|
||||
typedef int (*hidraw_set_leds)(
|
||||
const dev_in_settings_t *const conf,
|
||||
int hidraw_fd,
|
||||
uint8_t r,
|
||||
uint8_t g,
|
||||
uint8_t b,
|
||||
void* user_data
|
||||
);
|
||||
|
||||
typedef int (*hidraw_rumble)(
|
||||
const dev_in_settings_t *const conf,
|
||||
int hidraw_fd,
|
||||
uint8_t left_motor,
|
||||
uint8_t right_motor,
|
||||
void* user_data
|
||||
);
|
||||
|
||||
typedef void (*hidraw_timer)(
|
||||
const dev_in_settings_t *const conf,
|
||||
int fd,
|
||||
const char* const timer_name,
|
||||
uint64_t expired,
|
||||
void* user_data
|
||||
);
|
||||
|
||||
typedef struct hidraw_callbacks {
|
||||
hidraw_set_leds leds_callback;
|
||||
hidraw_rumble rumble_callback;
|
||||
hidraw_map map_callback;
|
||||
hidraw_timer timeout_callback;
|
||||
} hidraw_callbacks_t;
|
||||
|
||||
typedef struct iio_settings {
|
||||
|
|
@ -54,6 +99,23 @@ typedef struct iio_settings {
|
|||
int8_t post_matrix[3][3];
|
||||
} iio_settings_t;
|
||||
|
||||
typedef int (*timer_map)(const dev_in_settings_t *const conf, int timer_fd, uint64_t expirations, in_message_t *const messages, size_t messages_len, void* user_data);
|
||||
|
||||
typedef struct timer_callbacks {
|
||||
timer_map map_fn;
|
||||
} timer_callbacks_t;
|
||||
|
||||
typedef struct ev_callbacks {
|
||||
ev_map input_map_fn;
|
||||
ev_timer timeout_callback;
|
||||
} ev_callbacks_t;
|
||||
|
||||
typedef struct timer_filters {
|
||||
char name[128];
|
||||
uint64_t ticktime_ms;
|
||||
uint64_t ticktime_ns;
|
||||
} timer_filters_t;
|
||||
|
||||
typedef struct input_dev {
|
||||
input_dev_type_t dev_type;
|
||||
|
||||
|
|
@ -61,23 +123,25 @@ typedef struct input_dev {
|
|||
uinput_filters_t ev;
|
||||
iio_filters_t iio;
|
||||
hidraw_filters_t hidraw;
|
||||
timer_filters_t timer;
|
||||
} filters;
|
||||
|
||||
void* user_data;
|
||||
|
||||
union input_dev_map {
|
||||
iio_settings_t iio_settings;
|
||||
ev_map ev_input_map_fn;
|
||||
hidraw_map hidraw_input_map_fn;
|
||||
ev_callbacks_t ev_callbacks;
|
||||
hidraw_callbacks_t hidraw_callbacks;
|
||||
timer_callbacks_t timer_callbacks;
|
||||
} map;
|
||||
|
||||
} input_dev_t;
|
||||
|
||||
typedef int (*platform_init)(void** platform_data);
|
||||
typedef int (*platform_init)(const dev_in_settings_t *const conf, void** platform_data);
|
||||
|
||||
typedef void (*platform_deinit)(void** platform_data);
|
||||
typedef void (*platform_deinit)(const dev_in_settings_t *const conf, void** platform_data);
|
||||
|
||||
typedef int (*platform_leds)(uint8_t r, uint8_t g, uint8_t b, void* platform_data);
|
||||
typedef int (*platform_leds)(const dev_in_settings_t *const conf, uint8_t r, uint8_t g, uint8_t b, void* platform_data);
|
||||
|
||||
typedef struct input_dev_composite {
|
||||
|
||||
|
|
|
|||
23
legion_go.c
23
legion_go.c
|
|
@ -11,12 +11,12 @@ static input_dev_t in_xbox_dev = {
|
|||
}
|
||||
},
|
||||
.map = {
|
||||
.ev_input_map_fn = xbox360_ev_map,
|
||||
.ev_callbacks = {
|
||||
.input_map_fn = xbox360_ev_map,
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
static xbox360_settings_t x360_cfg;
|
||||
|
||||
static input_dev_t in_iio_dev = {
|
||||
.dev_type = input_dev_type_iio,
|
||||
.filters = {
|
||||
|
|
@ -40,7 +40,7 @@ static struct llg_hidraw_data {
|
|||
uint8_t last_packet[64];
|
||||
} llg_hidraw_user_data;
|
||||
|
||||
static int llg_hidraw_map(int hidraw_fd, in_message_t *const messages, size_t messages_len, void* user_data) {
|
||||
static int llg_hidraw_map(const dev_in_settings_t *const conf, int hidraw_fd, in_message_t *const messages, size_t messages_len, void* user_data) {
|
||||
struct llg_hidraw_data *const llg_data = (struct llg_hidraw_data*)user_data;
|
||||
|
||||
int msg_count = 0;
|
||||
|
|
@ -84,7 +84,9 @@ static input_dev_t in_hidraw_dev = {
|
|||
},
|
||||
.user_data = (void*)&llg_hidraw_user_data,
|
||||
.map = {
|
||||
.hidraw_input_map_fn = llg_hidraw_map,
|
||||
.hidraw_callbacks = {
|
||||
.map_callback = llg_hidraw_map,
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -92,7 +94,7 @@ typedef struct legion_go_platform {
|
|||
int _pad;
|
||||
} legion_go_platform_t;
|
||||
|
||||
static int legion_platform_init(void** platform_data) {
|
||||
static int legion_platform_init(const dev_in_settings_t *const conf, void** platform_data) {
|
||||
int res = -EINVAL;
|
||||
|
||||
legion_go_platform_t *const llg_platform = malloc(sizeof(legion_go_platform_t));
|
||||
|
|
@ -109,12 +111,12 @@ legion_platform_init_err:
|
|||
return res;
|
||||
}
|
||||
|
||||
static void legion_platform_deinit(void** platform_data) {
|
||||
static void legion_platform_deinit(const dev_in_settings_t *const conf, void** platform_data) {
|
||||
free(*platform_data);
|
||||
*platform_data = NULL;
|
||||
}
|
||||
|
||||
int legion_platform_leds(uint8_t r, uint8_t g, uint8_t b, void* platform_data) {
|
||||
int legion_platform_leds(const dev_in_settings_t *const conf, uint8_t r, uint8_t g, uint8_t b, void* platform_data) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -131,10 +133,7 @@ input_dev_composite_t legion_composite = {
|
|||
};
|
||||
|
||||
|
||||
input_dev_composite_t* legion_go_device_def(const controller_settings_t *const settings) {
|
||||
x360_cfg.nintendo_layout = settings->nintendo_layout;
|
||||
|
||||
in_xbox_dev.user_data = (void*)&x360_cfg;
|
||||
input_dev_composite_t* legion_go_device_def(void) {
|
||||
return &legion_composite;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,4 +3,4 @@
|
|||
#include "input_dev.h"
|
||||
#include "settings.h"
|
||||
|
||||
input_dev_composite_t* legion_go_device_def(const controller_settings_t *const settings);
|
||||
input_dev_composite_t* legion_go_device_def(void);
|
||||
|
|
|
|||
75
main.c
75
main.c
|
|
@ -10,15 +10,33 @@
|
|||
#include "rog_ally.h"
|
||||
#include "legion_go.h"
|
||||
|
||||
#include <sys/mman.h>
|
||||
|
||||
static const char* configuration_file = "/etc/ROGueENEMY/config.cfg";
|
||||
|
||||
controller_settings_t settings;
|
||||
|
||||
int main(int argc, char ** argv) {
|
||||
// Lock all current and future pages from preventing of being paged to swap
|
||||
const int lockall_res = mlockall( MCL_CURRENT | MCL_FUTURE );
|
||||
if (lockall_res) {
|
||||
fprintf(stderr, "mlockall failed: %d", lockall_res);
|
||||
}
|
||||
|
||||
int ret = 0;
|
||||
|
||||
init_config(&settings);
|
||||
fill_config(&settings, configuration_file);
|
||||
dev_in_settings_t in_settings = {
|
||||
.enable_qam = true,
|
||||
.ff_gain = 0xFFFF,
|
||||
.rumble_on_mode_switch = true,
|
||||
.m1m2_mode = 1,
|
||||
.touchbar = true,
|
||||
.enable_thermal_profiles_switching = false,
|
||||
.default_thermal_profile = -1,
|
||||
.enable_leds_commands = false,
|
||||
.enable_imu = true,
|
||||
.imu_polling_interface = true,
|
||||
};
|
||||
|
||||
load_in_config(&in_settings, configuration_file);
|
||||
|
||||
input_dev_composite_t* in_devs = NULL;
|
||||
|
||||
|
|
@ -33,10 +51,10 @@ int main(int argc, char ** argv) {
|
|||
read(dmi_name_fd, bname, sizeof(bname));
|
||||
if (strstr(bname, "RC71L") != NULL) {
|
||||
printf("Running in an Asus ROG Ally device\n");
|
||||
in_devs = rog_ally_device_def(&settings);
|
||||
in_devs = rog_ally_device_def(&in_settings);
|
||||
} else if (strstr(bname, "LNVNB161216")) {
|
||||
printf("Running in an Lenovo Legion Go device\n");
|
||||
in_devs = legion_go_device_def(&settings);
|
||||
in_devs = legion_go_device_def();
|
||||
}
|
||||
close(dmi_name_fd);
|
||||
|
||||
|
|
@ -55,13 +73,54 @@ int main(int argc, char ** argv) {
|
|||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
.settings = in_settings,
|
||||
};
|
||||
|
||||
// fill in configuration from file: automatic fallback to default
|
||||
load_in_config(&dev_in_thread_data.settings, configuration_file);
|
||||
|
||||
//memset(&dev_in_thread_data.communication.endpoint.socket.serveraddr, 0, sizeof(dev_in_thread_data.communication.endpoint.socket.serveraddr));
|
||||
|
||||
// Initialize pthread attributes (default values)
|
||||
struct sched_param param;
|
||||
pthread_attr_t attr;
|
||||
ret = pthread_attr_init(&attr);
|
||||
if (ret) {
|
||||
printf("init pthread attributes failed\n");
|
||||
goto main_err;
|
||||
}
|
||||
|
||||
// Set a specific stack size
|
||||
ret = pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN + 8192);
|
||||
if (ret) {
|
||||
printf("pthread setstacksize failed\n");
|
||||
goto main_err;
|
||||
}
|
||||
|
||||
// Set scheduler policy and priority of pthread
|
||||
ret = pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
|
||||
if (ret) {
|
||||
printf("pthread setschedpolicy failed\n");
|
||||
goto main_err;
|
||||
}
|
||||
param.sched_priority = 80;
|
||||
ret = pthread_attr_setschedparam(&attr, ¶m);
|
||||
if (ret) {
|
||||
printf("pthread setschedparam failed\n");
|
||||
goto main_err;
|
||||
}
|
||||
|
||||
// Use scheduling parameters of attr
|
||||
ret = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
|
||||
if (ret) {
|
||||
printf("pthread setinheritsched failed\n");
|
||||
goto main_err;
|
||||
}
|
||||
|
||||
|
||||
pthread_t dev_in_thread;
|
||||
const int dev_in_thread_creation = pthread_create(&dev_in_thread, NULL, dev_in_thread_func, (void*)(&dev_in_thread_data));
|
||||
const int dev_in_thread_creation = pthread_create(&dev_in_thread, &attr, dev_in_thread_func, (void*)(&dev_in_thread_data));
|
||||
if (dev_in_thread_creation != 0) {
|
||||
fprintf(stderr, "Error creating dev_in thread: %d\n", dev_in_thread_creation);
|
||||
ret = -1;
|
||||
|
|
|
|||
112
message.h
112
message.h
|
|
@ -24,6 +24,8 @@ typedef enum in_message_gamepad_btn {
|
|||
GAMEPAD_BTN_L5,
|
||||
GAMEPAD_BTN_R5,
|
||||
GAMEPAD_BTN_TOUCHPAD,
|
||||
GAMEPAD_BTN_JOIN_LEFT_ANALOG_AND_GYROSCOPE,
|
||||
GAMEPAD_BTN_JOIN_RIGHT_ANALOG_AND_GYROSCOPE,
|
||||
|
||||
GAMEPAD_LEFT_JOYSTICK_X,
|
||||
GAMEPAD_LEFT_JOYSTICK_Y,
|
||||
|
|
@ -32,36 +34,142 @@ typedef enum in_message_gamepad_btn {
|
|||
|
||||
GAMEPAD_DPAD_X,
|
||||
GAMEPAD_DPAD_Y,
|
||||
|
||||
GAMEPAD_GYROSCOPE,
|
||||
GAMEPAD_ACCELEROMETER,
|
||||
|
||||
GAMEPAD_TOUCHPAD_X,
|
||||
GAMEPAD_TOUCHPAD_Y,
|
||||
GAMEPAD_TOUCHPAD_TOUCH_ACTIVE,
|
||||
} in_gamepad_element_t;
|
||||
|
||||
typedef struct in_message_gamepad_touchpad_x {
|
||||
int16_t value;
|
||||
} in_message_gamepad_touchpad_x_t;
|
||||
|
||||
typedef struct in_message_gamepad_touchpad_y {
|
||||
int16_t value;
|
||||
} in_message_gamepad_touchpad_y_t;
|
||||
|
||||
typedef struct in_message_gamepad_touchpad_active {
|
||||
int16_t status;
|
||||
} in_message_gamepad_touchpad_active_t;
|
||||
|
||||
typedef struct in_message_gamepad_gyro {
|
||||
int64_t sample_timestamp_ns;
|
||||
|
||||
uint16_t x;
|
||||
uint16_t y;
|
||||
uint16_t z;
|
||||
} in_message_gamepad_gyro_t;
|
||||
|
||||
typedef struct in_message_gamepad_accel {
|
||||
int64_t sample_timestamp_ns;
|
||||
|
||||
uint16_t x;
|
||||
uint16_t y;
|
||||
uint16_t z;
|
||||
} in_message_gamepad_accel_t;
|
||||
|
||||
typedef struct in_message_gamepad_set_element {
|
||||
in_gamepad_element_t element;
|
||||
union {
|
||||
uint8_t btn;
|
||||
int32_t joystick_pos;
|
||||
int8_t dpad; // -1 | 0 | +1
|
||||
in_message_gamepad_accel_t accel;
|
||||
in_message_gamepad_gyro_t gyro;
|
||||
in_message_gamepad_touchpad_active_t touchpad_active;
|
||||
in_message_gamepad_touchpad_x_t touchpad_x;
|
||||
in_message_gamepad_touchpad_y_t touchpad_y;
|
||||
} status;
|
||||
} in_message_gamepad_set_element_t;
|
||||
|
||||
typedef enum mouse_element {
|
||||
MOUSE_ELEMENT_X,
|
||||
MOUSE_ELEMENT_Y,
|
||||
MOUSE_BTN_LEFT,
|
||||
MOUSE_BTN_MIDDLE,
|
||||
MOUSE_BTN_RIGHT,
|
||||
} mouse_element_t;
|
||||
|
||||
typedef struct in_message_mouse_event {
|
||||
mouse_element_t type;
|
||||
int32_t value;
|
||||
} in_message_mouse_event_t;
|
||||
|
||||
typedef enum in_message_gamepad_action {
|
||||
GAMEPAD_ACTION_PRESS_AND_RELEASE_CENTER,
|
||||
GAMEPAD_ACTION_OPEN_STEAM_QAM,
|
||||
} in_message_gamepad_action_t;
|
||||
|
||||
typedef enum kbd_element {
|
||||
KEYBOARD_KEY_Q,
|
||||
KEYBOARD_KEY_W,
|
||||
KEYBOARD_KEY_E,
|
||||
KEYBOARD_KEY_R,
|
||||
KEYBOARD_KEY_T,
|
||||
KEYBOARD_KEY_Y,
|
||||
KEYBOARD_KEY_U,
|
||||
KEYBOARD_KEY_I,
|
||||
KEYBOARD_KEY_O,
|
||||
KEYBOARD_KEY_P,
|
||||
KEYBOARD_KEY_A,
|
||||
KEYBOARD_KEY_S,
|
||||
KEYBOARD_KEY_D,
|
||||
KEYBOARD_KEY_F,
|
||||
KEYBOARD_KEY_G,
|
||||
KEYBOARD_KEY_H,
|
||||
KEYBOARD_KEY_J,
|
||||
KEYBOARD_KEY_K,
|
||||
KEYBOARD_KEY_L,
|
||||
KEYBOARD_KEY_Z,
|
||||
KEYBOARD_KEY_X,
|
||||
KEYBOARD_KEY_C,
|
||||
KEYBOARD_KEY_V,
|
||||
KEYBOARD_KEY_B,
|
||||
KEYBOARD_KEY_N,
|
||||
KEYBOARD_KEY_M,
|
||||
KEYBOARD_KEY_UP,
|
||||
KEYBOARD_KEY_DOWN,
|
||||
KEYBOARD_KEY_LEFT,
|
||||
KEYBOARD_KEY_RIGHT,
|
||||
KEYBOARD_KEY_NUM_1,
|
||||
KEYBOARD_KEY_NUM_2,
|
||||
KEYBOARD_KEY_NUM_3,
|
||||
KEYBOARD_KEY_NUM_4,
|
||||
KEYBOARD_KEY_NUM_5,
|
||||
KEYBOARD_KEY_NUM_6,
|
||||
KEYBOARD_KEY_NUM_7,
|
||||
KEYBOARD_KEY_NUM_8,
|
||||
KEYBOARD_KEY_NUM_9,
|
||||
KEYBOARD_KEY_NUM_0,
|
||||
KEYBOARD_KEY_LCRTL,
|
||||
} kbd_element_t;
|
||||
|
||||
typedef struct in_message_keyboard_set_element {
|
||||
kbd_element_t type;
|
||||
uint8_t value;
|
||||
} in_message_keyboard_set_element_t;
|
||||
|
||||
typedef enum in_in_message_type {
|
||||
GAMEPAD_SET_ELEMENT,
|
||||
GAMEPAD_ACTION,
|
||||
MOUSE_EVENT,
|
||||
KEYBOARD_SET_ELEMENT,
|
||||
} in_message_type_t;
|
||||
|
||||
typedef struct in_message {
|
||||
in_message_type_t type;
|
||||
|
||||
union {
|
||||
//imu_in_message_t imu;
|
||||
|
||||
in_message_gamepad_action_t action;
|
||||
|
||||
in_message_gamepad_set_element_t gamepad_set;
|
||||
|
||||
in_message_mouse_event_t mouse_event;
|
||||
|
||||
in_message_keyboard_set_element_t kbd_set;
|
||||
} data;
|
||||
|
||||
} in_message_t;
|
||||
|
|
|
|||
276
platform.c
276
platform.c
|
|
@ -1,276 +0,0 @@
|
|||
#include <asm-generic/errno-base.h>
|
||||
#include <stdlib.h>
|
||||
#include <libudev.h>
|
||||
|
||||
#include <dirent.h>
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
static const char* const platform_input_path = "/sys/devices/platform/asus-mcu.0/input/mode";
|
||||
|
||||
static int hidraw_cycle_to_mode(const char* const path, int controller_mode) {
|
||||
int res = 0;
|
||||
|
||||
if ((controller_mode < 0) || (controller_mode > 2)) {
|
||||
res = -EINVAL;
|
||||
goto hidraw_cycle_to_mode_err_mode;
|
||||
}
|
||||
|
||||
const char* hidraw_subdir = "/hidraw/";
|
||||
|
||||
const unsigned long len = strlen(path) + strlen(hidraw_subdir) + 64;
|
||||
char* hidraw_path = malloc(len + 1);
|
||||
if (hidraw_path == NULL) {
|
||||
res = -ENOMEM;
|
||||
goto hidraw_cycle_to_mode_err_path;
|
||||
}
|
||||
|
||||
memset(hidraw_path, 0, len + 1);
|
||||
strcat(hidraw_path, path);
|
||||
strcat(hidraw_path, hidraw_subdir);
|
||||
|
||||
DIR *d;
|
||||
struct dirent *dir;
|
||||
d = opendir(hidraw_path);
|
||||
if (d) {
|
||||
while ((dir = readdir(d)) != NULL) {
|
||||
if (strstr(dir->d_name, "hidraw") == NULL) { // h as in hidraw
|
||||
continue;
|
||||
}
|
||||
|
||||
memset(hidraw_path, 0, len + 1);
|
||||
strcat(hidraw_path, "/dev/");
|
||||
strcat(hidraw_path, dir->d_name);
|
||||
|
||||
//strcat(hidraw_path, dir->d_name);
|
||||
//strcat(hidraw_path, "/dev");
|
||||
|
||||
printf("Using hidraw located at: %s\n", hidraw_path);
|
||||
|
||||
int fd = open(hidraw_path, O_RDWR);
|
||||
if (fd == -1) {
|
||||
fprintf(stderr, "Error opening hidraw device %s\n", hidraw_path);
|
||||
|
||||
res = -EIO;
|
||||
|
||||
goto hidraw_cycle_to_mode_err;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 23; ++i) {
|
||||
const int write_res = write(fd, &rc71l_mode_switch_commands[controller_mode][i][0], 64);
|
||||
if (write_res != 64) {
|
||||
fprintf(stderr, "Error writing packet %d/23: %d bytes sent, 64 expected\n", i, write_res);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
if (res == 0) {
|
||||
printf("Control messages sent successfully.\n");
|
||||
} else {
|
||||
goto hidraw_cycle_to_mode_err;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
hidraw_cycle_to_mode_err:
|
||||
free(hidraw_path);
|
||||
|
||||
hidraw_cycle_to_mode_err_path:
|
||||
hidraw_cycle_to_mode_err_mode:
|
||||
return res;
|
||||
}
|
||||
|
||||
static char* find_device(struct udev *udev) {
|
||||
struct udev_enumerate *const enumerate = udev_enumerate_new(udev);
|
||||
if (enumerate == NULL) {
|
||||
fprintf(stderr, "Error in udev_enumerate_new: mode switch will not be available.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const int add_match_subsystem_res = udev_enumerate_add_match_subsystem(enumerate, "hid");
|
||||
if (add_match_subsystem_res != 0) {
|
||||
fprintf(stderr, "Error in udev_enumerate_add_match_subsystem: %d\n", add_match_subsystem_res);
|
||||
|
||||
udev_enumerate_unref(enumerate);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const int add_match_sysattr_res = udev_enumerate_add_match_sysattr(enumerate, "gamepad_mode", NULL);
|
||||
if (add_match_sysattr_res != 0) {
|
||||
fprintf(stderr, "Error in udev_enumerate_add_match_sysattr: %d\n", add_match_sysattr_res);
|
||||
|
||||
udev_enumerate_unref(enumerate);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const int enumerate_scan_devices_res = udev_enumerate_scan_devices(enumerate);
|
||||
if (enumerate_scan_devices_res != 0) {
|
||||
fprintf(stderr, "Error in udev_enumerate_scan_devices: %d\n", enumerate_scan_devices_res);
|
||||
|
||||
udev_enumerate_unref(enumerate);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct udev_list_entry *const udev_lst_frst = udev_enumerate_get_list_entry(enumerate);
|
||||
|
||||
struct udev_list_entry *list_entry = NULL;
|
||||
udev_list_entry_foreach(list_entry, udev_lst_frst) {
|
||||
const char* const name = udev_list_entry_get_name(list_entry);
|
||||
|
||||
const unsigned long len = strlen(name) + 1;
|
||||
char *const result = malloc(len);
|
||||
memset(result, 0, len);
|
||||
strncat(result, name, len - 1);
|
||||
|
||||
udev_enumerate_unref(enumerate);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
udev_enumerate_unref(enumerate);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int init_platform(rc71l_platform_t *const platform) {
|
||||
platform->udev = NULL;
|
||||
|
||||
if (access(platform_input_path, F_OK) != 0) {
|
||||
fprintf(stderr, "Unable to find the MCU platform mode file %s: asus-mcu not found.\n", platform_input_path);
|
||||
|
||||
/* create udev object */
|
||||
platform->udev = udev_new();
|
||||
if (platform->udev == NULL) {
|
||||
fprintf(stderr, "Cannot create udev context: mode switch will not be available.\n");
|
||||
platform->mode = -1;
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
char *const dev_name = find_device(platform->udev);
|
||||
if (dev_name == NULL) {
|
||||
fprintf(stderr, "Cannot locate asus-mcu device: mode switch will not be available.\n");
|
||||
platform->mode = -1;
|
||||
return -ENOENT;
|
||||
} else {
|
||||
printf("Asus MCU over hidraw: %s -- mode will be reset\n", dev_name);
|
||||
|
||||
platform->platform_mode = rc71l_platform_mode_hidraw;
|
||||
platform->modes_count = 2;
|
||||
platform->mode = 0;
|
||||
|
||||
// reset to mode 0: game mode
|
||||
const int reset_res = hidraw_cycle_to_mode(dev_name, 0);
|
||||
if (reset_res != 0) {
|
||||
fprintf(stderr, "Unable to reset Asus MCU over hidraw: %d -- Asus MCU will be unavailable.\n", reset_res);
|
||||
|
||||
free(dev_name);
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
// find_device does malloc
|
||||
free(dev_name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
FILE* mode_file = fopen(platform_input_path, "r");
|
||||
if (mode_file == NULL) {
|
||||
fprintf(stderr, "Unable to open the MCU platform mode file %s: modes cannot be switched.\n", platform_input_path);
|
||||
platform->mode = -1;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
char mode_str[12];
|
||||
unsigned long read_bytes = fread((void*)&mode_str[0], 1, sizeof(mode_str), mode_file);
|
||||
if (read_bytes < 1) {
|
||||
fprintf(stderr, "Unable to read the MCU platform mode file %s: no bytes.\n", platform_input_path);
|
||||
fclose(mode_file);
|
||||
platform->mode = -1;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
platform->mode = strtoul(&mode_str[0], NULL, 10);
|
||||
|
||||
fclose(mode_file);
|
||||
|
||||
printf("Asus MCU platform found: current mode %lu\n", platform->mode);
|
||||
platform->modes_count = 2;
|
||||
|
||||
platform->platform_mode = rc71l_platform_mode_asus_mcu;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cycle_mode(rc71l_platform_t *const platform) {
|
||||
if (platform == NULL) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
char new_mode_str[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
unsigned long new_mode = (platform->mode + 1) % platform->modes_count;
|
||||
sprintf(new_mode_str, "%lu\n", new_mode);
|
||||
|
||||
if (platform->platform_mode == rc71l_platform_mode_hidraw) {
|
||||
char *const dev_name = find_device(platform->udev);
|
||||
if (dev_name == NULL) {
|
||||
fprintf(stderr, "Unable to locate Asus MCU hidraw to mode-switch. Mode will not be switched.\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
const int next_mode = (platform->mode + 1) % platform->modes_count;
|
||||
|
||||
const int reset_res = hidraw_cycle_to_mode(dev_name, next_mode);
|
||||
if (reset_res != 0) {
|
||||
fprintf(stderr, "Unable to change mode of Asus MCU over hidraw: %d.\n", reset_res);
|
||||
}
|
||||
|
||||
free(dev_name);
|
||||
|
||||
platform->mode = next_mode;
|
||||
|
||||
printf("Used hidraw to switch Asus MCU to mode %lu\n", platform->mode);
|
||||
|
||||
return reset_res;
|
||||
} else if (platform->platform_mode == rc71l_platform_mode_asus_mcu) {
|
||||
FILE* mode_file = fopen(platform_input_path, "w");
|
||||
if (mode_file == NULL) {
|
||||
fprintf(stderr, "Unable to open the MCU platform mode file %s: modes cannot be switched.\n", platform_input_path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t len = strlen(new_mode_str);
|
||||
const int write_bytes = fwrite((void*)&new_mode_str[0], 1, len, mode_file);
|
||||
if (write_bytes < len) {
|
||||
fprintf(stderr, "Error writing new mode: expected to write %d bytes, %d written.\n", (int)len, (int)write_bytes);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
platform->mode = new_mode;
|
||||
|
||||
printf("Used asus-mcu to switch Asus MCU to mode %lu\n", platform->mode);
|
||||
|
||||
fclose(mode_file);
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int is_mouse_mode(rc71l_platform_t *const platform) {
|
||||
return platform != NULL ? platform->mode == 1 : 0;
|
||||
}
|
||||
23
platform.h
23
platform.h
|
|
@ -1,23 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "rogue_enemy.h"
|
||||
|
||||
typedef enum rc71l_platform_mode {
|
||||
rc71l_platform_mode_hidraw,
|
||||
rc71l_platform_mode_asus_mcu,
|
||||
} rc71l_platform_mode_t;
|
||||
|
||||
typedef struct rc71l_platform {
|
||||
struct udev *udev;
|
||||
|
||||
rc71l_platform_mode_t platform_mode;
|
||||
|
||||
unsigned long mode;
|
||||
unsigned int modes_count;
|
||||
} rc71l_platform_t;
|
||||
|
||||
int init_platform(rc71l_platform_t *const platform);
|
||||
|
||||
int cycle_mode(rc71l_platform_t *const platform);
|
||||
|
||||
int is_mouse_mode(rc71l_platform_t *const platform);
|
||||
2645
rog_ally.c
2645
rog_ally.c
File diff suppressed because it is too large
Load diff
|
|
@ -3,4 +3,4 @@
|
|||
#include "input_dev.h"
|
||||
#include "settings.h"
|
||||
|
||||
input_dev_composite_t* rog_ally_device_def(const controller_settings_t *const settings);
|
||||
input_dev_composite_t* rog_ally_device_def(const dev_in_settings_t *const settings);
|
||||
|
|
|
|||
18
rogue-enemy_iio_buffer_off.sh
Normal file
18
rogue-enemy_iio_buffer_off.sh
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
#!/bin/bash
|
||||
|
||||
for i in /sys/bus/iio/devices/* ; do
|
||||
if [ -d "$i" ]; then
|
||||
if [ -f "$i/name" ]; then
|
||||
name=$(cat "$i/name")
|
||||
if [ "$name" = "bmi323-imu" ]; then
|
||||
# bind fake hrtimer to to the iio device
|
||||
echo "void" > "$i/trigger/current_trigger"
|
||||
|
||||
# enable the buffer
|
||||
echo 0 > "$i/buffer0/enable"
|
||||
|
||||
echo "bmi323-imu buffer started"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
60
rogue-enemy_iio_buffer_on.sh
Normal file
60
rogue-enemy_iio_buffer_on.sh
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
#!/bin/bash
|
||||
modprobe industrialio-sw-trigger
|
||||
modprobe iio-trig-sysfs
|
||||
modprobe iio-trig-hrtimer
|
||||
|
||||
# hrtimer
|
||||
if [ ! -d "/home/config" ]; then
|
||||
mkdir -p /home/config
|
||||
fi
|
||||
|
||||
mount -t configfs none /home/config
|
||||
mkdir -p /home/config/iio/triggers/hrtimer/rogue
|
||||
|
||||
# set sampling frequency for rogue
|
||||
for i in /sys/bus/iio/devices/* ; do
|
||||
if [ -d "$i" ]; then
|
||||
if [ -f "$i/name" ]; then
|
||||
name=$(cat "$i/name")
|
||||
if [ "$name" = "rogue" ]; then
|
||||
echo "1600" > "$i/sampling_frequency"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# set the gyroscope
|
||||
for i in /sys/bus/iio/devices/* ; do
|
||||
if [ -d "$i" ]; then
|
||||
if [ -f "$i/name" ]; then
|
||||
name=$(cat "$i/name")
|
||||
if [ "$name" = "bmi323-imu" ]; then
|
||||
|
||||
# change chip sampling frequency
|
||||
echo "1600.000000" > "$i/in_accel_sampling_frequency"
|
||||
echo "1600.000000" > "$i/in_anglvel_sampling_frequency"
|
||||
|
||||
# enable accel data acquisition
|
||||
echo 1 > "$i/scan_elements/in_accel_x_en"
|
||||
echo 1 > "$i/scan_elements/in_accel_y_en"
|
||||
echo 1 > "$i/scan_elements/in_accel_z_en"
|
||||
|
||||
# enable gyroscope data acquisition
|
||||
echo 1 > "$i/scan_elements/in_anglvel_x_en"
|
||||
echo 1 > "$i/scan_elements/in_anglvel_y_en"
|
||||
echo 1 > "$i/scan_elements/in_anglvel_z_en"
|
||||
|
||||
# enable timestamp reporting
|
||||
echo 1 > "$i/scan_elements/in_timestamp_en"
|
||||
|
||||
# bind rogue hrtimer to to the iio device
|
||||
echo "rogue" > "$i/trigger/current_trigger"
|
||||
|
||||
# enable the buffer
|
||||
echo 1 > "$i/buffer0/enable"
|
||||
|
||||
echo "bmi323-imu buffer started"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
121
rogue_enemy.c
121
rogue_enemy.c
|
|
@ -5,3 +5,124 @@ int32_t div_round_closest(int32_t x, int32_t divisor) {
|
|||
const int32_t __d = divisor;
|
||||
return ((__x) > 0) == ((__d) > 0) ? (((__x) + ((__d) / 2)) / (__d)) : (((__x) - ((__d) / 2)) / (__d));
|
||||
}
|
||||
|
||||
int64_t div_round_closest_i64(int64_t x, int64_t divisor) {
|
||||
const int64_t __x = x;
|
||||
const int64_t __d = divisor;
|
||||
return ((__x) > 0) == ((__d) > 0) ? (((__x) + ((__d) / 2)) / (__d)) : (((__x) - ((__d) / 2)) / (__d));
|
||||
}
|
||||
|
||||
int64_t min_max_clamp(int64_t value, int64_t min, int64_t max) {
|
||||
if (value <= min) {
|
||||
return min;
|
||||
} else if (value >= max) {
|
||||
return max;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
int64_t absolute_value(int64_t value) {
|
||||
if (value < 0) {
|
||||
return (int64_t)-1 * value;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
ssize_t dmi_board_name(char *const buf, size_t buf_len) {
|
||||
int dmi_name_fd = open("/sys/class/dmi/id/board_name", O_RDONLY | O_NONBLOCK);
|
||||
if (dmi_name_fd < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(buf, 0, buf_len);
|
||||
const ssize_t ret = read(dmi_name_fd, buf, buf_len);
|
||||
close(dmi_name_fd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
char* inline_read_file(const char* base_path, const char *file) {
|
||||
char* res = NULL;
|
||||
char* fdir = NULL;
|
||||
long len = 0;
|
||||
|
||||
len = strlen(base_path) + strlen(file) + 1;
|
||||
fdir = malloc(len);
|
||||
if (fdir == NULL) {
|
||||
fprintf(stderr, "Cannot allocate %ld bytes for device path, device skipped.\n", len);
|
||||
goto read_file_err;
|
||||
}
|
||||
strcpy(fdir, base_path);
|
||||
strcat(fdir, file);
|
||||
|
||||
if (access(fdir, F_OK) == 0) {
|
||||
FILE* fp = fopen(fdir, "r");
|
||||
if (fp != NULL) {
|
||||
fseek(fp, 0L, SEEK_END);
|
||||
len = ftell(fp);
|
||||
rewind(fp);
|
||||
|
||||
len += 1;
|
||||
res = malloc(len);
|
||||
if (res != NULL) {
|
||||
unsigned long read_bytes = fread(res, 1, len, fp);
|
||||
printf("Read %lu bytes from file %s\n", read_bytes, fdir);
|
||||
} else {
|
||||
fprintf(stderr, "Cannot allocate %ld bytes for %s content.\n", len, fdir);
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
} else {
|
||||
fprintf(stderr, "Cannot open file %s.\n", fdir);
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "File %s does not exists.\n", fdir);
|
||||
}
|
||||
|
||||
free(fdir);
|
||||
fdir = NULL;
|
||||
|
||||
read_file_err:
|
||||
return res;
|
||||
}
|
||||
|
||||
int inline_write_file(const char* base_path, const char *file, const void* buf, size_t buf_sz) {
|
||||
char* fdir = NULL;
|
||||
|
||||
int res = 0;
|
||||
|
||||
const size_t len = strlen(base_path) + strlen(file) + 1;
|
||||
fdir = malloc(len);
|
||||
if (fdir == NULL) {
|
||||
fprintf(stderr, "Cannot allocate %ld bytes for device path, device skipped.\n", len);
|
||||
goto inline_write_file_err;
|
||||
}
|
||||
strcpy(fdir, base_path);
|
||||
strcat(fdir, file);
|
||||
|
||||
if (access(fdir, F_OK) == 0) {
|
||||
FILE* fp = fopen(fdir, "w");
|
||||
if (fp != NULL) {
|
||||
res = fwrite(buf, 1, buf_sz, fp);
|
||||
if (res >= buf_sz) {
|
||||
printf("Written %d bytes to file %s\n", res, fdir);
|
||||
} else {
|
||||
fprintf(stderr, "Cannot write to %s: %d.\n", fdir, res);
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
} else {
|
||||
fprintf(stderr, "Cannot open file %s.\n", fdir);
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "File %s does not exists.\n", fdir);
|
||||
}
|
||||
|
||||
free(fdir);
|
||||
fdir = NULL;
|
||||
|
||||
inline_write_file_err:
|
||||
return res;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
#include <sys/syscall.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/signalfd.h>
|
||||
#include <sys/timerfd.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#include <linux/hidraw.h>
|
||||
|
|
@ -41,12 +42,22 @@
|
|||
|
||||
#include <libevdev-1.0/libevdev/libevdev.h>
|
||||
|
||||
#include <libudev.h>
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
#define LSB_PER_RAD_S_2000_DEG_S ((double)0.001064724)
|
||||
#define LSB_PER_RAD_S_2000_DEG_S_STR "0.001064724"
|
||||
|
||||
#define LSB_PER_16G ((double)0.004785)
|
||||
#define LSB_PER_16G_STR "0.004785"
|
||||
|
||||
#define PREFERRED_SAMPLING_FREQ ((double)800.000000)
|
||||
#define PREFERRED_SAMPLING_FREQ_STR "800.000000"
|
||||
|
||||
#define PREFERRED_SAMPLING_FREQ_HIGH_HZ ((double)1600.000000)
|
||||
#define PREFERRED_SAMPLING_FREQ_HIGH_HZ_STR "1600.000000"
|
||||
|
||||
// courtesy of linux kernel
|
||||
#ifndef __packed
|
||||
#define __packed __attribute__((packed))
|
||||
|
|
@ -54,3 +65,15 @@
|
|||
|
||||
// also courtesy of linux kernel
|
||||
int32_t div_round_closest(int32_t x, int32_t divisor);
|
||||
|
||||
int64_t div_round_closest_i64(int64_t x, int64_t divisor);
|
||||
|
||||
int64_t min_max_clamp(int64_t value, int64_t min, int64_t max);
|
||||
|
||||
int64_t absolute_value(int64_t value);
|
||||
|
||||
ssize_t dmi_board_name(char *const buf, size_t buf_len);
|
||||
|
||||
char* inline_read_file(const char* base_path, const char *file);
|
||||
|
||||
int inline_write_file(const char* base_path, const char *file, const void* buf, size_t buf_sz);
|
||||
178
settings.c
178
settings.c
|
|
@ -2,68 +2,182 @@
|
|||
|
||||
#include <libconfig.h>
|
||||
|
||||
void init_config(controller_settings_t *const conf) {
|
||||
conf->ff_gain = 100;
|
||||
conf->enable_qam = 0;
|
||||
conf->nintendo_layout = 0;
|
||||
conf->gamepad_output_device = 1;
|
||||
conf->rumble_dedicated_thread = 0;
|
||||
}
|
||||
|
||||
int fill_config(controller_settings_t *const conf, const char* file) {
|
||||
int res = 0;
|
||||
|
||||
void load_in_config(dev_in_settings_t *const out_conf, const char* const filepath) {
|
||||
config_t cfg;
|
||||
|
||||
config_init(&cfg);
|
||||
|
||||
const int config_read_res = config_read_file(&cfg, file);
|
||||
const int config_read_res = config_read_file(&cfg, filepath);
|
||||
if (config_read_res != CONFIG_TRUE) {
|
||||
fprintf(stderr, "Error in reading config file: %s\n", config_error_text(&cfg));
|
||||
goto fill_config_err;
|
||||
goto load_in_config_err;
|
||||
}
|
||||
|
||||
int enable_qam;
|
||||
if (config_lookup_bool(&cfg, "enable_qam", &enable_qam) != CONFIG_FALSE) {
|
||||
conf->enable_qam = enable_qam;
|
||||
out_conf->enable_qam = enable_qam;
|
||||
} else {
|
||||
fprintf(stderr, "enable_qam (bool) configuration not found. Default value will be used.\n");
|
||||
}
|
||||
|
||||
int rumble_on_mode_switch;
|
||||
if (config_lookup_bool(&cfg, "rumble_on_mode_switch", &rumble_on_mode_switch) != CONFIG_FALSE) {
|
||||
out_conf->rumble_on_mode_switch = rumble_on_mode_switch;
|
||||
} else {
|
||||
fprintf(stderr, "rumble_on_mode_switch (bool) configuration not found. Default value will be used.\n");
|
||||
}
|
||||
|
||||
int ff_gain;
|
||||
if (config_lookup_int(&cfg, "ff_gain", &ff_gain) != CONFIG_FALSE) {
|
||||
if (ff_gain <= 100) {
|
||||
conf->ff_gain = (ff_gain == 100) ? 0xFFFF : ((int)0xFFFF / 100) * ff_gain;
|
||||
if (ff_gain <= 0xFF) {
|
||||
out_conf->ff_gain = (ff_gain == 0) ? 0x0000 : ((uint16_t)ff_gain << (uint16_t)8) | (uint16_t)0x00FF;
|
||||
} else {
|
||||
fprintf(stderr, "ff_gain (int) must be a number between 0 and 100");
|
||||
fprintf(stderr, "ff_gain (int) must be a number between 0 and 255");
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "ff_gain (int) configuration not found. Default value will be used.\n");
|
||||
}
|
||||
|
||||
int nintendo_layout;
|
||||
if (config_lookup_bool(&cfg, "nintendo_layout", &nintendo_layout) != CONFIG_FALSE) {
|
||||
conf->nintendo_layout = nintendo_layout;
|
||||
int m1m2_mode;
|
||||
if (config_lookup_int(&cfg, "m1m2_mode", &m1m2_mode) != CONFIG_FALSE) {
|
||||
if (m1m2_mode <= 2) {
|
||||
out_conf->m1m2_mode = m1m2_mode;
|
||||
} else {
|
||||
fprintf(stderr, "m1m2_mode (int) must be a number between 0 and 2");
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "nintendo_layout (bool) configuration not found. Default value will be used.\n");
|
||||
fprintf(stderr, "m1m2_mode (int) configuration not found. Default value will be used.\n");
|
||||
}
|
||||
|
||||
int gamepad_output_device;
|
||||
if (config_lookup_int(&cfg, "gamepad_output_device", &gamepad_output_device) != CONFIG_FALSE) {
|
||||
conf->gamepad_output_device = gamepad_output_device;
|
||||
int touchbar;
|
||||
if (config_lookup_bool(&cfg, "touchbar", &touchbar) != CONFIG_FALSE) {
|
||||
out_conf->touchbar = touchbar;
|
||||
} else {
|
||||
fprintf(stderr, "gamepad_output_device (int) configuration not found. Default value will be used.\n");
|
||||
fprintf(stderr, "touchbar (bool) configuration not found. Default value will be used.\n");
|
||||
}
|
||||
|
||||
int rumble_dedicated_thread;
|
||||
if (config_lookup_bool(&cfg, "rumble_dedicated_thread", &rumble_dedicated_thread) != CONFIG_FALSE) {
|
||||
conf->rumble_dedicated_thread = rumble_dedicated_thread;
|
||||
int enable_thermal_profiles_switching;
|
||||
if (config_lookup_bool(&cfg, "enable_thermal_profiles_switching", &enable_thermal_profiles_switching) != CONFIG_FALSE) {
|
||||
out_conf->enable_thermal_profiles_switching = enable_thermal_profiles_switching;
|
||||
} else {
|
||||
fprintf(stderr, "rumble_dedicated_thread (bool) configuration not found. Default value will be used.\n");
|
||||
fprintf(stderr, "enable_thermal_profiles_switching (bool) configuration not found. Default value will be used.\n");
|
||||
}
|
||||
|
||||
int default_thermal_profile;
|
||||
if (config_lookup_int(&cfg, "default_thermal_profile", &default_thermal_profile) != CONFIG_FALSE) {
|
||||
out_conf->default_thermal_profile = default_thermal_profile;
|
||||
} else {
|
||||
fprintf(stderr, "default_thermal_profile (int) configuration not found. Default value will be used.\n");
|
||||
}
|
||||
|
||||
int enable_leds_commands;
|
||||
if (config_lookup_bool(&cfg, "enable_leds_commands", &enable_leds_commands) != CONFIG_FALSE) {
|
||||
out_conf->enable_leds_commands = enable_leds_commands;
|
||||
} else {
|
||||
fprintf(stderr, "enable_leds_commands (bool) configuration not found. Default value will be used.\n");
|
||||
}
|
||||
|
||||
int enable_imu;
|
||||
if (config_lookup_bool(&cfg, "enable_imu", &enable_imu) != CONFIG_FALSE) {
|
||||
out_conf->enable_imu = enable_imu;
|
||||
} else {
|
||||
fprintf(stderr, "enable_imu (bool) configuration not found. Default value will be used.\n");
|
||||
}
|
||||
|
||||
int imu_polling_interface;
|
||||
if (config_lookup_bool(&cfg, "imu_polling_interface", &imu_polling_interface) != CONFIG_FALSE) {
|
||||
out_conf->imu_polling_interface = imu_polling_interface;
|
||||
} else {
|
||||
fprintf(stderr, "imu_polling_interface (bool) configuration not found. Default value will be used.\n");
|
||||
}
|
||||
|
||||
config_destroy(&cfg);
|
||||
|
||||
fill_config_err:
|
||||
return res;
|
||||
load_in_config_err:
|
||||
return;
|
||||
}
|
||||
|
||||
void load_out_config(dev_out_settings_t *const out_conf, const char* const filepath) {
|
||||
config_t cfg;
|
||||
config_init(&cfg);
|
||||
|
||||
const int config_read_res = config_read_file(&cfg, filepath);
|
||||
if (config_read_res != CONFIG_TRUE) {
|
||||
fprintf(stderr, "Error in reading config file: %s\n", config_error_text(&cfg));
|
||||
goto load_out_config_err;
|
||||
}
|
||||
|
||||
int nintendo_layout;
|
||||
if (config_lookup_bool(&cfg, "nintendo_layout", &nintendo_layout) != CONFIG_FALSE) {
|
||||
out_conf->nintendo_layout = nintendo_layout;
|
||||
} else {
|
||||
fprintf(stderr, "nintendo_layout (bool) configuration not found. Default value will be used.\n");
|
||||
}
|
||||
|
||||
int default_gamepad;
|
||||
if (config_lookup_int(&cfg, "default_gamepad", &default_gamepad) != CONFIG_FALSE) {
|
||||
out_conf->default_gamepad = default_gamepad % 3;
|
||||
} else {
|
||||
fprintf(stderr, "default_gamepad (int) configuration not found. Default value will be used.\n");
|
||||
}
|
||||
|
||||
int gamepad_leds_control;
|
||||
if (config_lookup_bool(&cfg, "gamepad_leds_control", &gamepad_leds_control) != CONFIG_FALSE) {
|
||||
out_conf->gamepad_leds_control = gamepad_leds_control;
|
||||
} else {
|
||||
fprintf(stderr, "gamepad_leds_control (bool) configuration not found. Default value will be used.\n");
|
||||
}
|
||||
|
||||
int gamepad_rumble_control;
|
||||
if (config_lookup_bool(&cfg, "gamepad_rumble_control", &gamepad_rumble_control) != CONFIG_FALSE) {
|
||||
out_conf->gamepad_rumble_control = gamepad_rumble_control;
|
||||
} else {
|
||||
fprintf(stderr, "gamepad_rumble_control (bool) configuration not found. Default value will be used.\n");
|
||||
}
|
||||
|
||||
int controller_bluetooth;
|
||||
if (config_lookup_bool(&cfg, "controller_bluetooth", &controller_bluetooth) != CONFIG_FALSE) {
|
||||
out_conf->controller_bluetooth = controller_bluetooth;
|
||||
} else {
|
||||
fprintf(stderr, "controller_bluetooth (bool) configuration not found. Default value will be used.\n");
|
||||
}
|
||||
|
||||
int dualsense_edge;
|
||||
if (config_lookup_bool(&cfg, "dualsense_edge", &dualsense_edge) != CONFIG_FALSE) {
|
||||
out_conf->dualsense_edge = dualsense_edge;
|
||||
} else {
|
||||
fprintf(stderr, "dualsense_edge (bool) configuration not found. Default value will be used.\n");
|
||||
}
|
||||
|
||||
int swap_y_z;
|
||||
if (config_lookup_bool(&cfg, "swap_y_z", &swap_y_z) != CONFIG_FALSE) {
|
||||
out_conf->swap_y_z = swap_y_z;
|
||||
} else {
|
||||
fprintf(stderr, "swap_y_z (bool) configuration not found. Default value will be used.\n");
|
||||
}
|
||||
|
||||
int invert_x;
|
||||
if (config_lookup_bool(&cfg, "invert_x", &invert_x) != CONFIG_FALSE) {
|
||||
out_conf->invert_x = invert_x;
|
||||
} else {
|
||||
fprintf(stderr, "invert_x (bool) configuration not found. Default value will be used.\n");
|
||||
}
|
||||
|
||||
int gyro_to_analog_activation_treshold;
|
||||
if (config_lookup_int(&cfg, "gyro_to_analog_activation_treshold", &gyro_to_analog_activation_treshold) != CONFIG_FALSE) {
|
||||
out_conf->gyro_to_analog_activation_treshold = gyro_to_analog_activation_treshold;
|
||||
} else {
|
||||
fprintf(stderr, "gyro_to_analog_activation_treshold (int) configuration not found. Default value will be used.\n");
|
||||
}
|
||||
|
||||
int gyro_to_analog_mapping;
|
||||
if (config_lookup_int(&cfg, "gyro_to_analog_mapping", &gyro_to_analog_mapping) != CONFIG_FALSE) {
|
||||
out_conf->gyro_to_analog_mapping = gyro_to_analog_mapping == 0 ? 1 : gyro_to_analog_mapping;
|
||||
} else {
|
||||
fprintf(stderr, "gyro_to_analog_mapping (int) configuration not found. Default value will be used.\n");
|
||||
}
|
||||
|
||||
config_destroy(&cfg);
|
||||
|
||||
load_out_config_err:
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
40
settings.h
40
settings.h
|
|
@ -2,22 +2,32 @@
|
|||
|
||||
#include "rogue_enemy.h"
|
||||
|
||||
typedef struct controller_settings {
|
||||
typedef struct dev_in_settings {
|
||||
bool enable_qam;
|
||||
bool rumble_on_mode_switch;
|
||||
uint16_t ff_gain;
|
||||
int enable_qam;
|
||||
int nintendo_layout;
|
||||
uint8_t m1m2_mode;
|
||||
bool touchbar;
|
||||
bool enable_thermal_profiles_switching;
|
||||
int default_thermal_profile;
|
||||
bool enable_leds_commands;
|
||||
bool enable_imu;
|
||||
bool imu_polling_interface;
|
||||
} dev_in_settings_t;
|
||||
|
||||
/**
|
||||
* 0 is virtual evdev
|
||||
* 1 is DualSense
|
||||
* 2 is DualShock
|
||||
* 3 is Xbox one
|
||||
*/
|
||||
int gamepad_output_device;
|
||||
void load_in_config(dev_in_settings_t *const out_conf, const char* const filepath);
|
||||
|
||||
int rumble_dedicated_thread;
|
||||
} controller_settings_t;
|
||||
typedef struct dev_out_settings {
|
||||
bool nintendo_layout;
|
||||
uint8_t default_gamepad;
|
||||
bool gamepad_leds_control;
|
||||
bool gamepad_rumble_control;
|
||||
bool controller_bluetooth;
|
||||
bool dualsense_edge;
|
||||
bool swap_y_z;
|
||||
bool invert_x;
|
||||
int gyro_to_analog_activation_treshold;
|
||||
int gyro_to_analog_mapping;
|
||||
} dev_out_settings_t;
|
||||
|
||||
void init_config(controller_settings_t *const conf);
|
||||
|
||||
int fill_config(controller_settings_t *const conf, const char* file);
|
||||
void load_out_config(dev_out_settings_t *const out_conf, const char* const filepath);
|
||||
71
stray_ally.c
71
stray_ally.c
|
|
@ -7,18 +7,33 @@
|
|||
#include "dev_out.h"
|
||||
#include "settings.h"
|
||||
|
||||
#include "rog_ally.h"
|
||||
#include "legion_go.h"
|
||||
#include <sys/mman.h>
|
||||
|
||||
static const char* configuration_file = "/etc/ROGueENEMY/config.cfg";
|
||||
|
||||
controller_settings_t settings;
|
||||
|
||||
int main(int argc, char ** argv) {
|
||||
// Lock all current and future pages from preventing of being paged to swap
|
||||
const int lockall_res = mlockall( MCL_CURRENT | MCL_FUTURE );
|
||||
if (lockall_res) {
|
||||
fprintf(stderr, "mlockall failed: %d", lockall_res);
|
||||
}
|
||||
|
||||
int ret = 0;
|
||||
|
||||
init_config(&settings);
|
||||
fill_config(&settings, configuration_file);
|
||||
dev_out_settings_t out_settings = {
|
||||
.default_gamepad = 0,
|
||||
.nintendo_layout = false,
|
||||
.gamepad_leds_control = true,
|
||||
.gamepad_rumble_control = true,
|
||||
.controller_bluetooth = false,
|
||||
.dualsense_edge = false,
|
||||
.swap_y_z = false,
|
||||
.invert_x = false,
|
||||
.gyro_to_analog_activation_treshold = 16,
|
||||
.gyro_to_analog_mapping = 4,
|
||||
};
|
||||
|
||||
load_out_config(&out_settings, configuration_file);
|
||||
|
||||
// Create a signal set containing only SIGTERM
|
||||
sigset_t mask;
|
||||
|
|
@ -50,11 +65,49 @@ int main(int argc, char ** argv) {
|
|||
}
|
||||
}
|
||||
},
|
||||
.gamepad = GAMEPAD_DUALSENSE,
|
||||
.settings = out_settings,
|
||||
};
|
||||
|
||||
load_out_config(&dev_out_thread_data.settings, configuration_file);
|
||||
|
||||
// Initialize pthread attributes (default values)
|
||||
struct sched_param param;
|
||||
pthread_attr_t attr;
|
||||
ret = pthread_attr_init(&attr);
|
||||
if (ret) {
|
||||
printf("init pthread attributes failed\n");
|
||||
goto main_err;
|
||||
}
|
||||
|
||||
// Set a specific stack size
|
||||
ret = pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN + 8192);
|
||||
if (ret) {
|
||||
printf("pthread setstacksize failed\n");
|
||||
goto main_err;
|
||||
}
|
||||
|
||||
// Set scheduler policy and priority of pthread
|
||||
ret = pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
|
||||
if (ret) {
|
||||
printf("pthread setschedpolicy failed\n");
|
||||
goto main_err;
|
||||
}
|
||||
param.sched_priority = 80;
|
||||
ret = pthread_attr_setschedparam(&attr, ¶m);
|
||||
if (ret) {
|
||||
printf("pthread setschedparam failed\n");
|
||||
goto main_err;
|
||||
}
|
||||
|
||||
// Use scheduling parameters of attr
|
||||
ret = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
|
||||
if (ret) {
|
||||
printf("pthread setinheritsched failed\n");
|
||||
goto main_err;
|
||||
}
|
||||
|
||||
pthread_t dev_out_thread;
|
||||
const int dev_out_thread_creation = pthread_create(&dev_out_thread, NULL, dev_out_thread_func, (void*)(&dev_out_thread_data));
|
||||
const int dev_out_thread_creation = pthread_create(&dev_out_thread, &attr, dev_out_thread_func, (void*)(&dev_out_thread_data));
|
||||
if (dev_out_thread_creation != 0) {
|
||||
fprintf(stderr, "Error creating dev_out thread: %d\n", dev_out_thread_creation);
|
||||
ret = -1;
|
||||
|
|
@ -71,7 +124,7 @@ int main(int argc, char ** argv) {
|
|||
int sd=-1;
|
||||
struct sockaddr_un serveraddr;
|
||||
do {
|
||||
sd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
|
||||
sd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (sd < 0)
|
||||
{
|
||||
fprintf(stderr, "socket() failed");
|
||||
|
|
|
|||
381
virt_ds4.c
381
virt_ds4.c
|
|
@ -1,12 +1,7 @@
|
|||
#include "virt_ds4.h"
|
||||
#include "message.h"
|
||||
|
||||
#include <bits/types/time_t.h>
|
||||
#include <linux/uhid.h>
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
#include <pthread.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define DS4_GYRO_RES_PER_DEG_S 1024
|
||||
#define DS4_ACC_RES_PER_G 8192
|
||||
|
|
@ -17,6 +12,24 @@
|
|||
#define DS4_OUTPUT_VALID_FLAG0_LED 0x02
|
||||
#define DS4_OUTPUT_VALID_FLAG0_LED_BLINK 0x04
|
||||
|
||||
#define DS4_INPUT_REPORT_USB 0x01
|
||||
#define DS4_INPUT_REPORT_USB_SIZE 64
|
||||
#define DS4_INPUT_REPORT_BT 0x11
|
||||
#define DS4_INPUT_REPORT_BT_SIZE 78
|
||||
#define DS4_OUTPUT_REPORT_USB 0x05
|
||||
#define DS4_OUTPUT_REPORT_USB_SIZE 32
|
||||
#define DS4_OUTPUT_REPORT_BT 0x11
|
||||
#define DS4_OUTPUT_REPORT_BT_SIZE 78
|
||||
|
||||
#define DS4_FEATURE_REPORT_CALIBRATION 0x02
|
||||
#define DS4_FEATURE_REPORT_CALIBRATION_SIZE 37
|
||||
#define DS4_FEATURE_REPORT_CALIBRATION_BT 0x05
|
||||
#define DS4_FEATURE_REPORT_CALIBRATION_BT_SIZE 41
|
||||
#define DS4_FEATURE_REPORT_FIRMWARE_INFO 0xa3
|
||||
#define DS4_FEATURE_REPORT_FIRMWARE_INFO_SIZE 49
|
||||
#define DS4_FEATURE_REPORT_PAIRING_INFO 0x12
|
||||
#define DS4_FEATURE_REPORT_PAIRING_INFO_SIZE 16
|
||||
|
||||
static const uint16_t gyro_pitch_bias = 0xfff9;
|
||||
static const uint16_t gyro_yaw_bias = 0x0009;
|
||||
static const uint16_t gyro_roll_bias = 0xfff9;
|
||||
|
|
@ -37,6 +50,17 @@ static const uint16_t acc_z_minus = 0xe086;
|
|||
|
||||
static const char* path = "/dev/uhid";
|
||||
|
||||
/* Seed values for DualShock4 / DualSense CRC32 for different report types. */
|
||||
static uint8_t PS_INPUT_CRC32_SEED = 0xA1;
|
||||
static uint8_t PS_OUTPUT_CRC32_SEED = 0xA2;
|
||||
static uint8_t PS_FEATURE_CRC32_SEED = 0xA3;
|
||||
|
||||
static uint32_t crc32_le(uint32_t crc_initial, const uint8_t *const buf, size_t len) {
|
||||
return crc32(crc_initial ^ 0xffffffff, buf, len) ^ 0xffffffff;
|
||||
}
|
||||
|
||||
static const uint8_t MAC_ADDR[] = { 0xf2, 0xa5, 0x71, 0x68, 0xaf, 0xdc };
|
||||
|
||||
static unsigned char rdesc[] = {
|
||||
0x05, 0x01, /* Usage Page (Desktop), */
|
||||
0x09, 0x05, /* Usage (Gamepad), */
|
||||
|
|
@ -291,6 +315,37 @@ static unsigned char rdesc[] = {
|
|||
0xC0 /* End Collection */
|
||||
};
|
||||
|
||||
static unsigned char rdesc_bt[] = {
|
||||
0x05, 0x01, 0x09, 0x05, 0xa1, 0x01, 0x85, 0x01, 0x09, 0x30, 0x09, 0x31, 0x09, 0x32, 0x09, 0x35,
|
||||
0x15, 0x00, 0x26, 0xff, 0x00, 0x75, 0x08, 0x95, 0x04, 0x81, 0x02, 0x09, 0x39, 0x15, 0x00, 0x25,
|
||||
0x07, 0x75, 0x04, 0x95, 0x01, 0x81, 0x42, 0x05, 0x09, 0x19, 0x01, 0x29, 0x0e, 0x15, 0x00, 0x25,
|
||||
0x01, 0x75, 0x01, 0x95, 0x0e, 0x81, 0x02, 0x75, 0x06, 0x95, 0x01, 0x81, 0x01, 0x05, 0x01, 0x09,
|
||||
0x33, 0x09, 0x34, 0x15, 0x00, 0x26, 0xff, 0x00, 0x75, 0x08, 0x95, 0x02, 0x81, 0x02, 0x06, 0x04,
|
||||
0xff, 0x85, 0x02, 0x09, 0x24, 0x95, 0x24, 0xb1, 0x02, 0x85, 0xa3, 0x09, 0x25, 0x95, 0x30, 0xb1,
|
||||
0x02, 0x85, 0x05, 0x09, 0x26, 0x95, 0x28, 0xb1, 0x02, 0x85, 0x06, 0x09, 0x27, 0x95, 0x34, 0xb1,
|
||||
0x02, 0x85, 0x07, 0x09, 0x28, 0x95, 0x30, 0xb1, 0x02, 0x85, 0x08, 0x09, 0x29, 0x95, 0x2f, 0xb1,
|
||||
0x02, 0x85, 0x09, 0x09, 0x2a, 0x95, 0x13, 0xb1, 0x02, 0x06, 0x03, 0xff, 0x85, 0x03, 0x09, 0x21,
|
||||
0x95, 0x26, 0xb1, 0x02, 0x85, 0x04, 0x09, 0x22, 0x95, 0x2e, 0xb1, 0x02, 0x85, 0xf0, 0x09, 0x47,
|
||||
0x95, 0x3f, 0xb1, 0x02, 0x85, 0xf1, 0x09, 0x48, 0x95, 0x3f, 0xb1, 0x02, 0x85, 0xf2, 0x09, 0x49,
|
||||
0x95, 0x0f, 0xb1, 0x02, 0x06, 0x00, 0xff, 0x85, 0x11, 0x09, 0x20, 0x15, 0x00, 0x26, 0xff, 0x00,
|
||||
0x75, 0x08, 0x95, 0x4d, 0x81, 0x02, 0x09, 0x21, 0x91, 0x02, 0x85, 0x12, 0x09, 0x22, 0x95, 0x8d,
|
||||
0x81, 0x02, 0x09, 0x23, 0x91, 0x02, 0x85, 0x13, 0x09, 0x24, 0x95, 0xcd, 0x81, 0x02, 0x09, 0x25,
|
||||
0x91, 0x02, 0x85, 0x14, 0x09, 0x26, 0x96, 0x0d, 0x01, 0x81, 0x02, 0x09, 0x27, 0x91, 0x02, 0x85,
|
||||
0x15, 0x09, 0x28, 0x96, 0x4d, 0x01, 0x81, 0x02, 0x09, 0x29, 0x91, 0x02, 0x85, 0x16, 0x09, 0x2a,
|
||||
0x96, 0x8d, 0x01, 0x81, 0x02, 0x09, 0x2b, 0x91, 0x02, 0x85, 0x17, 0x09, 0x2c, 0x96, 0xcd, 0x01,
|
||||
0x81, 0x02, 0x09, 0x2d, 0x91, 0x02, 0x85, 0x18, 0x09, 0x2e, 0x96, 0x0d, 0x02, 0x81, 0x02, 0x09,
|
||||
0x2f, 0x91, 0x02, 0x85, 0x19, 0x09, 0x30, 0x96, 0x22, 0x02, 0x81, 0x02, 0x09, 0x31, 0x91, 0x02,
|
||||
0x06, 0x80, 0xff, 0x85, 0x82, 0x09, 0x22, 0x95, 0x3f, 0xb1, 0x02, 0x85, 0x83, 0x09, 0x23, 0xb1,
|
||||
0x02, 0x85, 0x84, 0x09, 0x24, 0xb1, 0x02, 0x85, 0x90, 0x09, 0x30, 0xb1, 0x02, 0x85, 0x91, 0x09,
|
||||
0x31, 0xb1, 0x02, 0x85, 0x92, 0x09, 0x32, 0xb1, 0x02, 0x85, 0x93, 0x09, 0x33, 0xb1, 0x02, 0x85,
|
||||
0x94, 0x09, 0x34, 0xb1, 0x02, 0x85, 0xa0, 0x09, 0x40, 0xb1, 0x02, 0x85, 0xa4, 0x09, 0x44, 0xb1,
|
||||
0x02, 0x85, 0xa7, 0x09, 0x45, 0xb1, 0x02, 0x85, 0xa8, 0x09, 0x45, 0xb1, 0x02, 0x85, 0xa9, 0x09,
|
||||
0x45, 0xb1, 0x02, 0x85, 0xaa, 0x09, 0x45, 0xb1, 0x02, 0x85, 0xab, 0x09, 0x45, 0xb1, 0x02, 0x85,
|
||||
0xac, 0x09, 0x45, 0xb1, 0x02, 0x85, 0xad, 0x09, 0x45, 0xb1, 0x02, 0x85, 0xb3, 0x09, 0x45, 0xb1,
|
||||
0x02, 0x85, 0xb4, 0x09, 0x46, 0xb1, 0x02, 0x85, 0xb5, 0x09, 0x47, 0xb1, 0x02, 0x85, 0xd0, 0x09,
|
||||
0x40, 0xb1, 0x02, 0x85, 0xd4, 0x09, 0x44, 0xb1, 0x02, 0xc0, 0x00
|
||||
};
|
||||
|
||||
static int uhid_write(int fd, const struct uhid_event *ev)
|
||||
{
|
||||
ssize_t ret;
|
||||
|
|
@ -308,21 +363,25 @@ static int uhid_write(int fd, const struct uhid_event *ev)
|
|||
}
|
||||
}
|
||||
|
||||
static int create(int fd)
|
||||
static int create(int fd, bool bluetooth)
|
||||
{
|
||||
struct uhid_event ev;
|
||||
|
||||
memset(&ev, 0, sizeof(ev));
|
||||
ev.type = UHID_CREATE;
|
||||
strcpy((char*)ev.u.create.name, "Sony Corp. DualShock 4 [CUH-ZCT2x]");
|
||||
ev.u.create.rd_data = rdesc;
|
||||
ev.u.create.rd_size = sizeof(rdesc);
|
||||
ev.u.create.bus = BUS_USB;
|
||||
ev.u.create.rd_data = bluetooth ? rdesc_bt : rdesc;
|
||||
ev.u.create.rd_size = bluetooth ? sizeof(rdesc_bt) : sizeof(rdesc);
|
||||
ev.u.create.bus = bluetooth ? BUS_BLUETOOTH : BUS_USB;
|
||||
ev.u.create.vendor = 0x054C;
|
||||
ev.u.create.product = 0x09CC;
|
||||
ev.u.create.version = 0;
|
||||
ev.u.create.country = 0;
|
||||
|
||||
sprintf((char*)ev.u.create.uniq, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
|
||||
MAC_ADDR[5], MAC_ADDR[4], MAC_ADDR[3], MAC_ADDR[2], MAC_ADDR[1], MAC_ADDR[0]
|
||||
);
|
||||
|
||||
return uhid_write(fd, &ev);
|
||||
}
|
||||
|
||||
|
|
@ -370,15 +429,23 @@ static ds4_dpad_status_t ds4_dpad_from_gamepad(uint8_t dpad) {
|
|||
return DPAD_RELEASED;
|
||||
}
|
||||
|
||||
int virt_dualshock_init(virt_dualshock_t *const out_gamepad) {
|
||||
int virt_dualshock_init(
|
||||
virt_dualshock_t *const out_gamepad,
|
||||
bool bluetooth,
|
||||
int64_t gyro_to_analog_activation_treshold,
|
||||
int64_t gyro_to_analog_mapping
|
||||
) {
|
||||
int ret = 0;
|
||||
|
||||
out_gamepad->gyro_to_analog_activation_treshold = absolute_value(gyro_to_analog_activation_treshold);
|
||||
out_gamepad->gyro_to_analog_mapping = gyro_to_analog_mapping;
|
||||
out_gamepad->dt_sum = 0;
|
||||
out_gamepad->dt_buffer_current = 0;
|
||||
memset(out_gamepad->dt_buffer, 0, sizeof(out_gamepad->dt_buffer));
|
||||
out_gamepad->debug = false;
|
||||
out_gamepad->empty_reports = 0;
|
||||
out_gamepad->last_time = 0;
|
||||
out_gamepad->bluetooth = bluetooth;
|
||||
|
||||
out_gamepad->fd = open(path, O_RDWR | O_CLOEXEC /* | O_NONBLOCK */);
|
||||
if (out_gamepad->fd < 0) {
|
||||
|
|
@ -387,7 +454,7 @@ int virt_dualshock_init(virt_dualshock_t *const out_gamepad) {
|
|||
goto virt_dualshock_init_err;
|
||||
}
|
||||
|
||||
ret = create(out_gamepad->fd);
|
||||
ret = create(out_gamepad->fd, out_gamepad->bluetooth);
|
||||
if (ret) {
|
||||
fprintf(stderr, "Error creating uhid device: %d\n", ret);
|
||||
close(out_gamepad->fd);
|
||||
|
|
@ -452,57 +519,57 @@ int virt_dualshock_event(virt_dualshock_t *const gamepad, gamepad_status_t *cons
|
|||
if (ev.u.output.rtype != UHID_OUTPUT_REPORT)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
if (ds4->update_rumble) {
|
||||
* Select classic rumble style haptics and enable it. *
|
||||
common->valid_flag0 |= DS4_OUTPUT_VALID_FLAG0_MOTOR;
|
||||
common->motor_left = ds4->motor_left;
|
||||
common->motor_right = ds4->motor_right;
|
||||
ds4->update_rumble = false;
|
||||
}
|
||||
|
||||
if (ds4->update_lightbar) {
|
||||
common->valid_flag0 |= DS4_OUTPUT_VALID_FLAG0_LED;
|
||||
* Comptabile behavior with hid-sony, which used a dummy global LED to
|
||||
* allow enabling/disabling the lightbar. The global LED maps to
|
||||
* lightbar_enabled.
|
||||
*
|
||||
common->lightbar_red = ds4->lightbar_enabled ? ds4->lightbar_red : 0;
|
||||
common->lightbar_green = ds4->lightbar_enabled ? ds4->lightbar_green : 0;
|
||||
common->lightbar_blue = ds4->lightbar_enabled ? ds4->lightbar_blue : 0;
|
||||
ds4->update_lightbar = false;
|
||||
}
|
||||
|
||||
if (ds4->update_lightbar_blink) {
|
||||
common->valid_flag0 |= DS4_OUTPUT_VALID_FLAG0_LED_BLINK;
|
||||
common->lightbar_blink_on = ds4->lightbar_blink_on;
|
||||
common->lightbar_blink_off = ds4->lightbar_blink_off;
|
||||
ds4->update_lightbar_blink = false;
|
||||
}
|
||||
*/
|
||||
|
||||
if (ev.u.output.size != 32) {
|
||||
fprintf(stderr, "Invalid data length: got %d, expected 32\n", (int)ev.u.output.size);
|
||||
if (
|
||||
(!gamepad->bluetooth) && (ev.u.output.size != DS4_OUTPUT_REPORT_USB_SIZE) &&
|
||||
(gamepad->bluetooth) && (ev.u.output.size != DS4_OUTPUT_REPORT_BT_SIZE)
|
||||
) {
|
||||
fprintf(
|
||||
stderr,
|
||||
"Invalid data length: got %d, expected %d\n",
|
||||
(int)ev.u.output.size,
|
||||
(gamepad->bluetooth) ? DS4_OUTPUT_REPORT_BT_SIZE : DS4_OUTPUT_REPORT_USB_SIZE
|
||||
);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// first byte is report-id which is 0x01
|
||||
if (ev.u.output.data[0] != 0x05) {
|
||||
fprintf(stderr, "Unrecognised report-id: %d\n", (int)ev.u.output.data[0]);
|
||||
if (
|
||||
(!gamepad->bluetooth) && (ev.u.output.data[0] != DS4_OUTPUT_REPORT_USB) &&
|
||||
(gamepad->bluetooth) && ((ev.u.output.data[0] != DS4_OUTPUT_REPORT_BT) && (ev.u.output.data[0] < 0x10))
|
||||
) {
|
||||
fprintf(
|
||||
stderr,
|
||||
"Unrecognised report-id: got 0x%x expected 0x%x\n",
|
||||
(int)ev.u.output.data[0],
|
||||
(gamepad->bluetooth) ? DS4_OUTPUT_REPORT_BT : DS4_OUTPUT_REPORT_USB
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const uint8_t valid_flag0 = ev.u.output.data[1];
|
||||
const uint8_t valid_flag1 = ev.u.output.data[2];
|
||||
const uint8_t reserved = ev.u.output.data[3];
|
||||
const uint8_t motor_right = ev.u.output.data[4];
|
||||
const uint8_t motor_left = ev.u.output.data[5];
|
||||
const uint8_t lightbar_red = ev.u.output.data[6];
|
||||
const uint8_t lightbar_green = ev.u.output.data[7];
|
||||
const uint8_t lightbar_blue = ev.u.output.data[8];
|
||||
const uint8_t lightbar_blink_on = ev.u.output.data[9];
|
||||
const uint8_t lightbar_blink_off = ev.u.output.data[10];
|
||||
// When using bluetooth, the first byte after the reportID is uint8_t seq_tag,
|
||||
// while the next one is uint8_t tag, following bytes are the same.
|
||||
size_t offset = 1;
|
||||
if ((gamepad->bluetooth) && (ev.u.output.data[0] > 0x10)) {
|
||||
offset = 2;
|
||||
} else if ((gamepad->bluetooth) && (ev.u.output.data[0] == 0x02)) {
|
||||
offset = 3;
|
||||
} else if ((gamepad->bluetooth) && (ev.u.output.data[0] == 0x01)) {
|
||||
offset = 1;
|
||||
}
|
||||
|
||||
const uint8_t *const common_report = &ev.u.output.data[offset];
|
||||
|
||||
const uint8_t valid_flag0 = common_report[0];
|
||||
const uint8_t valid_flag1 = common_report[1];
|
||||
const uint8_t reserved = common_report[2];
|
||||
const uint8_t motor_right = common_report[3];
|
||||
const uint8_t motor_left = common_report[4];
|
||||
const uint8_t lightbar_red = common_report[5];
|
||||
const uint8_t lightbar_green = common_report[6];
|
||||
const uint8_t lightbar_blue = common_report[7];
|
||||
const uint8_t lightbar_blink_on = common_report[8];
|
||||
const uint8_t lightbar_blink_off = common_report[9];
|
||||
|
||||
if ((valid_flag0 & DS4_OUTPUT_VALID_FLAG0_LED)) {
|
||||
out_device_status->leds_colors[0] = lightbar_red;
|
||||
|
|
@ -543,32 +610,40 @@ int virt_dualshock_event(virt_dualshock_t *const gamepad, gamepad_status_t *cons
|
|||
}
|
||||
|
||||
if (ev.u.get_report.rnum == 18) {
|
||||
const struct uhid_event mac_addr_response = {
|
||||
struct uhid_event mac_addr_response = {
|
||||
.type = UHID_GET_REPORT_REPLY,
|
||||
.u = {
|
||||
.get_report_reply = {
|
||||
.size = 16,
|
||||
.size = DS4_FEATURE_REPORT_PAIRING_INFO_SIZE,
|
||||
.id = ev.u.get_report.id,
|
||||
.err = 0,
|
||||
.data = {
|
||||
0x12, 0xf2, 0xa5, 0x71, 0x68, 0xaf, 0xdc, 0x08,
|
||||
DS4_FEATURE_REPORT_PAIRING_INFO,
|
||||
MAC_ADDR[0], MAC_ADDR[1], MAC_ADDR[2], MAC_ADDR[3], MAC_ADDR[4], MAC_ADDR[5],
|
||||
0x08,
|
||||
0x25, 0x00, 0x4c, 0x46, 0x49, 0x0e, 0x41, 0x00
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (gamepad->bluetooth) {
|
||||
uint32_t crc = crc32_le(0xFFFFFFFFU, (const uint8_t*)&PS_FEATURE_CRC32_SEED, sizeof(PS_FEATURE_CRC32_SEED));
|
||||
crc = ~crc32_le(crc, (const Bytef *)&mac_addr_response.u.get_report_reply.data[0], mac_addr_response.u.get_report_reply.size - 4);
|
||||
memcpy(&mac_addr_response.u.get_report_reply.data[mac_addr_response.u.get_report_reply.size - sizeof(crc)], &crc, sizeof(crc));
|
||||
}
|
||||
|
||||
uhid_write(gamepad->fd, &mac_addr_response);
|
||||
} else if (ev.u.get_report.rnum == 0xa3) {
|
||||
const struct uhid_event firmware_info_response = {
|
||||
} else if (ev.u.get_report.rnum == DS4_FEATURE_REPORT_FIRMWARE_INFO) {
|
||||
struct uhid_event firmware_info_response = {
|
||||
.type = UHID_GET_REPORT_REPLY,
|
||||
.u = {
|
||||
.get_report_reply = {
|
||||
.size = 49,
|
||||
.size = DS4_FEATURE_REPORT_FIRMWARE_INFO_SIZE,
|
||||
.id = ev.u.get_report.id,
|
||||
.err = 0,
|
||||
.data = {
|
||||
0xa3, 0x53, 0x65, 0x70, 0x20, 0x32, 0x31, 0x20,
|
||||
DS4_FEATURE_REPORT_FIRMWARE_INFO, 0x53, 0x65, 0x70, 0x20, 0x32, 0x31, 0x20,
|
||||
0x32, 0x30, 0x31, 0x38, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x30, 0x34, 0x3a, 0x35, 0x30, 0x3a, 0x35,
|
||||
0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
|
@ -580,22 +655,32 @@ int virt_dualshock_event(virt_dualshock_t *const gamepad, gamepad_status_t *cons
|
|||
}
|
||||
};
|
||||
|
||||
if (gamepad->bluetooth) {
|
||||
uint32_t crc = crc32_le(0xFFFFFFFFU, (const uint8_t*)&PS_FEATURE_CRC32_SEED, sizeof(PS_FEATURE_CRC32_SEED));
|
||||
crc = ~crc32_le(crc, (const Bytef *)&firmware_info_response.u.get_report_reply.data[0], firmware_info_response.u.get_report_reply.size - 4);
|
||||
memcpy(&firmware_info_response.u.get_report_reply.data[firmware_info_response.u.get_report_reply.size - sizeof(crc)], &crc, sizeof(crc));
|
||||
}
|
||||
|
||||
uhid_write(gamepad->fd, &firmware_info_response);
|
||||
} else if (ev.u.get_report.rnum == 0x02) { // dualshock4_get_calibration_data
|
||||
struct uhid_event firmware_info_response = {
|
||||
} else if (
|
||||
((gamepad->bluetooth) && (ev.u.get_report.rnum == DS4_FEATURE_REPORT_CALIBRATION_BT)) ||
|
||||
((!gamepad->bluetooth) && (ev.u.get_report.rnum == DS4_FEATURE_REPORT_CALIBRATION))
|
||||
) { // dualshock4_get_calibration_data
|
||||
struct uhid_event calibration_response = {
|
||||
.type = UHID_GET_REPORT_REPLY,
|
||||
.u = {
|
||||
.get_report_reply = {
|
||||
.size = 37,
|
||||
.size = gamepad->bluetooth ? DS4_FEATURE_REPORT_CALIBRATION_BT_SIZE : DS4_FEATURE_REPORT_CALIBRATION_SIZE,
|
||||
.id = ev.u.get_report.id,
|
||||
.err = 0,
|
||||
.data = {
|
||||
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
gamepad->bluetooth ? DS4_FEATURE_REPORT_CALIBRATION_BT : DS4_FEATURE_REPORT_CALIBRATION,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x06, 0x00,
|
||||
|
||||
0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -605,25 +690,31 @@ int virt_dualshock_event(virt_dualshock_t *const gamepad, gamepad_status_t *cons
|
|||
// speed_2x = speed_2x*DS4_GYRO_RES_PER_DEG_S; calculated by the kernel will be 1080.
|
||||
// As a consequence sens_numer (for every axis) is 1080*1024.
|
||||
// that number will be 1105920
|
||||
memcpy((void*)&firmware_info_response.u.get_report_reply.data[1], (const void*)&gyro_pitch_bias, sizeof(int16_t));
|
||||
memcpy((void*)&firmware_info_response.u.get_report_reply.data[3], (const void*)&gyro_yaw_bias, sizeof(int16_t));
|
||||
memcpy((void*)&firmware_info_response.u.get_report_reply.data[5], (const void*)&gyro_roll_bias, sizeof(int16_t));
|
||||
memcpy((void*)&firmware_info_response.u.get_report_reply.data[7], (const void*)&gyro_pitch_plus, sizeof(int16_t));
|
||||
memcpy((void*)&firmware_info_response.u.get_report_reply.data[9], (const void*)&gyro_pitch_minus, sizeof(int16_t));
|
||||
memcpy((void*)&firmware_info_response.u.get_report_reply.data[11], (const void*)&gyro_yaw_plus, sizeof(int16_t));
|
||||
memcpy((void*)&firmware_info_response.u.get_report_reply.data[13], (const void*)&gyro_yaw_minus, sizeof(int16_t));
|
||||
memcpy((void*)&firmware_info_response.u.get_report_reply.data[15], (const void*)&gyro_roll_plus, sizeof(int16_t));
|
||||
memcpy((void*)&firmware_info_response.u.get_report_reply.data[17], (const void*)&gyro_roll_minus, sizeof(int16_t));
|
||||
memcpy((void*)&firmware_info_response.u.get_report_reply.data[19], (const void*)&gyro_speed_plus, sizeof(int16_t));
|
||||
memcpy((void*)&firmware_info_response.u.get_report_reply.data[21], (const void*)&gyro_speed_minus, sizeof(int16_t));
|
||||
memcpy((void*)&firmware_info_response.u.get_report_reply.data[23], (const void*)&acc_x_plus, sizeof(int16_t));
|
||||
memcpy((void*)&firmware_info_response.u.get_report_reply.data[25], (const void*)&acc_x_minus, sizeof(int16_t));
|
||||
memcpy((void*)&firmware_info_response.u.get_report_reply.data[27], (const void*)&acc_y_plus, sizeof(int16_t));
|
||||
memcpy((void*)&firmware_info_response.u.get_report_reply.data[29], (const void*)&acc_y_minus, sizeof(int16_t));
|
||||
memcpy((void*)&firmware_info_response.u.get_report_reply.data[31], (const void*)&acc_z_plus, sizeof(int16_t));
|
||||
memcpy((void*)&firmware_info_response.u.get_report_reply.data[33], (const void*)&acc_z_minus, sizeof(int16_t));
|
||||
memcpy((void*)&calibration_response.u.get_report_reply.data[1], (const void*)&gyro_pitch_bias, sizeof(int16_t));
|
||||
memcpy((void*)&calibration_response.u.get_report_reply.data[3], (const void*)&gyro_yaw_bias, sizeof(int16_t));
|
||||
memcpy((void*)&calibration_response.u.get_report_reply.data[5], (const void*)&gyro_roll_bias, sizeof(int16_t));
|
||||
memcpy((void*)&calibration_response.u.get_report_reply.data[7], (const void*)&gyro_pitch_plus, sizeof(int16_t));
|
||||
memcpy((void*)&calibration_response.u.get_report_reply.data[9], (const void*)&gyro_pitch_minus, sizeof(int16_t));
|
||||
memcpy((void*)&calibration_response.u.get_report_reply.data[11], (const void*)&gyro_yaw_plus, sizeof(int16_t));
|
||||
memcpy((void*)&calibration_response.u.get_report_reply.data[13], (const void*)&gyro_yaw_minus, sizeof(int16_t));
|
||||
memcpy((void*)&calibration_response.u.get_report_reply.data[15], (const void*)&gyro_roll_plus, sizeof(int16_t));
|
||||
memcpy((void*)&calibration_response.u.get_report_reply.data[17], (const void*)&gyro_roll_minus, sizeof(int16_t));
|
||||
memcpy((void*)&calibration_response.u.get_report_reply.data[19], (const void*)&gyro_speed_plus, sizeof(int16_t));
|
||||
memcpy((void*)&calibration_response.u.get_report_reply.data[21], (const void*)&gyro_speed_minus, sizeof(int16_t));
|
||||
memcpy((void*)&calibration_response.u.get_report_reply.data[23], (const void*)&acc_x_plus, sizeof(int16_t));
|
||||
memcpy((void*)&calibration_response.u.get_report_reply.data[25], (const void*)&acc_x_minus, sizeof(int16_t));
|
||||
memcpy((void*)&calibration_response.u.get_report_reply.data[27], (const void*)&acc_y_plus, sizeof(int16_t));
|
||||
memcpy((void*)&calibration_response.u.get_report_reply.data[29], (const void*)&acc_y_minus, sizeof(int16_t));
|
||||
memcpy((void*)&calibration_response.u.get_report_reply.data[31], (const void*)&acc_z_plus, sizeof(int16_t));
|
||||
memcpy((void*)&calibration_response.u.get_report_reply.data[33], (const void*)&acc_z_minus, sizeof(int16_t));
|
||||
|
||||
uhid_write(gamepad->fd, &firmware_info_response);
|
||||
if (gamepad->bluetooth) {
|
||||
uint32_t crc = crc32_le(0xFFFFFFFFU, (const uint8_t*)&PS_FEATURE_CRC32_SEED, sizeof(PS_FEATURE_CRC32_SEED));
|
||||
crc = ~crc32_le(crc, (const Bytef *)&calibration_response.u.get_report_reply.data[0], calibration_response.u.get_report_reply.size - 4);
|
||||
memcpy(&calibration_response.u.get_report_reply.data[calibration_response.u.get_report_reply.size - sizeof(crc)], &crc, sizeof(crc));
|
||||
}
|
||||
|
||||
uhid_write(gamepad->fd, &calibration_response);
|
||||
}
|
||||
|
||||
break;
|
||||
|
|
@ -642,9 +733,9 @@ void virt_dualshock_close(virt_dualshock_t *const out_gamepad) {
|
|||
* This function arranges HID packets as described on https://www.psdevwiki.com/ps4/DS4-USB
|
||||
*/
|
||||
void virt_dualshock_compose(virt_dualshock_t *const gamepad, gamepad_status_t *const in_device_status, uint8_t *const out_buf) {
|
||||
const int64_t time_us = in_device_status->last_gyro_motion_time.tv_sec * 1000000 + in_device_status->last_gyro_motion_time.tv_usec;
|
||||
const int64_t time_us = in_device_status->last_gyro_motion_timestamp_ns / (int64_t)1000;
|
||||
|
||||
const int delta_time = time_us - gamepad->last_time;
|
||||
const int64_t delta_time = time_us - gamepad->last_time;
|
||||
gamepad->last_time = time_us;
|
||||
|
||||
// find the average Δt in the last 30 non-zero inputs;
|
||||
|
|
@ -695,78 +786,82 @@ void virt_dualshock_compose(virt_dualshock_t *const gamepad, gamepad_status_t *c
|
|||
*
|
||||
* as we know sens_numer is 0, hence calib_data is zero.
|
||||
*/
|
||||
/*
|
||||
const int16_t g_x = ((in_device_status->gyro[0]) * ((double)(180.0)/(double)(M_PI))) / (double)DS4_GYRO_RES_PER_DEG_S;
|
||||
const int16_t g_y = ((in_device_status->gyro[1]) * ((double)(180.0)/(double)(M_PI))) / (double)DS4_GYRO_RES_PER_DEG_S;
|
||||
const int16_t g_z = ((in_device_status->gyro[2]) * ((double)(180.0)/(double)(M_PI))) / (double)DS4_GYRO_RES_PER_DEG_S;
|
||||
const int16_t a_x = ((in_device_status->accel[0]) / ((double)9.8)) / (double)DS4_ACC_RES_PER_G; // TODO: IDK how to test...
|
||||
const int16_t a_y = ((in_device_status->accel[1]) / ((double)9.8)) / (double)DS4_ACC_RES_PER_G; // TODO: IDK how to test...
|
||||
const int16_t a_z = ((in_device_status->accel[2]) / ((double)9.8)) / (double)DS4_ACC_RES_PER_G; // TODO: IDK how to test...
|
||||
*/
|
||||
|
||||
/*
|
||||
const int16_t g_x = (in_device_status->gyro[0]) / LSB_PER_RAD_S_2000_DEG_S;
|
||||
const int16_t g_y = (in_device_status->gyro[1]) / LSB_PER_RAD_S_2000_DEG_S;
|
||||
const int16_t g_z = (in_device_status->gyro[2]) / LSB_PER_RAD_S_2000_DEG_S;
|
||||
const int16_t a_x = (in_device_status->accel[0]) / LSB_PER_16G; // TODO: IDK how to test...
|
||||
const int16_t a_y = (in_device_status->accel[1]) / LSB_PER_16G; // TODO: IDK how to test...
|
||||
const int16_t a_z = (in_device_status->accel[2]) / LSB_PER_16G; // TODO: IDK how to test...
|
||||
*/
|
||||
|
||||
const int16_t g_x = in_device_status->raw_gyro[0];
|
||||
const int16_t g_y = (int16_t)(-1) * in_device_status->raw_gyro[1]; // Swap Y and Z
|
||||
const int16_t g_z = (int16_t)(-1) * in_device_status->raw_gyro[2]; // Swap Y and Z
|
||||
const int16_t g_y = in_device_status->raw_gyro[1];
|
||||
const int16_t g_z = in_device_status->raw_gyro[2];
|
||||
const int16_t a_x = in_device_status->raw_accel[0];
|
||||
const int16_t a_y = (int16_t)(-1) * in_device_status->raw_accel[1]; // Swap Y and Z
|
||||
const int16_t a_z = (int16_t)(-1) * in_device_status->raw_accel[2]; // Swap Y and Z
|
||||
const int16_t a_y = in_device_status->raw_accel[1];
|
||||
const int16_t a_z = in_device_status->raw_accel[2];
|
||||
|
||||
out_buf[0] = 0x01; // [00] report ID (0x01)
|
||||
out_buf[1] = ((uint64_t)((int64_t)in_device_status->joystick_positions[0][0] + (int64_t)32768) >> (uint64_t)8); // L stick, X axis
|
||||
out_buf[2] = ((uint64_t)((int64_t)in_device_status->joystick_positions[0][1] + (int64_t)32768) >> (uint64_t)8); // L stick, Y axis
|
||||
out_buf[3] = ((uint64_t)((int64_t)in_device_status->joystick_positions[1][0] + (int64_t)32768) >> (uint64_t)8); // R stick, X axis
|
||||
out_buf[4] = ((uint64_t)((int64_t)in_device_status->joystick_positions[1][1] + (int64_t)32768) >> (uint64_t)8); // R stick, Y axis
|
||||
out_buf[5] =
|
||||
const int64_t contrib_x = ((int64_t)g_y / (int64_t)gamepad->gyro_to_analog_mapping);
|
||||
const int64_t contrib_y = ((int64_t)g_x / (int64_t)gamepad->gyro_to_analog_mapping);
|
||||
|
||||
out_buf[0] = gamepad->bluetooth ? DS4_INPUT_REPORT_BT : DS4_INPUT_REPORT_USB; // [00] report ID (0x01)
|
||||
|
||||
uint8_t *const out_shifted_buf = gamepad->bluetooth ? &out_buf[2] : &out_buf[0];
|
||||
|
||||
out_shifted_buf[1] = ((uint64_t)((int64_t)in_device_status->joystick_positions[0][0] + (int64_t)32768) >> (uint64_t)8); // L stick, X axis
|
||||
out_shifted_buf[2] = ((uint64_t)((int64_t)in_device_status->joystick_positions[0][1] + (int64_t)32768) >> (uint64_t)8); // L stick, Y axis
|
||||
out_shifted_buf[3] = ((uint64_t)((int64_t)in_device_status->joystick_positions[1][0] + (int64_t)32768) >> (uint64_t)8); // R stick, X axis
|
||||
out_shifted_buf[4] = ((uint64_t)((int64_t)in_device_status->joystick_positions[1][1] + (int64_t)32768) >> (uint64_t)8); // R stick, Y axis
|
||||
out_shifted_buf[5] =
|
||||
(in_device_status->triangle ? 0x80 : 0x00) |
|
||||
(in_device_status->circle ? 0x40 : 0x00) |
|
||||
(in_device_status->cross ? 0x20 : 0x00) |
|
||||
(in_device_status->square ? 0x10 : 0x00) |
|
||||
(uint8_t)ds4_dpad_from_gamepad(in_device_status->dpad);
|
||||
out_buf[6] =
|
||||
out_shifted_buf[6] =
|
||||
(in_device_status->r3 ? 0x80 : 0x00) |
|
||||
(in_device_status->l3 ? 0x40 : 0x00) |
|
||||
(in_device_status->share ? 0x20 : 0x00) |
|
||||
(in_device_status->option ? 0x10 : 0x00) |
|
||||
(in_device_status->r2_trigger > 200 ? 0x08 : 0x00) |
|
||||
(in_device_status->l2_trigger > 200 ? 0x04 : 0x00) |
|
||||
/*(in_device_status->r2_trigger > 200 ? 0x08 : 0x00)*/ 0x00 |
|
||||
/*(in_device_status->l2_trigger > 200 ? 0x04 : 0x00)*/ 0x00 |
|
||||
(in_device_status->r1 ? 0x02 : 0x00) |
|
||||
(in_device_status->l1 ? 0x01 : 0x00);
|
||||
|
||||
/*
|
||||
static uint8_t counter = 0;
|
||||
buf[7] = (((counter++) % (uint8_t)64) << ((uint8_t)2)) | get_buttons_byte3_by_gs(&gs);
|
||||
*/
|
||||
if (in_device_status->join_left_analog_and_gyroscope) {
|
||||
if (absolute_value(contrib_x) > gamepad->gyro_to_analog_activation_treshold) {
|
||||
out_shifted_buf[1] = min_max_clamp((int64_t)127 + (((int64_t)out_shifted_buf[1] - (int64_t)127) + contrib_x), 0, 255);
|
||||
}
|
||||
|
||||
if (absolute_value(contrib_y) >= gamepad->gyro_to_analog_activation_treshold) {
|
||||
out_shifted_buf[2] = min_max_clamp((int64_t)127 + (((int64_t)out_shifted_buf[2] - (int64_t)127) + contrib_y), 0, 255);
|
||||
}
|
||||
}
|
||||
|
||||
if (in_device_status->join_right_analog_and_gyroscope) {
|
||||
if (absolute_value(contrib_x) >= gamepad->gyro_to_analog_activation_treshold) {
|
||||
out_shifted_buf[3] = min_max_clamp((int64_t)127 + (((int64_t)out_shifted_buf[3] - (int64_t)127) + contrib_x), 0, 255);
|
||||
}
|
||||
|
||||
if (absolute_value(contrib_y) >= gamepad->gyro_to_analog_activation_treshold) {
|
||||
out_shifted_buf[4] = min_max_clamp((int64_t)127 + (((int64_t)out_shifted_buf[4] - (int64_t)127) + contrib_y), 0, 255);
|
||||
}
|
||||
}
|
||||
|
||||
out_buf[7] = in_device_status->center ? 0x01 : 0x00;
|
||||
out_shifted_buf[7] = in_device_status->center ? 0x01 : 0x00;
|
||||
|
||||
out_buf[8] = in_device_status->l2_trigger;
|
||||
out_buf[9] = in_device_status->r2_trigger;
|
||||
memcpy(&out_buf[10], ×tamp, sizeof(timestamp));
|
||||
out_buf[12] = 0x20; // [12] battery level | this is called sensor_temparature in the kernel driver but is never used...
|
||||
memcpy(&out_buf[13], &g_x, sizeof(int16_t));
|
||||
memcpy(&out_buf[15], &g_y, sizeof(int16_t));
|
||||
memcpy(&out_buf[17], &g_z, sizeof(int16_t));
|
||||
memcpy(&out_buf[19], &a_x, sizeof(int16_t));
|
||||
memcpy(&out_buf[21], &a_y, sizeof(int16_t));
|
||||
memcpy(&out_buf[23], &a_z, sizeof(int16_t));
|
||||
out_shifted_buf[8] = in_device_status->l2_trigger;
|
||||
out_shifted_buf[9] = in_device_status->r2_trigger;
|
||||
memcpy(&out_shifted_buf[10], ×tamp, sizeof(timestamp));
|
||||
out_shifted_buf[12] = 0x20; // [12] battery level | this is called sensor_temparature in the kernel driver but is never used...
|
||||
memcpy(&out_shifted_buf[13], &g_x, sizeof(int16_t));
|
||||
memcpy(&out_shifted_buf[15], &g_y, sizeof(int16_t));
|
||||
memcpy(&out_shifted_buf[17], &g_z, sizeof(int16_t));
|
||||
memcpy(&out_shifted_buf[19], &a_x, sizeof(int16_t));
|
||||
memcpy(&out_shifted_buf[21], &a_y, sizeof(int16_t));
|
||||
memcpy(&out_shifted_buf[23], &a_z, sizeof(int16_t));
|
||||
|
||||
out_buf[30] = 0x1b; // no headset attached
|
||||
out_shifted_buf[30] = 0x1b; // no headset attached
|
||||
|
||||
out_buf[62] = 0x80; // IDK... it seems constant...
|
||||
out_buf[57] = 0x80; // IDK... it seems constant...
|
||||
out_buf[53] = 0x80; // IDK... it seems constant...
|
||||
out_buf[48] = 0x80; // IDK... it seems constant...
|
||||
out_buf[35] = 0x80; // IDK... it seems constant...
|
||||
out_buf[44] = 0x80; // IDK... it seems constant...
|
||||
out_shifted_buf[62] = 0x80; // IDK... it seems constant...
|
||||
out_shifted_buf[57] = 0x80; // IDK... it seems constant...
|
||||
out_shifted_buf[53] = 0x80; // IDK... it seems constant...
|
||||
out_shifted_buf[48] = 0x80; // IDK... it seems constant...
|
||||
out_shifted_buf[35] = 0x80; // IDK... it seems constant...
|
||||
out_shifted_buf[44] = 0x80; // IDK... it seems constant...
|
||||
}
|
||||
|
||||
int virt_dualshock_send(virt_dualshock_t *const gamepad, uint8_t *const out_buf) {
|
||||
|
|
@ -774,12 +869,18 @@ int virt_dualshock_send(virt_dualshock_t *const gamepad, uint8_t *const out_buf)
|
|||
.type = UHID_INPUT2,
|
||||
.u = {
|
||||
.input2 = {
|
||||
.size = 64,
|
||||
.size = gamepad->bluetooth ? DS4_INPUT_REPORT_BT_SIZE : DS4_INPUT_REPORT_USB_SIZE,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
memcpy(&l.u.input2.data[0], &out_buf[0], l.u.input2.size);
|
||||
|
||||
if (gamepad->bluetooth) {
|
||||
uint32_t crc = crc32_le(0xFFFFFFFFU, (const uint8_t*)&PS_INPUT_CRC32_SEED, sizeof(PS_INPUT_CRC32_SEED));
|
||||
crc = ~crc32_le(crc, (const uint8_t *)&l.u.input2.data[0], l.u.input2.size - 4);
|
||||
memcpy(&l.u.input2.data[l.u.input2.size - sizeof(crc)], &crc, sizeof(crc));
|
||||
}
|
||||
|
||||
return uhid_write(gamepad->fd, &l);
|
||||
}
|
||||
|
|
|
|||
38
virt_ds4.h
38
virt_ds4.h
|
|
@ -13,22 +13,46 @@ typedef struct virt_dualshock {
|
|||
|
||||
bool debug;
|
||||
|
||||
bool bluetooth;
|
||||
|
||||
uint32_t dt_sum;
|
||||
uint8_t dt_buffer_current;
|
||||
uint32_t dt_buffer[30];
|
||||
|
||||
uint32_t empty_reports;
|
||||
uint64_t last_time;
|
||||
int64_t last_time;
|
||||
|
||||
int64_t gyro_to_analog_activation_treshold;
|
||||
int64_t gyro_to_analog_mapping;
|
||||
} virt_dualshock_t;
|
||||
|
||||
int virt_dualshock_init(virt_dualshock_t *const gamepad);
|
||||
int virt_dualshock_init(
|
||||
virt_dualshock_t *const gamepad,
|
||||
bool bluetooth,
|
||||
int64_t gyro_to_analog_activation_treshold,
|
||||
int64_t gyro_to_analog_mapping
|
||||
);
|
||||
|
||||
int virt_dualshock_get_fd(virt_dualshock_t *const gamepad);
|
||||
int virt_dualshock_get_fd(
|
||||
virt_dualshock_t *const gamepad
|
||||
);
|
||||
|
||||
int virt_dualshock_event(virt_dualshock_t *const gamepad, gamepad_status_t *const out_device_status);
|
||||
int virt_dualshock_event(
|
||||
virt_dualshock_t *const gamepad,
|
||||
gamepad_status_t *const out_device_status
|
||||
);
|
||||
|
||||
void virt_dualshock_compose(virt_dualshock_t *const gamepad, gamepad_status_t *const in_device_status, uint8_t *const out_buf);
|
||||
void virt_dualshock_compose(
|
||||
virt_dualshock_t *const gamepad,
|
||||
gamepad_status_t *const in_device_status,
|
||||
uint8_t *const out_buf
|
||||
);
|
||||
|
||||
int virt_dualshock_send(virt_dualshock_t *const gamepad, uint8_t *const out_buf);
|
||||
int virt_dualshock_send(
|
||||
virt_dualshock_t *const gamepad,
|
||||
uint8_t *const out_buf
|
||||
);
|
||||
|
||||
void virt_dualshock_close(virt_dualshock_t *const gamepad);
|
||||
void virt_dualshock_close(
|
||||
virt_dualshock_t *const gamepad
|
||||
);
|
||||
|
|
|
|||
1330
virt_ds5.c
1330
virt_ds5.c
File diff suppressed because it is too large
Load diff
41
virt_ds5.h
41
virt_ds5.h
|
|
@ -13,6 +13,10 @@ typedef struct virt_dualsense {
|
|||
|
||||
bool debug;
|
||||
|
||||
bool bluetooth;
|
||||
|
||||
bool edge_model;
|
||||
|
||||
uint8_t seq_num;
|
||||
|
||||
uint32_t dt_sum;
|
||||
|
|
@ -20,18 +24,41 @@ typedef struct virt_dualsense {
|
|||
uint32_t dt_buffer[30];
|
||||
|
||||
uint32_t empty_reports;
|
||||
uint64_t last_time;
|
||||
int64_t last_time;
|
||||
|
||||
int64_t gyro_to_analog_activation_treshold;
|
||||
int64_t gyro_to_analog_mapping;
|
||||
} virt_dualsense_t;
|
||||
|
||||
int virt_dualsense_init(virt_dualsense_t *const gamepad);
|
||||
int virt_dualsense_init(
|
||||
virt_dualsense_t *const gamepad,
|
||||
bool bluetooth,
|
||||
bool dualsense_edge,
|
||||
int64_t gyro_to_analog_activation_treshold,
|
||||
int64_t gyro_to_analog_mapping
|
||||
);
|
||||
|
||||
int virt_dualsense_get_fd(virt_dualsense_t *const gamepad);
|
||||
int virt_dualsense_get_fd(
|
||||
virt_dualsense_t *const gamepad
|
||||
);
|
||||
|
||||
int virt_dualsense_event(virt_dualsense_t *const gamepad, gamepad_status_t *const out_device_status);
|
||||
int virt_dualsense_event(
|
||||
virt_dualsense_t *const gamepad,
|
||||
gamepad_status_t *const out_device_status
|
||||
);
|
||||
|
||||
void virt_dualsense_compose(virt_dualsense_t *const gamepad, gamepad_status_t *const in_device_status, uint8_t *const out_buf);
|
||||
void virt_dualsense_compose(
|
||||
virt_dualsense_t *const gamepad,
|
||||
gamepad_status_t *const in_device_status,
|
||||
uint8_t *const out_buf
|
||||
);
|
||||
|
||||
int virt_dualsense_send(virt_dualsense_t *const gamepad, uint8_t *const out_buf);
|
||||
int virt_dualsense_send(
|
||||
virt_dualsense_t *const gamepad,
|
||||
uint8_t *const out_buf
|
||||
);
|
||||
|
||||
void virt_dualsense_close(virt_dualsense_t *const gamepad);
|
||||
void virt_dualsense_close(
|
||||
virt_dualsense_t *const gamepad
|
||||
);
|
||||
|
||||
|
|
|
|||
411
virt_kbd.c
Normal file
411
virt_kbd.c
Normal file
|
|
@ -0,0 +1,411 @@
|
|||
#include "virt_kbd.h"
|
||||
#include "message.h"
|
||||
#include <linux/input-event-codes.h>
|
||||
|
||||
int virt_kbd_init(virt_kbd_t *const kbd) {
|
||||
int ret = -EINVAL;
|
||||
|
||||
memset(kbd, 0, sizeof(virt_kbd_t));
|
||||
|
||||
int fd = open("/dev/uinput", O_RDWR);
|
||||
if(fd < 0) {
|
||||
ret = errno;
|
||||
goto virt_mouse_init_err;
|
||||
}
|
||||
|
||||
ioctl(fd, UI_SET_EVBIT, EV_REL);
|
||||
ioctl(fd, UI_SET_EVBIT, EV_KEY);
|
||||
ioctl(fd, UI_SET_EVBIT, EV_MSC);
|
||||
ioctl(fd, UI_SET_EVBIT, EV_SYN);
|
||||
ioctl(fd, UI_SET_MSCBIT, MSC_TIMESTAMP);
|
||||
ioctl(fd, UI_SET_KEYBIT, KEY_Q);
|
||||
ioctl(fd, UI_SET_KEYBIT, KEY_W);
|
||||
ioctl(fd, UI_SET_KEYBIT, KEY_E);
|
||||
ioctl(fd, UI_SET_KEYBIT, KEY_R);
|
||||
ioctl(fd, UI_SET_KEYBIT, KEY_T);
|
||||
ioctl(fd, UI_SET_KEYBIT, KEY_Y);
|
||||
ioctl(fd, UI_SET_KEYBIT, KEY_U);
|
||||
ioctl(fd, UI_SET_KEYBIT, KEY_I);
|
||||
ioctl(fd, UI_SET_KEYBIT, KEY_O);
|
||||
ioctl(fd, UI_SET_KEYBIT, KEY_P);
|
||||
ioctl(fd, UI_SET_KEYBIT, KEY_A);
|
||||
ioctl(fd, UI_SET_KEYBIT, KEY_S);
|
||||
ioctl(fd, UI_SET_KEYBIT, KEY_D);
|
||||
ioctl(fd, UI_SET_KEYBIT, KEY_F);
|
||||
ioctl(fd, UI_SET_KEYBIT, KEY_G);
|
||||
ioctl(fd, UI_SET_KEYBIT, KEY_H);
|
||||
ioctl(fd, UI_SET_KEYBIT, KEY_J);
|
||||
ioctl(fd, UI_SET_KEYBIT, KEY_K);
|
||||
ioctl(fd, UI_SET_KEYBIT, KEY_L);
|
||||
ioctl(fd, UI_SET_KEYBIT, KEY_Z);
|
||||
ioctl(fd, UI_SET_KEYBIT, KEY_X);
|
||||
ioctl(fd, UI_SET_KEYBIT, KEY_C);
|
||||
ioctl(fd, UI_SET_KEYBIT, KEY_V);
|
||||
ioctl(fd, UI_SET_KEYBIT, KEY_B);
|
||||
ioctl(fd, UI_SET_KEYBIT, KEY_N);
|
||||
ioctl(fd, UI_SET_KEYBIT, KEY_M);
|
||||
ioctl(fd, UI_SET_KEYBIT, KEY_0);
|
||||
ioctl(fd, UI_SET_KEYBIT, KEY_1);
|
||||
ioctl(fd, UI_SET_KEYBIT, KEY_2);
|
||||
ioctl(fd, UI_SET_KEYBIT, KEY_3);
|
||||
ioctl(fd, UI_SET_KEYBIT, KEY_4);
|
||||
ioctl(fd, UI_SET_KEYBIT, KEY_5);
|
||||
ioctl(fd, UI_SET_KEYBIT, KEY_6);
|
||||
ioctl(fd, UI_SET_KEYBIT, KEY_7);
|
||||
ioctl(fd, UI_SET_KEYBIT, KEY_8);
|
||||
ioctl(fd, UI_SET_KEYBIT, KEY_9);
|
||||
ioctl(fd, UI_SET_KEYBIT, KEY_UP);
|
||||
ioctl(fd, UI_SET_KEYBIT, KEY_DOWN);
|
||||
ioctl(fd, UI_SET_KEYBIT, KEY_LEFT);
|
||||
ioctl(fd, UI_SET_KEYBIT, KEY_RIGHT);
|
||||
//ioctl(fd, UI_SET_KEYBIT, KEY_);
|
||||
|
||||
struct uinput_setup dev = {0};
|
||||
strncpy(dev.name, VIRT_KBD_DEV_NAME, UINPUT_MAX_NAME_SIZE-1);
|
||||
dev.id.bustype = BUS_VIRTUAL;
|
||||
dev.id.vendor = VIRT_KBD_DEV_VENDOR_ID;
|
||||
dev.id.product = VIRT_KBD_DEV_PRODUCT_ID;
|
||||
dev.id.version = VIRT_KBD_DEV_VERSION;
|
||||
|
||||
if(ioctl(fd, UI_DEV_SETUP, &dev) < 0) {
|
||||
ret = errno > 0 ? errno : -1 * errno;
|
||||
ret = ret == 0 ? -EIO : ret;
|
||||
goto virt_mouse_init_err;
|
||||
}
|
||||
|
||||
if(ioctl(fd, UI_DEV_CREATE) < 0) {
|
||||
ret = errno > 0 ? errno : -1 * errno;
|
||||
ret = ret == 0 ? -EIO : ret;
|
||||
goto virt_mouse_init_err;
|
||||
}
|
||||
|
||||
// initialization ok
|
||||
kbd->fd = fd;
|
||||
ret = 0;
|
||||
|
||||
virt_mouse_init_err:
|
||||
if (ret != 0) {
|
||||
kbd->fd = -1;
|
||||
close(fd);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int virt_kbd_get_fd(virt_kbd_t *const kbd) {
|
||||
return kbd->fd;
|
||||
}
|
||||
|
||||
int virt_kbd_send(virt_kbd_t *const kbd, keyboard_status_t *const status, struct timeval *const now) {
|
||||
int res = 0;
|
||||
|
||||
size_t events_count = 0;
|
||||
struct input_event events[12];
|
||||
|
||||
struct input_event tmp_ev;
|
||||
|
||||
tmp_ev.type = EV_KEY;
|
||||
|
||||
if (status->q != kbd->prev_q) {
|
||||
tmp_ev.code = KEY_Q;
|
||||
tmp_ev.value = kbd->prev_q = status->q;
|
||||
events[events_count++] = tmp_ev;
|
||||
}
|
||||
|
||||
if (status->w != kbd->prev_w) {
|
||||
tmp_ev.code = KEY_W;
|
||||
tmp_ev.value = kbd->prev_w = status->w;
|
||||
events[events_count++] = tmp_ev;
|
||||
}
|
||||
|
||||
if (status->e != kbd->prev_e) {
|
||||
tmp_ev.code = KEY_E;
|
||||
tmp_ev.value = kbd->prev_e = status->e;
|
||||
events[events_count++] = tmp_ev;
|
||||
}
|
||||
|
||||
if (status->r != kbd->prev_r) {
|
||||
tmp_ev.code = KEY_R;
|
||||
tmp_ev.value = kbd->prev_r = status->r;
|
||||
events[events_count++] = tmp_ev;
|
||||
}
|
||||
|
||||
if (status->t != kbd->prev_t) {
|
||||
tmp_ev.code = KEY_T;
|
||||
tmp_ev.value = kbd->prev_t = status->t;
|
||||
events[events_count++] = tmp_ev;
|
||||
}
|
||||
|
||||
if (status->y != kbd->prev_y) {
|
||||
tmp_ev.code = KEY_Y;
|
||||
tmp_ev.value = kbd->prev_y = status->y;
|
||||
events[events_count++] = tmp_ev;
|
||||
}
|
||||
|
||||
if (status->u != kbd->prev_u) {
|
||||
tmp_ev.code = KEY_U;
|
||||
tmp_ev.value = kbd->prev_u = status->u;
|
||||
events[events_count++] = tmp_ev;
|
||||
}
|
||||
|
||||
if (status->i != kbd->prev_i) {
|
||||
tmp_ev.code = KEY_I;
|
||||
tmp_ev.value = kbd->prev_i = status->i;
|
||||
events[events_count++] = tmp_ev;
|
||||
}
|
||||
|
||||
if (status->o != kbd->prev_o) {
|
||||
tmp_ev.code = KEY_O;
|
||||
tmp_ev.value = kbd->prev_o = status->o;
|
||||
events[events_count++] = tmp_ev;
|
||||
}
|
||||
|
||||
if (status->p != kbd->prev_p) {
|
||||
tmp_ev.code = KEY_P;
|
||||
tmp_ev.value = kbd->prev_p = status->p;
|
||||
events[events_count++] = tmp_ev;
|
||||
}
|
||||
|
||||
if (status->a != kbd->prev_a) {
|
||||
tmp_ev.code = KEY_A;
|
||||
tmp_ev.value = kbd->prev_a = status->a;
|
||||
events[events_count++] = tmp_ev;
|
||||
}
|
||||
|
||||
if (status->s != kbd->prev_s) {
|
||||
tmp_ev.code = KEY_S;
|
||||
tmp_ev.value = kbd->prev_s = status->s;
|
||||
events[events_count++] = tmp_ev;
|
||||
}
|
||||
|
||||
|
||||
if (status->d != kbd->prev_d) {
|
||||
tmp_ev.code = KEY_D;
|
||||
tmp_ev.value = kbd->prev_d = status->d;
|
||||
events[events_count++] = tmp_ev;
|
||||
}
|
||||
|
||||
if (status->f != kbd->prev_f) {
|
||||
tmp_ev.code = KEY_F;
|
||||
tmp_ev.value = kbd->prev_f = status->f;
|
||||
events[events_count++] = tmp_ev;
|
||||
}
|
||||
|
||||
if (status->g != kbd->prev_g) {
|
||||
tmp_ev.code = KEY_G;
|
||||
tmp_ev.value = kbd->prev_g = status->g;
|
||||
events[events_count++] = tmp_ev;
|
||||
}
|
||||
|
||||
if (status->h != kbd->prev_h) {
|
||||
tmp_ev.code = KEY_H;
|
||||
tmp_ev.value = kbd->prev_h = status->h;
|
||||
events[events_count++] = tmp_ev;
|
||||
}
|
||||
|
||||
if (status->j != kbd->prev_j) {
|
||||
tmp_ev.code = KEY_J;
|
||||
tmp_ev.value = kbd->prev_j = status->j;
|
||||
events[events_count++] = tmp_ev;
|
||||
}
|
||||
|
||||
if (status->k != kbd->prev_k) {
|
||||
tmp_ev.code = KEY_K;
|
||||
tmp_ev.value = kbd->prev_k = status->k;
|
||||
events[events_count++] = tmp_ev;
|
||||
}
|
||||
|
||||
if (status->l != kbd->prev_l) {
|
||||
tmp_ev.code = KEY_L;
|
||||
tmp_ev.value = kbd->prev_l = status->l;
|
||||
events[events_count++] = tmp_ev;
|
||||
}
|
||||
|
||||
if (status->z != kbd->prev_z) {
|
||||
tmp_ev.code = KEY_Z;
|
||||
tmp_ev.value = kbd->prev_z = status->z;
|
||||
events[events_count++] = tmp_ev;
|
||||
}
|
||||
|
||||
if (status->x != kbd->prev_x) {
|
||||
tmp_ev.code = KEY_X;
|
||||
tmp_ev.value = kbd->prev_x = status->x;
|
||||
events[events_count++] = tmp_ev;
|
||||
}
|
||||
|
||||
if (status->c != kbd->prev_c) {
|
||||
tmp_ev.code = KEY_C;
|
||||
tmp_ev.value = kbd->prev_c = status->c;
|
||||
events[events_count++] = tmp_ev;
|
||||
}
|
||||
|
||||
if (status->v != kbd->prev_v) {
|
||||
tmp_ev.code = KEY_V;
|
||||
tmp_ev.value = kbd->prev_v = status->v;
|
||||
events[events_count++] = tmp_ev;
|
||||
}
|
||||
|
||||
if (status->b != kbd->prev_b) {
|
||||
tmp_ev.code = KEY_B;
|
||||
tmp_ev.value = kbd->prev_b = status->b;
|
||||
events[events_count++] = tmp_ev;
|
||||
}
|
||||
|
||||
if (status->n != kbd->prev_n) {
|
||||
tmp_ev.code = KEY_N;
|
||||
tmp_ev.value = kbd->prev_n = status->n;
|
||||
events[events_count++] = tmp_ev;
|
||||
}
|
||||
|
||||
if (status->m != kbd->prev_m) {
|
||||
tmp_ev.code = KEY_M;
|
||||
tmp_ev.value = kbd->prev_m = status->m;
|
||||
events[events_count++] = tmp_ev;
|
||||
}
|
||||
|
||||
if (status->num_0 != kbd->prev_num_0) {
|
||||
tmp_ev.code = KEY_0;
|
||||
tmp_ev.value = kbd->prev_num_0 = status->num_0;
|
||||
events[events_count++] = tmp_ev;
|
||||
}
|
||||
|
||||
if (status->num_1 != kbd->prev_num_1) {
|
||||
tmp_ev.code = KEY_1;
|
||||
tmp_ev.value = kbd->prev_num_1 = status->num_1;
|
||||
events[events_count++] = tmp_ev;
|
||||
}
|
||||
|
||||
if (status->num_2 != kbd->prev_num_2) {
|
||||
tmp_ev.code = KEY_2;
|
||||
tmp_ev.value = kbd->prev_num_2 = status->num_2;
|
||||
events[events_count++] = tmp_ev;
|
||||
}
|
||||
|
||||
if (status->num_3 != kbd->prev_num_3) {
|
||||
tmp_ev.code = KEY_3;
|
||||
tmp_ev.value = kbd->prev_num_3 = status->num_3;
|
||||
events[events_count++] = tmp_ev;
|
||||
}
|
||||
|
||||
if (status->num_4 != kbd->prev_num_4) {
|
||||
tmp_ev.code = KEY_4;
|
||||
tmp_ev.value = kbd->prev_num_4 = status->num_4;
|
||||
events[events_count++] = tmp_ev;
|
||||
}
|
||||
|
||||
if (status->num_5 != kbd->prev_num_5) {
|
||||
tmp_ev.code = KEY_5;
|
||||
tmp_ev.value = kbd->prev_num_5 = status->num_5;
|
||||
events[events_count++] = tmp_ev;
|
||||
}
|
||||
|
||||
if (status->num_6 != kbd->prev_num_6) {
|
||||
tmp_ev.code = KEY_6;
|
||||
tmp_ev.value = kbd->prev_num_6 = status->num_6;
|
||||
events[events_count++] = tmp_ev;
|
||||
}
|
||||
|
||||
if (status->num_7 != kbd->prev_num_7) {
|
||||
tmp_ev.code = KEY_7;
|
||||
tmp_ev.value = kbd->prev_num_7 = status->num_7;
|
||||
events[events_count++] = tmp_ev;
|
||||
}
|
||||
|
||||
if (status->num_8 != kbd->prev_num_8) {
|
||||
tmp_ev.code = KEY_8;
|
||||
tmp_ev.value = kbd->prev_num_8 = status->num_8;
|
||||
events[events_count++] = tmp_ev;
|
||||
}
|
||||
|
||||
if (status->num_9 != kbd->prev_num_9) {
|
||||
tmp_ev.code = KEY_9;
|
||||
tmp_ev.value = kbd->prev_num_9 = status->num_9;
|
||||
events[events_count++] = tmp_ev;
|
||||
}
|
||||
|
||||
if (status->lctrl != kbd->prev_lctrl) {
|
||||
tmp_ev.code = KEY_LEFTCTRL;
|
||||
tmp_ev.value = kbd->prev_lctrl = status->lctrl;
|
||||
events[events_count++] = tmp_ev;
|
||||
}
|
||||
|
||||
if (status->up != kbd->prev_up) {
|
||||
tmp_ev.code = KEY_UP;
|
||||
tmp_ev.value = kbd->prev_up = status->up;
|
||||
events[events_count++] = tmp_ev;
|
||||
}
|
||||
|
||||
if (status->down != kbd->prev_down) {
|
||||
tmp_ev.code = KEY_DOWN;
|
||||
tmp_ev.value = kbd->prev_down = status->down;
|
||||
events[events_count++] = tmp_ev;
|
||||
}
|
||||
|
||||
if (status->left != kbd->prev_left) {
|
||||
tmp_ev.code = KEY_LEFT;
|
||||
tmp_ev.value = kbd->prev_left = status->left;
|
||||
events[events_count++] = tmp_ev;
|
||||
}
|
||||
|
||||
if (status->right != kbd->prev_right) {
|
||||
tmp_ev.code = KEY_RIGHT;
|
||||
tmp_ev.value = kbd->prev_right = status->right;
|
||||
if (write(kbd->fd, &tmp_ev, sizeof(tmp_ev)) != sizeof(struct input_event)) {
|
||||
res = errno < 0 ? errno : -1 * errno;
|
||||
goto virt_kbd_send_err;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
const struct input_event timestamp_ev = {
|
||||
.code = MSC_TIMESTAMP,
|
||||
.type = EV_MSC,
|
||||
.value = (now.tv_sec - secAtInit)*1000000 + (now.tv_usec - usecAtInit),
|
||||
.time = now,
|
||||
};
|
||||
const ssize_t timestamp_written = write(fd, (void*)×tamp_ev, sizeof(timestamp_ev));
|
||||
if (timestamp_written != sizeof(timestamp_ev)) {
|
||||
fprintf(stderr, "Error in sync: written %ld bytes out of %ld\n", timestamp_written, sizeof(timestamp_ev));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (events_count > 0) {
|
||||
struct timeval t;
|
||||
if (now != NULL) {
|
||||
t = *now;
|
||||
} else {
|
||||
gettimeofday(&t, NULL);
|
||||
}
|
||||
|
||||
struct input_event syn_ev = {
|
||||
.code = SYN_REPORT,
|
||||
.type = EV_SYN,
|
||||
.value = 0,
|
||||
.time = t,
|
||||
};
|
||||
syn_ev.time.tv_usec += 1;
|
||||
|
||||
events[events_count++] = syn_ev;
|
||||
|
||||
for (size_t i = 0; i < events_count; ++i) {
|
||||
if (i != (events_count - 1)) {
|
||||
events[i].time = t;
|
||||
}
|
||||
|
||||
const ssize_t sync_written = write(kbd->fd, (void*)&events[i], sizeof(struct input_event));
|
||||
if (sync_written != sizeof(syn_ev)) {
|
||||
fprintf(stderr, "Error in sync: written %ld bytes out of %ld\n", sync_written, sizeof(syn_ev));
|
||||
res = errno;
|
||||
res = res < 0 ? res : -1*res;
|
||||
res = res == 0 ? -EIO : res;
|
||||
goto virt_kbd_send_err;
|
||||
}
|
||||
}
|
||||
}
|
||||
virt_kbd_send_err:
|
||||
return res;
|
||||
}
|
||||
|
||||
void virt_kbd_close(virt_kbd_t *const kbd) {
|
||||
close(kbd->fd);
|
||||
}
|
||||
67
virt_kbd.h
Normal file
67
virt_kbd.h
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
#pragma once
|
||||
|
||||
#include "message.h"
|
||||
#include "devices_status.h"
|
||||
|
||||
#define VIRT_KBD_DEV_NAME "ROGueENEMY - kbd"
|
||||
#define VIRT_KBD_DEV_VENDOR_ID 0x108c
|
||||
#define VIRT_KBD_DEV_PRODUCT_ID 0x0323
|
||||
#define VIRT_KBD_DEV_VERSION 0x0111
|
||||
|
||||
typedef struct virt_kbd {
|
||||
int fd;
|
||||
|
||||
uint8_t prev_q;
|
||||
uint8_t prev_w;
|
||||
uint8_t prev_e;
|
||||
uint8_t prev_r;
|
||||
uint8_t prev_t;
|
||||
uint8_t prev_y;
|
||||
uint8_t prev_u;
|
||||
uint8_t prev_i;
|
||||
uint8_t prev_o;
|
||||
uint8_t prev_p;
|
||||
uint8_t prev_a;
|
||||
uint8_t prev_s;
|
||||
uint8_t prev_d;
|
||||
uint8_t prev_f;
|
||||
uint8_t prev_g;
|
||||
uint8_t prev_h;
|
||||
uint8_t prev_j;
|
||||
uint8_t prev_k;
|
||||
uint8_t prev_l;
|
||||
uint8_t prev_z;
|
||||
uint8_t prev_x;
|
||||
uint8_t prev_c;
|
||||
uint8_t prev_v;
|
||||
uint8_t prev_b;
|
||||
uint8_t prev_n;
|
||||
uint8_t prev_m;
|
||||
|
||||
uint8_t prev_num_1;
|
||||
uint8_t prev_num_2;
|
||||
uint8_t prev_num_3;
|
||||
uint8_t prev_num_4;
|
||||
uint8_t prev_num_5;
|
||||
uint8_t prev_num_6;
|
||||
uint8_t prev_num_7;
|
||||
uint8_t prev_num_8;
|
||||
uint8_t prev_num_9;
|
||||
uint8_t prev_num_0;
|
||||
|
||||
uint8_t prev_up;
|
||||
uint8_t prev_down;
|
||||
uint8_t prev_left;
|
||||
uint8_t prev_right;
|
||||
|
||||
uint8_t prev_lctrl;
|
||||
|
||||
} virt_kbd_t;
|
||||
|
||||
int virt_kbd_init(virt_kbd_t *const mouse);
|
||||
|
||||
int virt_kbd_get_fd(virt_kbd_t *const mouse);
|
||||
|
||||
int virt_kbd_send(virt_kbd_t *const mouse, keyboard_status_t *const status, struct timeval *const now);
|
||||
|
||||
void virt_kbd_close(virt_kbd_t *const mouse);
|
||||
163
virt_mouse.c
Normal file
163
virt_mouse.c
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
#include "virt_mouse.h"
|
||||
|
||||
int virt_mouse_init(virt_mouse_t *const mouse) {
|
||||
int ret = -EINVAL;
|
||||
|
||||
mouse->status_recv = 0;
|
||||
|
||||
int fd = open("/dev/uinput", O_RDWR);
|
||||
if(fd < 0) {
|
||||
ret = errno;
|
||||
goto virt_mouse_init_err;
|
||||
}
|
||||
|
||||
ioctl(fd, UI_SET_EVBIT, EV_REL);
|
||||
ioctl(fd, UI_SET_EVBIT, EV_KEY);
|
||||
ioctl(fd, UI_SET_EVBIT, EV_MSC);
|
||||
ioctl(fd, UI_SET_EVBIT, EV_SYN);
|
||||
ioctl(fd, UI_SET_MSCBIT, MSC_TIMESTAMP);
|
||||
ioctl(fd, UI_SET_KEYBIT, BTN_LEFT);
|
||||
ioctl(fd, UI_SET_KEYBIT, BTN_MIDDLE);
|
||||
ioctl(fd, UI_SET_KEYBIT, BTN_RIGHT);
|
||||
ioctl(fd, UI_SET_RELBIT, REL_X);
|
||||
ioctl(fd, UI_SET_RELBIT, REL_Y);
|
||||
ioctl(fd, UI_SET_RELBIT, REL_WHEEL);
|
||||
ioctl(fd, UI_SET_RELBIT, REL_WHEEL_HI_RES);
|
||||
|
||||
struct uinput_setup dev = {0};
|
||||
strncpy(dev.name, VIRT_MOUSE_DEV_NAME, UINPUT_MAX_NAME_SIZE-1);
|
||||
dev.id.bustype = BUS_VIRTUAL;
|
||||
dev.id.vendor = VIRT_MOUSE_DEV_VENDOR_ID;
|
||||
dev.id.product = VIRT_MOUSE_DEV_PRODUCT_ID;
|
||||
dev.id.version = VIRT_MOUSE_DEV_VERSION;
|
||||
|
||||
if(ioctl(fd, UI_DEV_SETUP, &dev) < 0) {
|
||||
ret = errno > 0 ? errno : -1 * errno;
|
||||
ret = ret == 0 ? -EIO : ret;
|
||||
goto virt_mouse_init_err;
|
||||
}
|
||||
|
||||
if(ioctl(fd, UI_DEV_CREATE) < 0) {
|
||||
ret = errno > 0 ? errno : -1 * errno;
|
||||
ret = ret == 0 ? -EIO : ret;
|
||||
goto virt_mouse_init_err;
|
||||
}
|
||||
|
||||
// initialization ok
|
||||
mouse->prev_btn_left = 0;
|
||||
mouse->prev_btn_right = 0;
|
||||
mouse->prev_btn_middle = 0;
|
||||
mouse->fd = fd;
|
||||
ret = 0;
|
||||
|
||||
virt_mouse_init_err:
|
||||
if (ret != 0) {
|
||||
mouse->fd = -1;
|
||||
close(fd);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int virt_mouse_get_fd(virt_mouse_t *const mouse) {
|
||||
return mouse->fd;
|
||||
}
|
||||
|
||||
int virt_mouse_send(virt_mouse_t *const mouse, mouse_status_t *const status, struct timeval *const now) {
|
||||
int res = 0;
|
||||
|
||||
size_t events_count = 0;
|
||||
struct input_event events[12];
|
||||
|
||||
struct input_event tmp_ev;
|
||||
tmp_ev.type = EV_REL;
|
||||
|
||||
if (status->x != 0) {
|
||||
tmp_ev.code = REL_X;
|
||||
tmp_ev.value = status->x;
|
||||
events[events_count++] = tmp_ev;
|
||||
}
|
||||
|
||||
if (status->y != 0) {
|
||||
tmp_ev.code = REL_Y;
|
||||
tmp_ev.value = status->y;
|
||||
events[events_count++] = tmp_ev;
|
||||
}
|
||||
|
||||
tmp_ev.type = EV_KEY;
|
||||
|
||||
if (status->btn_left != mouse->prev_btn_left) {
|
||||
mouse->prev_btn_left = status->btn_left;
|
||||
tmp_ev.code = BTN_LEFT;
|
||||
tmp_ev.value = status->btn_left;
|
||||
events[events_count++] = tmp_ev;
|
||||
}
|
||||
|
||||
if (status->btn_middle != mouse->prev_btn_middle) {
|
||||
mouse->prev_btn_middle = status->btn_middle;
|
||||
tmp_ev.code = BTN_MIDDLE;
|
||||
tmp_ev.value = status->btn_middle;
|
||||
events[events_count++] = tmp_ev;
|
||||
}
|
||||
|
||||
if (status->btn_right != mouse->prev_btn_right) {
|
||||
mouse->prev_btn_right = status->btn_right;
|
||||
tmp_ev.code = BTN_RIGHT;
|
||||
tmp_ev.value = status->btn_right;
|
||||
events[events_count++] = tmp_ev;
|
||||
}
|
||||
|
||||
#if 0
|
||||
const struct input_event timestamp_ev = {
|
||||
.code = MSC_TIMESTAMP,
|
||||
.type = EV_MSC,
|
||||
.value = (now.tv_sec - secAtInit)*1000000 + (now.tv_usec - usecAtInit),
|
||||
.time = now,
|
||||
};
|
||||
const ssize_t timestamp_written = write(fd, (void*)×tamp_ev, sizeof(timestamp_ev));
|
||||
if (timestamp_written != sizeof(timestamp_ev)) {
|
||||
fprintf(stderr, "Error in sync: written %ld bytes out of %ld\n", timestamp_written, sizeof(timestamp_ev));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (events_count > 0) {
|
||||
struct timeval t;
|
||||
if (now != NULL) {
|
||||
t = *now;
|
||||
} else {
|
||||
gettimeofday(&t, NULL);
|
||||
}
|
||||
|
||||
struct input_event syn_ev = {
|
||||
.code = SYN_REPORT,
|
||||
.type = EV_SYN,
|
||||
.value = 0,
|
||||
.time = t,
|
||||
};
|
||||
syn_ev.time.tv_usec += 1;
|
||||
|
||||
events[events_count++] = syn_ev;
|
||||
|
||||
for (size_t i = 0; i < events_count; ++i) {
|
||||
if (i != (events_count - 1)) {
|
||||
events[i].time = t;
|
||||
}
|
||||
|
||||
const ssize_t sync_written = write(mouse->fd, (void*)&events[i], sizeof(struct input_event));
|
||||
if (sync_written != sizeof(syn_ev)) {
|
||||
fprintf(stderr, "Error in sync: written %ld bytes out of %ld\n", sync_written, sizeof(syn_ev));
|
||||
res = errno;
|
||||
res = res < 0 ? res : -1*res;
|
||||
res = res == 0 ? -EIO : res;
|
||||
goto virt_mouse_send_err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virt_mouse_send_err:
|
||||
return res;
|
||||
}
|
||||
|
||||
void virt_mouse_close(virt_mouse_t *const mouse) {
|
||||
close(mouse->fd);
|
||||
}
|
||||
28
virt_mouse.h
Normal file
28
virt_mouse.h
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
#pragma once
|
||||
|
||||
#include "message.h"
|
||||
#include "devices_status.h"
|
||||
|
||||
#define VIRT_MOUSE_DEV_NAME "ROGueENEMY - mouse"
|
||||
#define VIRT_MOUSE_DEV_VENDOR_ID 0x108c
|
||||
#define VIRT_MOUSE_DEV_PRODUCT_ID 0x0323
|
||||
#define VIRT_MOUSE_DEV_VERSION 0x0111
|
||||
|
||||
typedef struct virt_mouse {
|
||||
int fd;
|
||||
|
||||
uint8_t prev_btn_left;
|
||||
uint8_t prev_btn_right;
|
||||
uint8_t prev_btn_middle;
|
||||
|
||||
uint64_t status_recv;
|
||||
|
||||
} virt_mouse_t;
|
||||
|
||||
int virt_mouse_init(virt_mouse_t *const mouse);
|
||||
|
||||
int virt_mouse_get_fd(virt_mouse_t *const mouse);
|
||||
|
||||
int virt_mouse_send(virt_mouse_t *const mouse, mouse_status_t *const status, struct timeval *const now);
|
||||
|
||||
void virt_mouse_close(virt_mouse_t *const mouse);
|
||||
17
xbox360.c
17
xbox360.c
|
|
@ -1,8 +1,13 @@
|
|||
#include "xbox360.h"
|
||||
#include "message.h"
|
||||
|
||||
int xbox360_ev_map(const evdev_collected_t *const coll, in_message_t *const messages, size_t messages_len, void* user_data) {
|
||||
const xbox360_settings_t *const settings = (xbox360_settings_t*)user_data;
|
||||
int xbox360_ev_map(
|
||||
const dev_in_settings_t *const conf,
|
||||
const evdev_collected_t *const coll,
|
||||
in_message_t *const messages,
|
||||
size_t messages_len,
|
||||
void* user_data
|
||||
) {
|
||||
int written_msg = 0;
|
||||
|
||||
for (uint32_t i = 0; i < coll->ev_count; ++i) {
|
||||
|
|
@ -12,16 +17,16 @@ int xbox360_ev_map(const evdev_collected_t *const coll, in_message_t *const mess
|
|||
};
|
||||
|
||||
if (coll->ev[i].code == BTN_EAST) {
|
||||
current_message.data.gamepad_set.element = (settings->nintendo_layout) ? GAMEPAD_BTN_CROSS : GAMEPAD_BTN_CIRCLE;
|
||||
current_message.data.gamepad_set.element = GAMEPAD_BTN_CIRCLE;
|
||||
current_message.data.gamepad_set.status.btn = coll->ev[i].value;
|
||||
} else if (coll->ev[i].code == BTN_NORTH) {
|
||||
current_message.data.gamepad_set.element = (settings->nintendo_layout) ? GAMEPAD_BTN_TRIANGLE : GAMEPAD_BTN_SQUARE;
|
||||
current_message.data.gamepad_set.element = GAMEPAD_BTN_SQUARE;
|
||||
current_message.data.gamepad_set.status.btn = coll->ev[i].value;
|
||||
} else if (coll->ev[i].code == BTN_SOUTH) {
|
||||
current_message.data.gamepad_set.element = (settings->nintendo_layout) ? GAMEPAD_BTN_CIRCLE : GAMEPAD_BTN_CROSS;
|
||||
current_message.data.gamepad_set.element = GAMEPAD_BTN_CROSS;
|
||||
current_message.data.gamepad_set.status.btn = coll->ev[i].value;
|
||||
} else if (coll->ev[i].code == BTN_WEST) {
|
||||
current_message.data.gamepad_set.element = (settings->nintendo_layout) ? GAMEPAD_BTN_SQUARE : GAMEPAD_BTN_TRIANGLE;
|
||||
current_message.data.gamepad_set.element = GAMEPAD_BTN_TRIANGLE;
|
||||
current_message.data.gamepad_set.status.btn = coll->ev[i].value;
|
||||
} else if (coll->ev[i].code == BTN_SELECT) {
|
||||
current_message.data.gamepad_set.element = GAMEPAD_BTN_OPTION;
|
||||
|
|
|
|||
12
xbox360.h
12
xbox360.h
|
|
@ -2,8 +2,10 @@
|
|||
|
||||
#include "input_dev.h"
|
||||
|
||||
typedef struct xbox360_settings {
|
||||
bool nintendo_layout;
|
||||
} xbox360_settings_t;
|
||||
|
||||
int xbox360_ev_map(const evdev_collected_t *const coll, in_message_t *const messages, size_t messages_len, void* user_data);
|
||||
int xbox360_ev_map(
|
||||
const dev_in_settings_t *const conf,
|
||||
const evdev_collected_t *const coll,
|
||||
in_message_t *const messages,
|
||||
size_t messages_len,
|
||||
void* user_data
|
||||
);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue