whe.el

emacs support for the thrustmaster t-150 steering wheel
Log | Files | Refs | README

commit 31a752142adf44620fcdc04646fe3e4ba6fcf42c
parent 99a09a6927fd0030a70f8b5963bba985c68bbca6
Author: quantumish <freifeld.david@gmail.com>
Date:   Mon, 27 Feb 2023 00:23:14 +0000

Add wheel parameter support

Diffstat:
Mtodo.org | 13++++++++-----
Awheeldaemon.c | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mwheelmacs.cpp | 90++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
Awheelmesg.h | 27+++++++++++++++++++++++++++
4 files changed, 170 insertions(+), 19 deletions(-)

diff --git a/todo.org b/todo.org @@ -1,11 +1,14 @@ * todos -- [ ] settings before worker init -- [X] bind wheel keys to unused emacs-recognized keys +- [-] bind wheel keys to unused emacs-recognized keys + - [X] function keys - [ ] dynamically choose unused keys -- [ ] enabling autocenter -- [ ] changing range +- [X] enabling autocenter +- [X] changing range/gain/force - [ ] ffb settings - [ ] send wheel shifts as keypresses - [ ] emulated (emacs) - [ ] emulated (c++/X11) - +- [ ] curate some fun examples + - [ ] "roll back" changes + - [ ] exert force to force push + - [ ] wheel for warning level diff --git a/wheeldaemon.c b/wheeldaemon.c @@ -0,0 +1,59 @@ +#include <fcntl.h> +#include <stdio.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <string.h> +#include <sys/types.h> +#include <arpa/inet.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdio.h> + +#include "wheelmesg.h" + +#define PORT 8070 +#define PATH "/sys/devices/pci0000:00/0000:00:14.0/usb1/1-6" +#define BUFSIZE 512 + +int main() { + int s = socket(AF_INET, SOCK_DGRAM, 0); + struct sockaddr_in addr; + memset((char *)&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; // Specify address family. + addr.sin_addr.s_addr = htonl(INADDR_ANY); // INADDR_ANY just 0.0.0.0, machine IP address + addr.sin_port = htons(PORT); // Specify port. + bind(s, (struct sockaddr *)&addr, sizeof(addr)); + struct sockaddr_in remaddr; + socklen_t addrlen = sizeof(remaddr); + int recvlen; + unsigned char buf[BUFSIZE]; + + while (1 == 1) { + recvlen = recvfrom(s, buf, BUFSIZE, 0, (struct sockaddr *)&remaddr, &addrlen); + struct wheel_cmd cmd = *(struct wheel_cmd*)buf; + int fd; + char val[5] = {0}; + switch (cmd.type) { + case AUTOCENTER: + fd = open(PATH "/enable_autocenter", O_WRONLY); + write(fd, cmd.value.autocenter ? "y" : "n", 1); + break; + case AUTOCENTER_FORCE: + fd = open(PATH "/autocenter", O_WRONLY); + sprintf(val, "%d", cmd.value.autocenter_force); + write(fd, val, 3); + break; + case GAIN: + fd = open(PATH "/gain", O_WRONLY); + sprintf(val, "%d", cmd.value.gain); + write(fd, val, 3); + break; + case RANGE: + fd = open(PATH "/range", O_WRONLY); + sprintf(val, "%d", cmd.value.range); + write(fd, val, 4); + break; + } + } + +} diff --git a/wheelmacs.cpp b/wheelmacs.cpp @@ -1,4 +1,5 @@ #include <cstdint> +#include <stdint.h> #include <thread> #include <memory> #include <vector> @@ -8,12 +9,19 @@ #include <fcntl.h> #include <unistd.h> #include <iostream> +#include <sys/socket.h> +#include <netinet/in.h> +#include <string.h> +#include <sys/types.h> +#include <arpa/inet.h> +#include <mutex> #include "linux/joystick.h" #include "emacs-module.h" extern "C" { #include "xdo.h" + #include "wheelmesg.h" } #define VERSION 0.1 @@ -21,18 +29,11 @@ int plugin_is_GPL_compatible; #define S(s) (env->intern(env, s)) +// Set the function cell of the symbol named NAME to SFUN using the 'fset' function. static void bind_function (emacs_env *env, const char *name, emacs_value Sfun) { - /* Set the function cell of the symbol named NAME to SFUN using - the 'fset' function. */ - - /* Convert the strings to symbols by interning them */ emacs_value Qfset = env->intern (env, "fset"); emacs_value Qsym = env->intern (env, name); - - /* Prepare the arguments array */ emacs_value args[] = { Qsym, Sfun }; - - /* Make the call (2 == nb of arguments) */ env->funcall (env, Qfset, 2, args); } @@ -47,15 +48,26 @@ static void provide (emacs_env *env, const char *feature) { env->funcall (env, Qprovide, 1, args); } - std::shared_ptr<std::vector<bool>> buttons; std::shared_ptr<std::vector<int16_t>> axes; std::thread worker; std::atomic_bool stop_worker; +std::mutex cmd_mutex; +struct wheel_cmd cmd; void grab_values() { xdo_t* x = xdo_new(NULL); int fd = open("/dev/input/js0", O_RDONLY | O_NONBLOCK); + + int s = socket(AF_INET, SOCK_DGRAM, 0); + struct sockaddr_in addr; + memset((char *)&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; // Specify address family. + addr.sin_addr.s_addr = htonl(INADDR_ANY); // INADDR_ANY just 0.0.0.0, machine IP address + addr.sin_port = htons(8070); // Specify port. + + connect(s, (struct sockaddr *)&addr, sizeof(addr)); + while (true) { struct js_event e; int r = read(fd, &e, sizeof(e)); @@ -67,15 +79,20 @@ void grab_values() { } else if (e.type & JS_EVENT_AXIS) { (*axes)[e.number] = e.value; } + if (cmd.type != NONE) { + sendto(s, (void*)&cmd, sizeof(struct wheel_cmd), 0, NULL, sizeof(addr)); + cmd.type = NONE; + cmd_mutex.unlock(); + } if (stop_worker) return; } } static emacs_value wheel_init (emacs_env *env, ptrdiff_t nargs, emacs_value* args, void* data) noexcept { - std::vector<bool> tmp_buttons = - {{false,false,false,false,false,false,false,false,false,false,false,false}}; - std::vector<int16_t> tmp_axes = {{0,0,0,0,0}}; - + std::vector<bool> tmp_buttons(12); + std::vector<int16_t> tmp_axes(5); + std::fill(tmp_buttons.begin(), tmp_buttons.end(), false); + std::fill(tmp_axes.begin(), tmp_axes.end(), 0); buttons = std::make_unique<std::vector<bool>>(tmp_buttons); axes = std::make_unique<std::vector<int16_t>>(tmp_axes); @@ -90,6 +107,47 @@ static emacs_value wheel_stop (emacs_env *env, ptrdiff_t nargs, emacs_value* arg return S("nil"); } +static emacs_value wheel_set_autocenter (emacs_env *env, ptrdiff_t nargs, emacs_value* args, void* data) noexcept { + bool val = env->is_not_nil(env, args[0]); + // cmd_mutex.lock(); + cmd = { + .type = AUTOCENTER, + .value = {.autocenter = val} + }; + // cmd_mutex.unlock(); + return S("nil"); +} + +static emacs_value wheel_set_range (emacs_env *env, ptrdiff_t nargs, emacs_value* args, void* data) noexcept { + int val = env->extract_integer(env, args[0]); + if (val < 270 || val > 1080) return S("nil"); + cmd = { + .type = RANGE, + .value = {.range = val} + }; + return S("nil"); +} + +static emacs_value wheel_set_gain (emacs_env *env, ptrdiff_t nargs, emacs_value* args, void* data) noexcept { + int val = env->extract_integer(env, args[0]); + if (val < 0 || val > 100) return S("nil"); + cmd = { + .type = GAIN, + .value = {.gain = val} + }; + return S("nil"); +} + +static emacs_value wheel_set_autocenter_force (emacs_env *env, ptrdiff_t nargs, emacs_value* args, void* data) noexcept { + int val = env->extract_integer(env, args[0]); + if (val < 0 || val > 100) return S("nil"); + cmd = { + .type = AUTOCENTER_FORCE, + .value = {.autocenter_force = val} + }; + return S("nil"); +} + static emacs_value wheel_button (emacs_env *env, ptrdiff_t nargs, emacs_value* args, void* data) noexcept { auto index = env->extract_integer(env, args[0]); if (index >= (*buttons).size() || stop_worker) return S("nil"); @@ -108,7 +166,11 @@ extern int emacs_module_init (struct emacs_runtime *ert) noexcept { emacs_env *env = ert->get_environment (ert); DEFUN("wheel-init", wheel_init, 0, 0, "Set up whe.el worker thread", NULL); DEFUN("wheel-stop", wheel_stop, 0, 0, "Stop whe.el worker thread", NULL); - DEFUN("wheel-button", wheel_button, 1, 1, "Check if button is pressed.", NULL); + DEFUN("wheel-button", wheel_button, 1, 1, "Check if button is pressed.", NULL); + DEFUN("wheel-set-autocenter", wheel_set_autocenter, 1, 1, "Enable/disable autocentering.", NULL); + DEFUN("wheel-set-autocenter-force", wheel_set_autocenter_force, 1, 1, "", NULL); + DEFUN("wheel-set-range", wheel_set_range, 1, 1, "", NULL); + DEFUN("wheel-set-gain", wheel_set_gain, 1, 1, "", NULL); DEFUN("wheel-axis", wheel_axis, 1, 1, "Get axis value.", NULL); provide(env, "wheel"); return 0; diff --git a/wheelmesg.h b/wheelmesg.h @@ -0,0 +1,27 @@ +#pragma once +#include <stdbool.h> + +enum wheel_cmd_type { + AUTOCENTER, + AUTOCENTER_FORCE, + GAIN, + RANGE, + NONE, +}; + +// tagged union +struct wheel_cmd { + enum wheel_cmd_type type; + union { + bool autocenter; + int autocenter_force; + int gain; + int range; + } value; +}; + + +/* struct wheel_cmd a = { */ +/* .type = AUTOCENTER, */ +/* .value = { .autocenter = true } */ +/* }; */