add slots and fix things
This commit is contained in:
parent
6973ba305b
commit
6f76aef797
35
README.md
35
README.md
|
@ -39,9 +39,13 @@ and a client with this one:
|
|||
|
||||
```json
|
||||
{
|
||||
"controllers": [
|
||||
"slots": [
|
||||
{
|
||||
"tag": ["Controller"]
|
||||
"controllers": [
|
||||
{
|
||||
"tag": "Controller"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -104,17 +108,24 @@ The client configuration specifies what devices the client wants as well as unde
|
|||
```js
|
||||
// Any property can be ommitted, unless specified otherwise
|
||||
// The values listed here are examples
|
||||
// Comments are here to document things, they are not allowed in the actual config
|
||||
{
|
||||
"controllers": [
|
||||
// (required) The slots the client has
|
||||
"slots": [
|
||||
{
|
||||
// (required) Accepted tags of the device to request
|
||||
"tag": ["Joystick"],
|
||||
// (default: 6969) Vendor code for the virtual device, expects a 4 long hex string
|
||||
"vendor": "dead",
|
||||
// (default: 0420) Product code for the virtual device, expects a 4 long hex string
|
||||
"product": "beef",
|
||||
// (default: "JSFW Virtual Device") Name for the virtual device
|
||||
"name": "Emanuel"
|
||||
// (required) The controllers that are accepted in that slot
|
||||
"controllers": [
|
||||
{
|
||||
// (required) Accepted tags of the device to request
|
||||
"tag": ["Joystick"],
|
||||
// (default: 6969) Vendor code for the virtual device, expects a 4 long hex string
|
||||
"vendor": "dead",
|
||||
// (default: 0420) Product code for the virtual device, expects a 4 long hex string
|
||||
"product": "beef",
|
||||
// (default: "JSFW Virtual Device") Name for the virtual device
|
||||
"name": "Emanuel"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
// (default: "/tmp/jsfw_fifo") Path to the fifo for hidraw
|
||||
|
@ -130,7 +141,7 @@ Additionaly messages can be sent to the client's fifo to change the led colors (
|
|||
// Any property can be ommitted, unless specified otherwise
|
||||
// The values listed here are examples
|
||||
{
|
||||
// (default: 0) Index of the device to send the state to, this is the index in the client configuration controllers list
|
||||
// (default: 0) Index of the slot to send the state to, this is the index in the client configuration controllers list
|
||||
"index": 1,
|
||||
// (default: [0, 0]) Setting for the rumble, values are in range 0-255 first element is small rumble, second is big
|
||||
"rumble": [255, 0],
|
||||
|
|
92
client.c
92
client.c
|
@ -72,7 +72,7 @@ static const JSONAdapter ControllerStateAdapter = {
|
|||
};
|
||||
|
||||
static const JSONPropertyAdapter ControllerAdapterProps[] = {
|
||||
{".tag[]", &StringAdapter, offsetof(ClientController, tags), default_to_null, NULL },
|
||||
{".tag", &StringAdapter, offsetof(ClientController, tag), default_to_null, NULL },
|
||||
{".vendor", &StringAdapter, offsetof(ClientController, device_vendor), default_vendor, tsf_hex_to_i32},
|
||||
{".product", &StringAdapter, offsetof(ClientController, device_product), default_product, tsf_hex_to_i32},
|
||||
{".name", &StringAdapter, offsetof(ClientController, device_name), default_name, NULL },
|
||||
|
@ -83,10 +83,19 @@ static const JSONAdapter ControllerAdapter = {
|
|||
.size = sizeof(ClientController),
|
||||
};
|
||||
|
||||
static const JSONPropertyAdapter SlotAdapterProps[] = {
|
||||
{".controllers[]", &ControllerAdapter, offsetof(ClientSlot, controllers), default_to_null, NULL},
|
||||
};
|
||||
static const JSONAdapter SlotAdapter = {
|
||||
.props = SlotAdapterProps,
|
||||
.prop_count = sizeof(SlotAdapterProps) / sizeof(JSONPropertyAdapter),
|
||||
.size = sizeof(ClientSlot),
|
||||
};
|
||||
|
||||
static const JSONPropertyAdapter ClientConfigAdapterProps[] = {
|
||||
{".controllers[]", &ControllerAdapter, offsetof(ClientConfig, controllers), default_to_null, NULL },
|
||||
{".fifo_path", &StringAdapter, offsetof(ClientConfig, fifo_path), default_fifo_path, NULL },
|
||||
{".retry_delay", &NumberAdapter, offsetof(ClientConfig, retry_delay), default_retry_delay, tsf_numsec_to_timespec}
|
||||
{".slots[]", &SlotAdapter, offsetof(ClientConfig, slots), default_to_null, NULL },
|
||||
{".fifo_path", &StringAdapter, offsetof(ClientConfig, fifo_path), default_fifo_path, NULL },
|
||||
{".retry_delay", &NumberAdapter, offsetof(ClientConfig, retry_delay), default_retry_delay, tsf_numsec_to_timespec}
|
||||
};
|
||||
static const JSONAdapter ConfigAdapter = {
|
||||
.props = ClientConfigAdapterProps,
|
||||
|
@ -99,23 +108,23 @@ static void print_config() {
|
|||
printf("CLIENT: Config\n");
|
||||
printf(" fifo_path: %s\n", config.fifo_path);
|
||||
printf(" retry_delay: %fs\n", timespec_to_double(&config.retry_delay));
|
||||
printf(" controllers: \n");
|
||||
for (size_t i = 0; i < config.controller_count; i++) {
|
||||
ClientController *ctr = &config.controllers[i];
|
||||
printf(" - tags: ['%s'", ctr->tags[0]);
|
||||
for (size_t j = 1; j < ctr->tag_count; j++) {
|
||||
printf(", '%s'", ctr->tags[j]);
|
||||
printf(" slots: \n");
|
||||
for (size_t i = 0; i < config.slot_count; i++) {
|
||||
ClientSlot *slot = &config.slots[i];
|
||||
printf(" - controllers:\n");
|
||||
for (size_t j = 0; j < slot->controller_count; j++) {
|
||||
ClientController *ctr = &slot->controllers[j];
|
||||
printf(" - tag: '%s'\n", ctr->tag);
|
||||
printf(" name: %s\n", ctr->device_name);
|
||||
printf(" vendor: %04x\n", ctr->device_vendor);
|
||||
printf(" product: %04x\n", ctr->device_product);
|
||||
}
|
||||
printf("]\n");
|
||||
printf(" name: %s\n", ctr->device_name);
|
||||
printf(" vendor: %04x\n", ctr->device_vendor);
|
||||
printf(" product: %04x\n", ctr->device_product);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void destroy_devices(void) {
|
||||
for (int i = 0; i < config.controller_count; i++) {
|
||||
for (int i = 0; i < config.slot_count; i++) {
|
||||
int fd = *(int *)vec_get(&devices_fd, i);
|
||||
MessageDeviceInfo *info = vec_get(&devices_info, i);
|
||||
|
||||
|
@ -135,14 +144,14 @@ bool device_exists(int index) {
|
|||
return info->code == DeviceInfo;
|
||||
}
|
||||
|
||||
void device_destroy(int index) {
|
||||
if (index >= devices_info.len) {
|
||||
void device_destroy(int slot) {
|
||||
if (slot >= devices_info.len) {
|
||||
return;
|
||||
}
|
||||
|
||||
int fd = *(int *)vec_get(&devices_fd, index);
|
||||
int fd = *(int *)vec_get(&devices_fd, slot);
|
||||
|
||||
MessageDeviceInfo *info = vec_get(&devices_info, index);
|
||||
MessageDeviceInfo *info = vec_get(&devices_info, slot);
|
||||
|
||||
if (info->code == DeviceInfo) {
|
||||
ioctl(fd, UI_DEV_DESTROY);
|
||||
|
@ -151,14 +160,14 @@ void device_destroy(int index) {
|
|||
}
|
||||
|
||||
void device_init(MessageDeviceInfo *dev) {
|
||||
if (dev->index >= devices_info.len) {
|
||||
if (dev->slot >= devices_info.len) {
|
||||
printf("CLIENT: Got wrong device index\n");
|
||||
return;
|
||||
}
|
||||
|
||||
device_destroy(dev->index);
|
||||
device_destroy(dev->slot);
|
||||
|
||||
int fd = *(int *)vec_get(&devices_fd, dev->index);
|
||||
int fd = *(int *)vec_get(&devices_fd, dev->slot);
|
||||
|
||||
// Abs
|
||||
if (dev->abs_count > 0) {
|
||||
|
@ -193,7 +202,7 @@ void device_init(MessageDeviceInfo *dev) {
|
|||
}
|
||||
}
|
||||
|
||||
ClientController *ctr = &config.controllers[dev->index];
|
||||
ClientController *ctr = &config.slots[dev->slot].controllers[dev->index];
|
||||
|
||||
struct uinput_setup setup = {0};
|
||||
|
||||
|
@ -206,10 +215,10 @@ void device_init(MessageDeviceInfo *dev) {
|
|||
ioctl(fd, UI_DEV_SETUP, &setup);
|
||||
ioctl(fd, UI_DEV_CREATE);
|
||||
|
||||
MessageDeviceInfo *dst = vec_get(&devices_info, dev->index);
|
||||
MessageDeviceInfo *dst = vec_get(&devices_info, dev->slot);
|
||||
|
||||
memcpy(dst, dev, sizeof(MessageDeviceInfo));
|
||||
printf("CLIENT: Got device [%d]: '%s' (abs: %d, rel: %d, key: %d)\n", dev->index, ctr->device_name, dev->abs_count,
|
||||
printf("CLIENT: Got device [%d]: '%s' (abs: %d, rel: %d, key: %d)\n", dev->slot, ctr->device_name, dev->abs_count,
|
||||
dev->rel_count, dev->key_count);
|
||||
}
|
||||
|
||||
|
@ -231,12 +240,12 @@ bool device_emit(int index, uint16_t type, uint16_t id, uint32_t value) {
|
|||
|
||||
// Update device with report
|
||||
void device_handle_report(MessageDeviceReport *report) {
|
||||
if (!device_exists(report->index)) {
|
||||
printf("CLIENT: [%d] Got report before device info\n", report->index);
|
||||
if (!device_exists(report->slot)) {
|
||||
printf("CLIENT: [%d] Got report before device info\n", report->slot);
|
||||
return;
|
||||
}
|
||||
|
||||
MessageDeviceInfo *info = vec_get(&devices_info, report->index);
|
||||
MessageDeviceInfo *info = vec_get(&devices_info, report->slot);
|
||||
|
||||
if (report->abs_count != info->abs_count || report->rel_count != info->rel_count || report->key_count != info->key_count) {
|
||||
printf("CLIENT: Report doesn't match with device info\n");
|
||||
|
@ -244,25 +253,25 @@ void device_handle_report(MessageDeviceReport *report) {
|
|||
}
|
||||
|
||||
for (int i = 0; i < report->abs_count; i++) {
|
||||
if (device_emit(report->index, EV_ABS, info->abs_id[i], report->abs[i]) != 0) {
|
||||
if (device_emit(report->slot, EV_ABS, info->abs_id[i], report->abs[i]) != 0) {
|
||||
printf("CLIENT: Error writing abs event to uinput\n");
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < report->rel_count; i++) {
|
||||
if (device_emit(report->index, EV_REL, info->rel_id[i], report->rel[i]) != 0) {
|
||||
if (device_emit(report->slot, EV_REL, info->rel_id[i], report->rel[i]) != 0) {
|
||||
printf("CLIENT: Error writing rel event to uinput\n");
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < report->key_count; i++) {
|
||||
if (device_emit(report->index, EV_KEY, info->key_id[i], (uint32_t)(!report->key[i]) - 1) != 0) {
|
||||
if (device_emit(report->slot, EV_KEY, info->key_id[i], (uint32_t)(!report->key[i]) - 1) != 0) {
|
||||
printf("CLIENT: Error writing key event to uinput\n");
|
||||
}
|
||||
}
|
||||
// Reports are sent by the server every time the server receives an EV_SYN from the physical device, so we
|
||||
// send one when we receive the report to match
|
||||
device_emit(report->index, EV_SYN, 0, 0);
|
||||
device_emit(report->slot, EV_SYN, 0, 0);
|
||||
}
|
||||
|
||||
void setup_devices(void) {
|
||||
|
@ -272,7 +281,7 @@ void setup_devices(void) {
|
|||
MessageDeviceInfo no_info = {0};
|
||||
no_info.code = NoMessage;
|
||||
|
||||
for (int i = 0; i < config.controller_count; i++) {
|
||||
for (int i = 0; i < config.slot_count; i++) {
|
||||
int fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
|
||||
if (fd < 0) {
|
||||
perror("CLIENT: Can't open /dev/uinput, aborting now");
|
||||
|
@ -371,19 +380,19 @@ void setup_server(char *address, uint16_t port) {
|
|||
}
|
||||
|
||||
void build_device_request(void) {
|
||||
TagList * reqs = malloc(config.controller_count * sizeof(TagList *));
|
||||
for (int i = 0; i < config.controller_count; i++) {
|
||||
TagList * req = &reqs[i];
|
||||
req->count = config.controllers[i].tag_count;
|
||||
req->tags = malloc(req->count * sizeof(char *));
|
||||
TagList *reqs = malloc(config.slot_count * sizeof(TagList));
|
||||
for (int i = 0; i < config.slot_count; i++) {
|
||||
TagList *req = &reqs[i];
|
||||
req->count = config.slots[i].controller_count;
|
||||
req->tags = malloc(req->count * sizeof(char *));
|
||||
|
||||
for (int j = 0; j < req->count; j++) {
|
||||
req->tags[j] = config.controllers[i].tags[j];
|
||||
req->tags[j] = config.slots[i].controllers[j].tag;
|
||||
}
|
||||
}
|
||||
|
||||
device_request.code = Request;
|
||||
device_request.request_count = config.controller_count;
|
||||
device_request.request_count = config.slot_count;
|
||||
device_request.requests = reqs;
|
||||
}
|
||||
|
||||
|
@ -490,12 +499,11 @@ void client_run(char *address, uint16_t port, char *config_path) {
|
|||
recv(sock, buf, msg_len, 0);
|
||||
|
||||
if (message.code == DeviceInfo) {
|
||||
if (device_exists(message.device_info.index)) {
|
||||
if (device_exists(message.device_info.slot)) {
|
||||
printf("CLIENT: Got more than one device info for same device\n");
|
||||
}
|
||||
|
||||
device_init((MessageDeviceInfo *)&message);
|
||||
printf("CLIENT: Got device %d\n", message.device_info.index);
|
||||
} else if (message.code == DeviceReport) {
|
||||
device_handle_report((MessageDeviceReport *)&message);
|
||||
} else if (message.code == DeviceDestroy) {
|
||||
|
|
8
client.h
8
client.h
|
@ -7,8 +7,7 @@
|
|||
void client_run(char *address, uint16_t port, char *config_path);
|
||||
|
||||
typedef struct {
|
||||
char **tags;
|
||||
size_t tag_count;
|
||||
char *tag;
|
||||
int32_t device_vendor;
|
||||
int32_t device_product;
|
||||
char *device_name;
|
||||
|
@ -17,6 +16,11 @@ typedef struct {
|
|||
typedef struct {
|
||||
ClientController *controllers;
|
||||
size_t controller_count;
|
||||
} ClientSlot;
|
||||
|
||||
typedef struct {
|
||||
ClientSlot *slots;
|
||||
size_t slot_count;
|
||||
|
||||
char *fifo_path;
|
||||
struct timespec retry_delay;
|
||||
|
|
83
hid.c
83
hid.c
|
@ -167,49 +167,55 @@ bool filter_event(int fd, char *event, ControllerFilter *filter, uniq_t uniq) {
|
|||
|
||||
// Initialize vectors for polling
|
||||
void poll_devices_init(void) {
|
||||
known_devices = vec_of(Controller);
|
||||
cloneable_devices = vec_of(Controller *);
|
||||
available_devices = vec_of(Controller *);
|
||||
known_devices = vec_of(uint64_t);
|
||||
cloneable_devices = vec_of(Controller);
|
||||
available_devices = vec_of(Controller);
|
||||
}
|
||||
|
||||
// Check if tag match any of the tags specified in the tags array (of length tag_count)
|
||||
bool match_tags(char *tag, char **tags, size_t tag_count) {
|
||||
// Find index of tag that matches any of the tags specified in the tags array (of length tag_count), returns -1 otherwise
|
||||
static int match_tags(char *tag, char **tags, size_t tag_count) {
|
||||
for (int i = 0; i < tag_count; i++) {
|
||||
if (strcmp(tag, tags[i]) == 0) {
|
||||
return true;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Block to get a device, this is thread safe
|
||||
// stop: additional condition to check before doing anything,
|
||||
// if the condition is ever found to be true the function will return immediately with a NULL pointer.
|
||||
Controller *get_device(char **tags, size_t tag_count, bool *stop) {
|
||||
bool get_device(char **tags, size_t tag_count, bool *stop, Controller *res, uint8_t *ref_index) {
|
||||
// Check if we can get one right away
|
||||
pthread_mutex_lock(&devices_mutex);
|
||||
|
||||
while (1) {
|
||||
if (*stop) {
|
||||
pthread_mutex_unlock(&devices_mutex);
|
||||
return NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < available_devices.len; i++) {
|
||||
Controller *c = *(Controller **)vec_get(&available_devices, i);
|
||||
if (match_tags(c->ctr.tag, tags, tag_count)) {
|
||||
Controller *c = vec_get(&available_devices, i);
|
||||
int index = match_tags(c->ctr.tag, tags, tag_count);
|
||||
if (index >= 0) {
|
||||
*ref_index = index;
|
||||
*res = *c;
|
||||
vec_remove(&available_devices, i, NULL);
|
||||
pthread_mutex_unlock(&devices_mutex);
|
||||
return c;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < cloneable_devices.len; i++) {
|
||||
Controller *c = *(Controller **)vec_get(&cloneable_devices, i);
|
||||
if (match_tags(c->ctr.tag, tags, tag_count)) {
|
||||
Controller *c = vec_get(&cloneable_devices, i);
|
||||
int index = match_tags(c->ctr.tag, tags, tag_count);
|
||||
if (index >= 0) {
|
||||
*ref_index = index;
|
||||
*res = *c;
|
||||
pthread_mutex_unlock(&devices_mutex);
|
||||
return c;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -226,7 +232,7 @@ void return_device(Controller *c) {
|
|||
}
|
||||
|
||||
pthread_mutex_lock(&devices_mutex);
|
||||
vec_push(&available_devices, &c);
|
||||
vec_push(&available_devices, c);
|
||||
// Signal that there are new devices
|
||||
pthread_cond_broadcast(&devices_cond);
|
||||
pthread_mutex_unlock(&devices_mutex);
|
||||
|
@ -234,26 +240,25 @@ void return_device(Controller *c) {
|
|||
|
||||
// Forget about a broken device. This invalidates the reference to the controller
|
||||
void forget_device(Controller *c) {
|
||||
pthread_mutex_lock(&known_devices_mutex);
|
||||
|
||||
// If controller is cloneable we need to remove it from the cloneable list
|
||||
if (c->ctr.duplicate) {
|
||||
pthread_mutex_lock(&devices_mutex);
|
||||
for (int i = 0; i < cloneable_devices.len; i++) {
|
||||
Controller *d = *(Controller **)vec_get(&cloneable_devices, i);
|
||||
if (d->dev.uniq == c->dev.uniq) {
|
||||
if (d->dev.id == c->dev.id) {
|
||||
vec_remove(&cloneable_devices, i, NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&devices_mutex);
|
||||
}
|
||||
|
||||
// Free the name if it was allocated
|
||||
if (c->dev.name != NULL && c->dev.name != DEVICE_DEFAULT_NAME) {
|
||||
printf("HID: Forgetting device '%s' (%016lx)\n", c->dev.name, c->dev.uniq);
|
||||
printf("HID: Forgetting device '%s' (%lu)\n", c->dev.name, c->dev.id);
|
||||
free(c->dev.name);
|
||||
} else {
|
||||
printf("HID: Forgetting device %016lx\n", c->dev.uniq);
|
||||
printf("HID: Forgetting device %lu\n", c->dev.id);
|
||||
}
|
||||
|
||||
// try to close the file descriptor, they may be already closed if the device was unpugged.
|
||||
|
@ -261,10 +266,9 @@ void forget_device(Controller *c) {
|
|||
close(c->dev.hidraw);
|
||||
|
||||
// Safely remove device from the known device list
|
||||
pthread_mutex_lock(&known_devices_mutex);
|
||||
for (int i = 0; i < known_devices.len; i++) {
|
||||
Controller *d = vec_get(&known_devices, i);
|
||||
if (d->dev.uniq == c->dev.uniq) {
|
||||
uint64_t *id = vec_get(&known_devices, i);
|
||||
if (*id == c->dev.id) {
|
||||
vec_remove(&known_devices, i, NULL);
|
||||
break;
|
||||
}
|
||||
|
@ -272,6 +276,8 @@ void forget_device(Controller *c) {
|
|||
pthread_mutex_unlock(&known_devices_mutex);
|
||||
}
|
||||
|
||||
uint64_t parse_event_name(const char *event) { return atol(event + 5); }
|
||||
|
||||
// Find all available devices and pick up on new ones
|
||||
void poll_devices(void) {
|
||||
// loop over all entries of /sys/class/input
|
||||
|
@ -287,6 +293,7 @@ void poll_devices(void) {
|
|||
PhysicalDevice dev;
|
||||
dev.hidraw = -1;
|
||||
dev.uniq = 0;
|
||||
dev.id = parse_event_name(input->d_name);
|
||||
|
||||
// Open /dev/input/eventXX
|
||||
{
|
||||
|
@ -340,21 +347,14 @@ void poll_devices(void) {
|
|||
}
|
||||
}
|
||||
|
||||
// Get the id
|
||||
{
|
||||
struct input_id id;
|
||||
ioctl(dev.event, EVIOCGID, &id);
|
||||
dev.id = *(uint64_t *)&id;
|
||||
}
|
||||
|
||||
// Check if we already know of this device
|
||||
{
|
||||
found = false;
|
||||
|
||||
pthread_mutex_lock(&known_devices_mutex);
|
||||
for (int i = 0; i < known_devices.len; i++) {
|
||||
Controller *c = vec_get(&known_devices, i);
|
||||
if (c->dev.uniq == dev.uniq) {
|
||||
uint64_t *id = vec_get(&known_devices, i);
|
||||
if (*id == dev.id) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
@ -415,25 +415,20 @@ void poll_devices(void) {
|
|||
Controller c = {.dev = dev, .ctr = *ctr};
|
||||
|
||||
pthread_mutex_lock(&known_devices_mutex);
|
||||
// Index of the device in known_devices
|
||||
int index = known_devices.len;
|
||||
vec_push(&known_devices, &c);
|
||||
vec_push(&known_devices, &c.dev.id);
|
||||
pthread_mutex_unlock(&known_devices_mutex);
|
||||
|
||||
// Pointer to the device in known_devices
|
||||
Controller *p = vec_get(&known_devices, index);
|
||||
|
||||
printf("HID: New device, %s [%s] (%s: %016lx)\n", name, ctr->tag, input->d_name, dev.uniq);
|
||||
printf("HID: New device, %s [%s] (%s: %lu)\n", name, ctr->tag, input->d_name, dev.id);
|
||||
|
||||
if (ctr->duplicate) {
|
||||
pthread_mutex_lock(&devices_mutex);
|
||||
vec_push(&cloneable_devices, &p);
|
||||
vec_push(&cloneable_devices, &c);
|
||||
// Signal that there are new cloneable devices
|
||||
pthread_cond_broadcast(&devices_cond);
|
||||
pthread_mutex_unlock(&devices_mutex);
|
||||
} else {
|
||||
pthread_mutex_lock(&devices_mutex);
|
||||
vec_push(&available_devices, &p);
|
||||
vec_push(&available_devices, &c);
|
||||
// Signal that there are new devices
|
||||
pthread_cond_broadcast(&devices_cond);
|
||||
pthread_mutex_unlock(&devices_mutex);
|
||||
|
@ -452,11 +447,11 @@ void poll_devices(void) {
|
|||
// "Execute" a MessageControllerState: set the led color, rumble and flash using the hidraw interface (Dualshock 4 only)
|
||||
void apply_controller_state(Controller *c, MessageControllerState *state) {
|
||||
if (c->ctr.ps4_hidraw && c->dev.hidraw < 0) {
|
||||
printf("HID: Trying to apply controller state on incompatible device (%016lx)\n", c->dev.uniq);
|
||||
printf("HID: Trying to apply controller state on incompatible device (%lu)\n", c->dev.id);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("HID: (%016lx) Controller state: #%02x%02x%02x flash: (%d, %d) rumble: (%d, %d)\n", c->dev.uniq, state->led[0],
|
||||
printf("HID: (%lu) Controller state: #%02x%02x%02x flash: (%d, %d) rumble: (%d, %d)\n", c->dev.id, state->led[0],
|
||||
state->led[1], state->led[2], state->flash_on, state->flash_off, state->small_rumble, state->big_rumble);
|
||||
|
||||
uint8_t buf[32] = {0x05, 0xff, 0x00, 0x00};
|
||||
|
|
12
hid.h
12
hid.h
|
@ -9,7 +9,7 @@
|
|||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// Unique identifier for devices (provided by linux), May be the mac address
|
||||
// Unique identifier for devices (provided by linux)
|
||||
typedef uint64_t uniq_t;
|
||||
|
||||
// Mapping to go from index to id of events
|
||||
|
@ -38,10 +38,10 @@ typedef struct {
|
|||
ServerConfigController ctr;
|
||||
} Controller;
|
||||
|
||||
void *hid_thread(void *arg);
|
||||
void return_device(Controller *c);
|
||||
void forget_device(Controller *c);
|
||||
Controller *get_device(char **tags, size_t tag_count, bool *stop);
|
||||
void apply_controller_state(Controller *c, MessageControllerState *state);
|
||||
void *hid_thread(void *arg);
|
||||
void return_device(Controller *c);
|
||||
void forget_device(Controller *c);
|
||||
bool get_device(char **tags, size_t tag_count, bool *stop, Controller *res, uint8_t *index);
|
||||
void apply_controller_state(Controller *c, MessageControllerState *state);
|
||||
|
||||
#endif
|
||||
|
|
80
net.c
80
net.c
|
@ -30,23 +30,26 @@ int msg_deserialize(const uint8_t *buf, size_t len, Message *restrict dst) {
|
|||
MessageCode code = (MessageCode)code_byte;
|
||||
uint32_t size = 0;
|
||||
|
||||
uint16_t abs, rel, key, index, *buf16;
|
||||
uint16_t abs, rel, key, *buf16;
|
||||
uint8_t index, slot;
|
||||
|
||||
switch (code) {
|
||||
case DeviceInfo:
|
||||
if (len < 7)
|
||||
return -1;
|
||||
// buf + 2: a byte for code and a byte for padding
|
||||
buf16 = (uint16_t *)(buf + 2);
|
||||
index = buf16[0];
|
||||
abs = buf16[1];
|
||||
rel = buf16[2];
|
||||
key = buf16[3];
|
||||
slot = buf[2];
|
||||
index = buf[3];
|
||||
// buf + 4: a byte for, code, padding, slot, index
|
||||
buf16 = (uint16_t *)(buf + 4);
|
||||
abs = buf16[0];
|
||||
rel = buf16[1];
|
||||
key = buf16[2];
|
||||
buf += 12;
|
||||
if (MSS_DEVICE_INFO(abs, rel, key) > len)
|
||||
return -1;
|
||||
|
||||
dst->device_info.code = code;
|
||||
dst->device_info.slot = slot;
|
||||
dst->device_info.index = index;
|
||||
dst->device_info.abs_count = abs;
|
||||
dst->device_info.rel_count = rel;
|
||||
|
@ -83,17 +86,19 @@ int msg_deserialize(const uint8_t *buf, size_t len, Message *restrict dst) {
|
|||
if (len < 7)
|
||||
return -1;
|
||||
|
||||
// buf + 2: a byte for code and a byte of padding
|
||||
buf16 = (uint16_t *)(buf + 2);
|
||||
index = buf16[0];
|
||||
abs = buf16[1];
|
||||
rel = buf16[2];
|
||||
key = buf16[3];
|
||||
slot = buf[2];
|
||||
index = buf[3];
|
||||
// buf + 4: a byte for, code, padding, slot and index
|
||||
buf16 = (uint16_t *)(buf + 4);
|
||||
abs = buf16[0];
|
||||
rel = buf16[1];
|
||||
key = buf16[2];
|
||||
buf += 12;
|
||||
if (len < MSS_DEVICE_REPORT(abs, rel, key))
|
||||
return -1;
|
||||
|
||||
dst->device_report.code = code;
|
||||
dst->device_report.slot = slot;
|
||||
dst->device_report.index = index;
|
||||
dst->device_report.abs_count = abs;
|
||||
dst->device_report.rel_count = rel;
|
||||
|
@ -198,16 +203,19 @@ int msg_deserialize(const uint8_t *buf, size_t len, Message *restrict dst) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (size + MAGIC_SIZE > len + 1) {
|
||||
if (align_m(size) + MAGIC_SIZE > len + 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (*(MAGIC_TYPE *)buf != MAGIC_END) {
|
||||
// WARN: This is technically bad, but should be ok nonetheless
|
||||
MAGIC_TYPE *mbuf = (MAGIC_TYPE *)align_m((uintptr_t)buf);
|
||||
|
||||
if (*mbuf != MAGIC_END) {
|
||||
printf("NET: Magic not found\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return size + 2 * MAGIC_SIZE;
|
||||
return align_m(size) + 2 * MAGIC_SIZE;
|
||||
}
|
||||
|
||||
// Serialize the message msg in buf, buf must be at least 4 aligned. Returns -1 on error (buf not big enough);
|
||||
|
@ -231,15 +239,15 @@ int msg_serialize(uint8_t *restrict buf, size_t len, const Message *msg) {
|
|||
if (len < MSS_DEVICE_INFO(abs, rel, key))
|
||||
return -1;
|
||||
|
||||
// We begin 4 aligned
|
||||
buf[0] = (uint8_t)msg->code;
|
||||
// buf + 2: a byte for code and a byte for padding
|
||||
buf16 = (uint16_t *)(buf + 2);
|
||||
// 2 aligned here
|
||||
buf16[0] = msg->device_info.index;
|
||||
buf16[1] = abs;
|
||||
buf16[2] = rel;
|
||||
buf16[3] = key;
|
||||
// 1 byte of padding
|
||||
buf[2] = (uint8_t)msg->device_info.slot;
|
||||
buf[3] = (uint8_t)msg->device_info.index;
|
||||
// buf + 4: a byte for, code, padding, slot, index
|
||||
buf16 = (uint16_t *)(buf + 4);
|
||||
buf16[0] = abs;
|
||||
buf16[1] = rel;
|
||||
buf16[2] = key;
|
||||
buf += 12;
|
||||
|
||||
// Back to 4 aligned
|
||||
|
@ -278,12 +286,14 @@ int msg_serialize(uint8_t *restrict buf, size_t len, const Message *msg) {
|
|||
return -1;
|
||||
|
||||
buf[0] = (uint8_t)msg->code;
|
||||
// buf + 2: a byte for code and a byte for padding
|
||||
buf16 = (uint16_t *)(buf + 2);
|
||||
buf16[0] = msg->device_report.index;
|
||||
buf16[1] = abs;
|
||||
buf16[2] = rel;
|
||||
buf16[3] = key;
|
||||
// 1 byte of padding
|
||||
buf[2] = msg->device_report.slot;
|
||||
buf[3] = msg->device_report.index;
|
||||
// buf + 4: a byte for, code, padding, slot and index
|
||||
buf16 = (uint16_t *)(buf + 4);
|
||||
buf16[0] = abs;
|
||||
buf16[1] = rel;
|
||||
buf16[2] = key;
|
||||
buf += 12;
|
||||
// We're 4 aligned already
|
||||
for (int i = 0; i < abs; i++) {
|
||||
|
@ -340,9 +350,7 @@ int msg_serialize(uint8_t *restrict buf, size_t len, const Message *msg) {
|
|||
buf += 2;
|
||||
|
||||
for (int j = 0; j < tag_count; j++) {
|
||||
printf("about to strlen\n");
|
||||
int str_len = strlen(tags[j]);
|
||||
printf("len : %i\n", str_len);
|
||||
int byte_len = align_2(str_len);
|
||||
|
||||
expected_len += 2 + byte_len;
|
||||
|
@ -376,13 +384,15 @@ int msg_serialize(uint8_t *restrict buf, size_t len, const Message *msg) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (size + MAGIC_SIZE > len) {
|
||||
if (align_m(size) + MAGIC_SIZE > len) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*(MAGIC_TYPE *)buf = MAGIC_END;
|
||||
MAGIC_TYPE *mbuf = (MAGIC_TYPE *)align_m((uintptr_t)buf);
|
||||
|
||||
return size + MAGIC_SIZE * 2;
|
||||
*mbuf = MAGIC_END;
|
||||
|
||||
return align_m(size) + MAGIC_SIZE * 2;
|
||||
}
|
||||
|
||||
void msg_free(Message *msg) {
|
||||
|
|
9
net.h
9
net.h
|
@ -11,6 +11,8 @@
|
|||
#define MAGIC_SIZE sizeof(MAGIC_TYPE)
|
||||
static const MAGIC_TYPE MAGIC_BEG = 0xDEADCAFE;
|
||||
static const MAGIC_TYPE MAGIC_END = 0xCAFEDEAD;
|
||||
// Align n to the next MAGIC boundary
|
||||
static inline size_t align_m(uintptr_t n) { return (((n - 1) >> 2) + 1) << 2; }
|
||||
|
||||
typedef enum {
|
||||
NoMessage = 0,
|
||||
|
@ -26,7 +28,8 @@ typedef struct {
|
|||
MessageCode code;
|
||||
// + 1 byte of padding
|
||||
|
||||
uint16_t index;
|
||||
uint8_t slot;
|
||||
uint8_t index;
|
||||
|
||||
uint16_t abs_count;
|
||||
uint16_t rel_count;
|
||||
|
@ -52,7 +55,9 @@ typedef struct {
|
|||
typedef struct {
|
||||
MessageCode code;
|
||||
// + 1 byte of padding
|
||||
uint16_t index;
|
||||
|
||||
uint8_t slot;
|
||||
uint8_t index;
|
||||
|
||||
uint16_t abs_count;
|
||||
uint16_t rel_count;
|
||||
|
|
18
server.c
18
server.c
|
@ -123,6 +123,7 @@ void device_thread_exit(int _sig) {
|
|||
Controller *ctr = *args->controller;
|
||||
if (ctr != NULL) {
|
||||
return_device(ctr);
|
||||
free(ctr);
|
||||
}
|
||||
|
||||
for (int i = 0; i < args->tag_count; i++) {
|
||||
|
@ -146,16 +147,22 @@ void *device_thread(void *args_) {
|
|||
MessageDeviceInfo dev_info;
|
||||
|
||||
while (true) {
|
||||
if (*args->controller != NULL) {
|
||||
free(*args->controller);
|
||||
}
|
||||
|
||||
*args->controller = NULL;
|
||||
Controller *ctr = get_device(args->tags, args->tag_count, &args->conn->closed);
|
||||
if (ctr == NULL) {
|
||||
uint8_t controller_index;
|
||||
Controller *ctr = malloc(sizeof(Controller));
|
||||
if (!get_device(args->tags, args->tag_count, &args->conn->closed, ctr, &controller_index)) {
|
||||
break;
|
||||
}
|
||||
*args->controller = ctr;
|
||||
dev_info = ctr->dev.device_info;
|
||||
dev_info.index = args->index;
|
||||
dev_info.slot = args->index;
|
||||
dev_info.index = controller_index;
|
||||
|
||||
printf("CONN(%d): [%d] Found suitable [%s] device: '%s' (%016lx)\n", args->conn->id, args->index, ctr->ctr.tag,
|
||||
printf("CONN(%d): [%d] Found suitable [%s] device: '%s' (%lu)\n", args->conn->id, args->index, ctr->ctr.tag,
|
||||
ctr->dev.name, ctr->dev.id);
|
||||
|
||||
// Send over device info
|
||||
|
@ -173,7 +180,8 @@ void *device_thread(void *args_) {
|
|||
report.abs_count = ctr->dev.device_info.abs_count;
|
||||
report.rel_count = ctr->dev.device_info.rel_count;
|
||||
report.key_count = ctr->dev.device_info.key_count;
|
||||
report.index = args->index;
|
||||
report.slot = args->index;
|
||||
report.index = controller_index;
|
||||
|
||||
while (true) {
|
||||
struct input_event event;
|
||||
|
|
Loading…
Reference in New Issue