Skip to content

Commit

Permalink
Move driver to an always-running systemd service rather than a udev R…
Browse files Browse the repository at this point in the history
…UN command (#15)
  • Loading branch information
wheaney authored Aug 22, 2023
1 parent f293e36 commit 1b1d644
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 66 deletions.
3 changes: 3 additions & 0 deletions bin/package.sh
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ cp ../bin/xreal_driver_config $PACKAGE_DIR
# copy the udev rule that's needed for the USB integration
cp -r ../udev $PACKAGE_DIR

# copy the systemd files needed to run our service
cp -r ../systemd $PACKAGE_DIR

# bundle up the driver directory
tar -zcvf xrealAirLinuxDriver.tar.gz $PACKAGE_DIR

Expand Down
4 changes: 0 additions & 4 deletions bin/xreal_driver_config
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,5 @@ else
# Add the new key/value pair to the end of the file
echo "$config_key=$config_value" >> "$config_file"
fi

if [ "$config_key" == "disabled" ] && [ "$config_value" == "false" ]; then
~/bin/xrealAirLinuxDriver &
fi
fi
fi
28 changes: 25 additions & 3 deletions bin/xreal_driver_setup
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,36 @@ cp udev/60-xreal-air.rules $UDEV_FILE
udevadm control --reload
udevadm trigger

echo "Copying driver and scripts to ${USER_HOME}/bin"
echo "Copying scripts to ${USER_HOME}/bin"
if test ! -d "$USER_HOME/bin"; then
mkdir $USER_HOME/bin
fi

cp xrealAirLinuxDriver $USER_HOME/bin
cp xreal_driver_config $USER_HOME/bin

echo "Setting up the systemd service"
# check if the systemd service is already running from a previous install
if systemctl is-active --quiet xreal-air-driver; then
systemctl stop xreal-air-driver
fi

cp xrealAirLinuxDriver /usr/bin
chmod 755 /usr/bin/xrealAirLinuxDriver

sed -i -e "s/{user_home}/$ESCAPED_USER_HOME/g" -e "s/{user}/$USER/g" systemd/xreal-air-driver.service
cp systemd/xreal-air-driver.service /etc/systemd/system
chmod 644 /etc/systemd/system/xreal-air-driver.service
systemctl daemon-reload
systemctl start xreal-air-driver

# check if systemd startup was successful
if ! systemctl is-active --quiet xreal-air-driver; then
echo "systemd startup failed"
exit 1
fi

# set it to run on startup
systemctl enable xreal-air-driver

echo "Deleting temp directory: ${tmp_dir}"
rm -rf $tmp_dir
cd "$(dirs -l -0)" && dirs -c
Expand Down
6 changes: 0 additions & 6 deletions interface_lib/src/device3.c
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,6 @@ device3_type* device3_open(device3_event_callback callback) {
device3_type* device = (device3_type*) malloc(sizeof(device3_type));

if (!device) {
fprintf(stderr, "Not allocated!\n");
return NULL;
}

Expand All @@ -190,7 +189,6 @@ device3_type* device3_open(device3_event_callback callback) {
device->callback = callback;

if (0 != hid_init()) {
fprintf(stderr, "Not initialized!\n");
return device;
}

Expand All @@ -212,14 +210,12 @@ device3_type* device3_open(device3_event_callback callback) {
hid_free_enumeration(info);

if (!device->handle) {
fprintf(stderr, "No handle!\n");
return device;
}

device3_clear(device);

if (!send_payload_msg(device, DEVICE3_MSG_GET_STATIC_ID, 0, NULL)) {
fprintf(stderr, "Failed sending payload to get static id!\n");
return device;
}

Expand All @@ -234,7 +230,6 @@ device3_type* device3_open(device3_event_callback callback) {
device3_reset_calibration(device);

if (!send_payload_msg(device, DEVICE3_MSG_GET_CAL_DATA_LENGTH, 0, NULL)) {
fprintf(stderr, "Failed sending payload to get calibration data length!\n");
return device;
}

Expand Down Expand Up @@ -288,7 +283,6 @@ device3_type* device3_open(device3_event_callback callback) {
}

if (!send_payload_msg_signal(device, DEVICE3_MSG_START_IMU_DATA, 0x1)) {
fprintf(stderr, "Failed sending payload to start imu data stream!\n");
return device;
}

Expand Down
109 changes: 57 additions & 52 deletions src/driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ struct libevdev_uinput* uinput;
void handle_device_3(uint64_t timestamp,
device3_event_type event,
const device3_ahrs_type* ahrs) {
if (event == DEVICE3_EVENT_UPDATE) {
if (uinput && event == DEVICE3_EVENT_UPDATE) {
static device3_vec3_type prev_tracked;
device3_quat_type q = device3_get_orientation(ahrs);
device3_vec3_type e = device3_get_euler(q);
Expand Down Expand Up @@ -145,17 +145,49 @@ void handle_device_4(uint64_t timestamp,
device3_type* glasses_imu;
bool driver_disabled=false;

// pthread function to poll the glasses and translate to our virtual controller's joystick input
// pthread function to create the virtual controller and poll the glasses
void *poll_glasses_imu(void *arg) {
printf("Device connected, redirecting input to virtual controller...\n");

// create our virtual device
struct input_absinfo absinfo;
absinfo.minimum = min_input;
absinfo.maximum = max_input;
absinfo.resolution = joystick_resolution;
absinfo.value = mid_input;
absinfo.flat = 2;
absinfo.fuzz = 0;

struct libevdev* evdev = libevdev_new();
check(libevdev_enable_property(evdev, INPUT_PROP_BUTTONPAD));
libevdev_set_name(evdev, "xReal Air virtual joystick");
check(libevdev_enable_event_type(evdev, EV_ABS));
check(libevdev_enable_event_code(evdev, EV_ABS, ABS_X, &absinfo));
check(libevdev_enable_event_code(evdev, EV_ABS, ABS_Y, &absinfo));
check(libevdev_enable_event_code(evdev, EV_ABS, ABS_Z, &absinfo));
check(libevdev_enable_event_code(evdev, EV_ABS, ABS_RX, &absinfo));
check(libevdev_enable_event_code(evdev, EV_ABS, ABS_RY, &absinfo));
check(libevdev_enable_event_code(evdev, EV_ABS, ABS_RZ, &absinfo));

/* do not remove next 3 lines or udev scripts won't assign 0664 permissions -sh */
check(libevdev_enable_event_type(evdev, EV_KEY));
check(libevdev_enable_event_code(evdev, EV_KEY, BTN_JOYSTICK, NULL));
check(libevdev_enable_event_code(evdev, EV_KEY, BTN_TRIGGER, NULL));

check(libevdev_enable_event_code(evdev, EV_KEY, BTN_A, NULL));

check(libevdev_uinput_create_from_device(evdev, LIBEVDEV_UINPUT_OPEN_MANAGED, &uinput));

device3_clear(glasses_imu);
while (!driver_disabled) {
if (device3_read(glasses_imu, 1, false) < 0) {
glasses_imu = NULL;
break;
}
}

glasses_imu = NULL;
libevdev_uinput_destroy(uinput);
libevdev_free(evdev);
}

void parse_config_file(FILE *fp) {
Expand All @@ -164,9 +196,12 @@ void parse_config_file(FILE *fp) {
char *key = strtok(line, "=");
char *value = strtok(NULL, "\n");
if (strcmp(key, "disabled") == 0) {
bool was_disabled = driver_disabled;
driver_disabled = strcmp(value, "true") == 0;
if (driver_disabled)
printf("Driver is disabled!\n");
if (!was_disabled && driver_disabled)
printf("Driver has been disabled, see ~/bin/xreal_driver_config\n");
if (was_disabled && !driver_disabled)
printf("Driver has been re-enabled, see ~/bin/xreal_driver_config\n");
}
}
}
Expand Down Expand Up @@ -227,7 +262,11 @@ void *monitor_config_file(void *arg) {
}

char buffer[EVENT_SIZE];
while (!driver_disabled && glasses_imu) {

// hold this pthread open while the glasses are plugged in, but if they become unplugged:
// 1. hold this thread open as long as driver is disabled, this will block from re-initializing the glasses-polling thread until the driver becomes re-enabled
// 2. exit this thread if the driver is enabled, then we'll wait for the glasses to get plugged back in to re-initialize these threads
while (glasses_imu || driver_disabled) {
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(fd, &readfds);
Expand Down Expand Up @@ -296,60 +335,26 @@ int main(int argc, const char** argv) {
exit(1);
}

struct input_absinfo absinfo;

absinfo.minimum = min_input;
absinfo.maximum = max_input;
absinfo.resolution = joystick_resolution;
absinfo.value = mid_input;
absinfo.flat = 2;
absinfo.fuzz = 0;

struct libevdev* evdev = libevdev_new();
check(libevdev_enable_property(evdev, INPUT_PROP_BUTTONPAD));
libevdev_set_name(evdev, "xReal Air virtual joystick");
check(libevdev_enable_event_type(evdev, EV_ABS));
check(libevdev_enable_event_code(evdev, EV_ABS, ABS_X, &absinfo));
check(libevdev_enable_event_code(evdev, EV_ABS, ABS_Y, &absinfo));
check(libevdev_enable_event_code(evdev, EV_ABS, ABS_Z, &absinfo));
check(libevdev_enable_event_code(evdev, EV_ABS, ABS_RX, &absinfo));
check(libevdev_enable_event_code(evdev, EV_ABS, ABS_RY, &absinfo));
check(libevdev_enable_event_code(evdev, EV_ABS, ABS_RZ, &absinfo));

/* do not remove next 3 lines or udev scripts won't assign 0664 permissions -sh */
check(libevdev_enable_event_type(evdev, EV_KEY));
check(libevdev_enable_event_code(evdev, EV_KEY, BTN_JOYSTICK, NULL));
check(libevdev_enable_event_code(evdev, EV_KEY, BTN_TRIGGER, NULL));

check(libevdev_enable_event_code(evdev, EV_KEY, BTN_A, NULL));

check(libevdev_uinput_create_from_device(evdev, LIBEVDEV_UINPUT_OPEN_MANAGED, &uinput));

glasses_imu = device3_open(handle_device_3);
int connection_attempts = 0;
while (!glasses_imu || !glasses_imu->ready) {
if (++connection_attempts > 5) {
fprintf(stderr, "Device not found, exiting...\n");
break;
}

device3_close(glasses_imu);
fprintf(stderr, "Device not found, sleeping...\n");
sleep(5);
while (1) {
glasses_imu = device3_open(handle_device_3);
}
while (!glasses_imu || !glasses_imu->ready) {
// TODO - move to a blocking check, rather than polling for device availability
// retry every 5 seconds until the device becomes available
device3_close(glasses_imu);
sleep(5);
glasses_imu = device3_open(handle_device_3);
}

if (glasses_imu && glasses_imu->ready) {
// kick off threads to monitor glasses and config file, wait for both to finish (glasses disconnected)
pthread_t glasses_imu_thread;
pthread_t monitor_config_file_thread;
pthread_create(&glasses_imu_thread, NULL, poll_glasses_imu, NULL);
pthread_create(&monitor_config_file_thread, NULL, monitor_config_file, NULL);

pthread_join(glasses_imu_thread, NULL);
pthread_join(monitor_config_file_thread, NULL);

device3_close(glasses_imu);
}

device3_close(glasses_imu);
libevdev_uinput_destroy(uinput);
libevdev_free(evdev);
return 0;
}
11 changes: 11 additions & 0 deletions systemd/xreal-air-driver.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[Unit]
Description=XREAL Air user-space driver
After=network.target

[Service]
Type=simple
ExecStart=/bin/bash -c 'HOME={user_home} /usr/bin/xrealAirLinuxDriver'
Restart=on-failure

[Install]
WantedBy=multi-user.target
2 changes: 1 addition & 1 deletion udev/60-xreal-air.rules
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# copied from Valve: https://github.com/ValveSoftware/steam-devices/blob/13443480a64fe8f10676606bd57da6de89f8ccb1/60-steam-input.rules#L5
KERNEL=="uinput", SUBSYSTEM=="misc", TAG+="uaccess", OPTIONS+="static_node=uinput"

SUBSYSTEMS=="usb", ATTRS{idVendor}=="3318", ATTRS{idProduct}=="0424", MODE="0660", TAG+="uaccess", RUN+="/bin/sh -c 'HOME={user_home} {user_home}/bin/xrealAirLinuxDriver' &"
SUBSYSTEMS=="usb", ATTRS{idVendor}=="3318", ATTRS{idProduct}=="0424", MODE="0660", TAG+="uaccess"

0 comments on commit 1b1d644

Please sign in to comment.