Create IMU virtual device

This commit is contained in:
Denis Benato 2023-11-02 13:11:02 +01:00
parent 2d40a35a48
commit ecea75cf5f
8 changed files with 253 additions and 58 deletions

View file

@ -1,7 +1,7 @@
CFLAGS=-g -std=c11 -pedantic # -Wall -Werror
LDFLAGS=-lpthread
CC=gcc
OBJECTS=main.o gamepad_output.o imu_output.o
OBJECTS=main.o gamepad_output.o imu_output.o input_dev.o output_dev.o
TARGET=rogue_enemy
all: $(TARGET)

View file

@ -6,6 +6,11 @@
void *imu_thread_func(void *ptr) {
output_dev_t *out_dev = (output_dev_t*)ptr;
/*timeval now = {0};
gettimeofday(&now, NULL);
secAtInit = now.tv_sec;
usecAtInit = now.tv_usec;*/
for (;;) {
pthread_mutex_lock(&out_dev->ctrl_mutex);

41
input_dev.c Normal file
View file

@ -0,0 +1,41 @@
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include "input_dev.h"
int open_and_hide_input() {
int fd = -1;
char buf[256];
fd = open("/dev/input/event3", O_RDONLY);
if (fd == -1) {
perror("open_port: Unable to open /dev/ttyAMA0 - ");
return(-1);
}
// Turn off blocking for reads, use (fd, F_SETFL, FNDELAY) if you want that
//fcntl(fd, F_SETFL, 0);
while(1){
int n = read(fd, (void*)buf, 255);
if (n < 0) {
perror("Read failed - ");
return -1;
} else if (n == 0) {
printf("No data on port\n");
} else {
buf[n] = '\0';
printf("%i bytes read : %s", n, buf);
}
sleep(1);
printf("i'm still doing something");
}
close(fd);
return fd;
}

View file

@ -1,12 +1,12 @@
#pragma once
#include <inttypes.h>
#include <pthread.h>
#include "rogue_enemy.h"
#define INPUT_DEV_CTRL_FLAG_EXIT 0x00000001U
#define INPUT_DEV_CTRL_FLAG_DATA 0x00000002U
typedef struct input_dev {
pthread_mutex_t ctrl_mutex;
uint32_t crtl_flags;
} input_dev_t;
} input_dev_t;
int open_and_hide_input();

81
main.c
View file

@ -1,11 +1,4 @@
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include "imu_output.h"
#include "gamepad_output.h"
@ -22,27 +15,42 @@ output_dev_t gamepadd_dev = {
.crtl_flags = 0x00000000U,
};
void request_termination() {
pthread_mutex_lock(&imu_dev.ctrl_mutex);
imu_dev.crtl_flags |= OUTPUT_DEV_CTRL_FLAG_EXIT;
pthread_mutex_unlock(&imu_dev.ctrl_mutex);
pthread_mutex_lock(&gamepadd_dev.ctrl_mutex);
gamepadd_dev.crtl_flags |= OUTPUT_DEV_CTRL_FLAG_EXIT;
pthread_mutex_unlock(&gamepadd_dev.ctrl_mutex);
}
void sig_handler(int signo)
{
if (signo == SIGINT) {
pthread_mutex_lock(&imu_dev.ctrl_mutex);
imu_dev.crtl_flags |= OUTPUT_DEV_CTRL_FLAG_EXIT;
pthread_mutex_unlock(&imu_dev.ctrl_mutex);
pthread_mutex_lock(&gamepadd_dev.ctrl_mutex);
gamepadd_dev.crtl_flags |= OUTPUT_DEV_CTRL_FLAG_EXIT;
pthread_mutex_unlock(&gamepadd_dev.ctrl_mutex);
request_termination();
printf("received SIGINT\n");
}
}
int main(int argc, char ** argv) {
imu_dev.fd = create_imu("/dev/uinput", "Virtual IMU - ROGueENEMY");
if (imu_dev.fd < 0) {
fprintf(stderr, "Unable to create IMU virtual device\n");
return EXIT_FAILURE;
}
gamepadd_dev.fd = create_gamepad("/dev/uinput", "Virtual Controller - ROGueENEMY");
if (gamepadd_dev.fd < 0) {
close(imu_dev.fd);
fprintf(stderr, "Unable to create gamepad virtual device\n");
return EXIT_FAILURE;
}
__sighandler_t sigint_hndl = signal(SIGINT, sig_handler);
if (sigint_hndl == SIG_ERR) {
fprintf(stderr, "Error registering SIGINT handler");
return -1;
fprintf(stderr, "Error registering SIGINT handler\n");
return EXIT_FAILURE;
}
int ret = 0;
@ -51,15 +59,17 @@ int main(int argc, char ** argv) {
int imu_thread_creation = pthread_create(&imu_thread, NULL, imu_thread_func, (void*)(&imu_dev));
if (imu_thread_creation != 0) {
fprintf(stderr, "Error creating IMU output thread: %d", imu_thread_creation);
fprintf(stderr, "Error creating IMU output thread: %d\n", imu_thread_creation);
ret = -1;
request_termination();
goto imu_thread_err;
}
int gamepad_thread_creation = pthread_create(&gamepad_thread, NULL, gamepad_thread_func, (void*)(&gamepadd_dev));
if (gamepad_thread_creation != 0) {
fprintf(stderr, "Error creating gamepad output thread: %d", gamepad_thread_creation);
fprintf(stderr, "Error creating gamepad output thread: %d\n", gamepad_thread_creation);
ret = -1;
request_termination();
goto gamepad_thread_err;
}
@ -69,34 +79,5 @@ gamepad_thread_err:
pthread_join(imu_thread, NULL);
imu_thread_err:
return ret;
int fd;
char buf[256];
fd = open("/dev/input/event3", O_RDONLY);
if (fd == -1) {
perror("open_port: Unable to open /dev/ttyAMA0 - ");
return(-1);
}
// Turn off blocking for reads, use (fd, F_SETFL, FNDELAY) if you want that
//fcntl(fd, F_SETFL, 0);
while(1){
int n = read(fd, (void*)buf, 255);
if (n < 0) {
perror("Read failed - ");
return -1;
} else if (n == 0) {
printf("No data on port\n");
} else {
buf[n] = '\0';
printf("%i bytes read : %s", n, buf);
}
sleep(1);
printf("i'm still doing something");
}
close(fd);
return 0;
return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}

139
output_dev.c Normal file
View file

@ -0,0 +1,139 @@
#include "output_dev.h"
int create_imu(const char* uinput_path, const char* name) {
int fd = open(uinput_path, O_WRONLY | O_NONBLOCK);
if(fd < 0) {
fd = -1;
close(fd);
goto create_imu_err;
}
struct uinput_setup dev = {0};
if (strlen(name) < UINPUT_MAX_NAME_SIZE) {
strcpy(dev.name, name);
} else {
strncpy(dev.name, name, UINPUT_MAX_NAME_SIZE-1);
}
dev.id.bustype = BUS_VIRTUAL;
dev.id.vendor = OUTPUT_DEV_VENDOR_ID;
dev.id.product = OUTPUT_DEV_PRODUCT_ID;
ioctl(fd, UI_SET_PROPBIT, INPUT_PROP_ACCELEROMETER);
ioctl(fd, UI_SET_EVBIT, EV_ABS);
//ioctl(fd, UI_SET_EVBIT, EV_KEY);
ioctl(fd, UI_SET_EVBIT, EV_MSC);
ioctl(fd, UI_SET_MSCBIT, MSC_TIMESTAMP);
ioctl(fd, UI_SET_ABSBIT, ABS_X);
ioctl(fd, UI_SET_ABSBIT, ABS_Y);
ioctl(fd, UI_SET_ABSBIT, ABS_Z);
ioctl(fd, UI_SET_ABSBIT, ABS_RX);
ioctl(fd, UI_SET_ABSBIT, ABS_RY);
ioctl(fd, UI_SET_ABSBIT, ABS_RZ);
//ioctl(fd, UI_SET_KEYBIT, BTN_TRIGGER);
//ioctl(fd, UI_SET_KEYBIT, BTN_THUMB);
struct uinput_abs_setup devAbsX = {0};
devAbsX.code = ABS_X;
devAbsX.absinfo.minimum = -ACCEL_RANGE;
devAbsX.absinfo.maximum = ACCEL_RANGE;
devAbsX.absinfo.resolution = 255; // 255 units = 1g
devAbsX.absinfo.fuzz = 5;
devAbsX.absinfo.flat = 0;
if(ioctl(fd, UI_ABS_SETUP, &devAbsX) < 0) {
fd = -1;
close(fd);
goto create_imu_err;
}
struct uinput_abs_setup devAbsY = {0};
devAbsY.code = ABS_Y;
devAbsY.absinfo.minimum = -ACCEL_RANGE;
devAbsY.absinfo.maximum = ACCEL_RANGE;
devAbsY.absinfo.resolution = 255; // 255 units = 1g
devAbsY.absinfo.fuzz = 5;
devAbsY.absinfo.flat = 0;
if(ioctl(fd, UI_ABS_SETUP, &devAbsY) < 0) {
fd = -1;
close(fd);
goto create_imu_err;
}
struct uinput_abs_setup devAbsZ = {0};
devAbsZ.code = ABS_Z;
devAbsZ.absinfo.minimum = -ACCEL_RANGE;
devAbsZ.absinfo.maximum = ACCEL_RANGE;
devAbsZ.absinfo.resolution = 255; // 255 units = 1g
devAbsZ.absinfo.fuzz = 5;
devAbsZ.absinfo.flat = 0;
if(ioctl(fd, UI_ABS_SETUP, &devAbsZ) < 0) {
fd = -1;
close(fd);
goto create_imu_err;
}
struct uinput_abs_setup devAbsRX = {0};
devAbsRX.code = ABS_RX;
devAbsRX.absinfo.minimum = -GYRO_RANGE;
devAbsRX.absinfo.maximum = GYRO_RANGE;
devAbsRX.absinfo.resolution = 1; // 1 unit = 1 degree/s
devAbsRX.absinfo.fuzz = 0;
devAbsRX.absinfo.flat = GYRO_DEADZONE;
if(ioctl(fd, UI_ABS_SETUP, &devAbsRX) < 0) {
fd = -1;
close(fd);
goto create_imu_err;
}
struct uinput_abs_setup devAbsRY = {0};
devAbsRY.code = ABS_RY;
devAbsRY.absinfo.minimum = -GYRO_RANGE;
devAbsRY.absinfo.maximum = GYRO_RANGE;
devAbsRY.absinfo.resolution = 1; // 1 unit = 1 degree/s
devAbsRY.absinfo.fuzz = 0;
devAbsRY.absinfo.flat = GYRO_DEADZONE;
if(ioctl(fd, UI_ABS_SETUP, &devAbsRY) < 0) {
fd = -1;
close(fd);
goto create_imu_err;
}
struct uinput_abs_setup devAbsRZ = {0};
devAbsRZ.code = ABS_RZ;
devAbsRZ.absinfo.minimum = -GYRO_RANGE;
devAbsRZ.absinfo.maximum = GYRO_RANGE;
devAbsRZ.absinfo.resolution = 1; // 1 unit = 1 degree/s
devAbsRZ.absinfo.fuzz = 0;
devAbsRZ.absinfo.flat = GYRO_DEADZONE;
if(ioctl(fd, UI_ABS_SETUP, &devAbsRZ) < 0) {
fd = -1;
close(fd);
goto create_imu_err;
}
if(ioctl(fd, UI_DEV_SETUP, &dev) < 0) {
fd = -1;
close(fd);
goto create_imu_err;
}
if(ioctl(fd, UI_DEV_CREATE) < 0) {
fd = -1;
close(fd);
goto create_imu_err;
}
int64_t secAtInit = 0;
int64_t usecAtInit = 0;
create_imu_err:
return fd;
}
int create_gamepad(const char* uinput_path, const char* name) {
create_gamepad_err:
return -1;
}

View file

@ -1,14 +1,28 @@
#pragma once
#include <inttypes.h>
#include <pthread.h>
#include "rogue_enemy.h"
#define OUTPUT_DEV_VENDOR_ID 0x4532
#define OUTPUT_DEV_PRODUCT_ID 0x0924
#define OUTPUT_DEV_CTRL_FLAG_EXIT 0x00000001U
#define OUTPUT_DEV_CTRL_FLAG_DATA 0x00000002U
#define ACCEL_RANGE 512
#define GYRO_RANGE 2000 // max range is +/- 35 radian/s
#define GYRO_DEADZONE 1 // degrees/s to count as zero movement
typedef struct output_dev {
int fd;
pthread_mutex_t ctrl_mutex;
uint32_t crtl_flags;
} output_dev_t;
uint32_t max_events;
uint32_t events_count;
struct input_event events_list;
} output_dev_t;
int create_imu(const char* uinput_path, const char* name);
int create_gamepad(const char* uinput_path, const char* name);

15
rogue_enemy.h Normal file
View file

@ -0,0 +1,15 @@
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <fcntl.h>
#include <time.h>
#include <errno.h>
#include <sys/time.h>
#include <unistd.h>
#include <string.h>
#include <linux/uinput.h>
#include <linux/input.h>
#include <pthread.h>