Skip to content

Instantly share code, notes, and snippets.

@Raven24
Last active May 18, 2020 18:56
Show Gist options
  • Save Raven24/2d4e3f83ed7e2799cf8114206e963bd3 to your computer and use it in GitHub Desktop.
Save Raven24/2d4e3f83ed7e2799cf8114206e963bd3 to your computer and use it in GitHub Desktop.
olympus footswitch debug - libusb hid
cmake_minimum_required(VERSION 3.15)
project(UsbTest)
set(CMAKE_COLOR_MAKEFILE ON)
set(CMAKE_BUILD_TYPE Debug)
add_executable(test test.c)
find_package(PkgConfig)
pkg_check_modules(LIBUSB REQUIRED libusb-1.0)
include_directories(${LIBUSB_INCLUDE_DIRS})
target_link_libraries(test ${LIBUSB_LIBRARIES})
/*
TEST PROGRAM FOR PROOF-OF-CONCEPT HANDLING FOR A OLYMPUS FOOTSWITCH HID DEVICE
*/
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include "libusb.h"
// source: https://github.com/DIGImend/usbhid-dump/blob/master/src/usbhid-dump.c
static void dump(const uint8_t *ptr, size_t len) {
static const char xd[] = "0123456789ABCDEF";
static char buf[] = " XX\n";
size_t pos;
uint8_t b;
for(pos = 1; len > 0; len--, ptr++, pos++) {
b = *ptr;
buf[1] = xd[b >> 4];
buf[2] = xd[b & 0xF];
(void)fwrite(buf, ((pos % 16 == 0) ? 4 : 3), 1, stdout);
}
if (pos % 16 != 1)
fputc('\n', stdout);
fflush(stdout);
}
static void interrupt_cb(struct libusb_transfer *transfer) {
assert(transfer != NULL);
switch(transfer->status) {
case LIBUSB_TRANSFER_COMPLETED:
printf(" + DATA", transfer->actual_length);
dump(transfer->buffer, transfer->actual_length);
printf(" * re-submitting interrupt transfer\n");
int t_res = libusb_submit_transfer(transfer);
if(t_res != LIBUSB_SUCCESS) {
fprintf(stderr, "failed submitting transfer\n");
}
break;
case LIBUSB_TRANSFER_CANCELLED:
default:
break;
}
}
int main(int argc, char **argv[]) {
libusb_context* context = NULL;
libusb_device* device = NULL;
libusb_device_handle* handle = NULL;
struct libusb_device_descriptor desc;
struct libusb_transfer* ptransfer;
// DEVICE INFO - according to lsusb
uint16_t vendor = 0x07b4;
uint16_t product = 0x0218;
int iface = 0;
unsigned char endpoint = 0x81;
const size_t ep_len = 8;
int r = libusb_init(&context);
if(r != LIBUSB_SUCCESS) {
fprintf(stderr, "unable to init context\n");
return r;
}
printf("Opening Device %04X:%04X\n", vendor, product);
handle = libusb_open_device_with_vid_pid(context, vendor, product);
if(handle == NULL) {
fprintf(stderr, "failed to get device handle\n");
return -1;
}
printf(" * performing reset\n");
r = libusb_reset_device(handle);
if(r != LIBUSB_SUCCESS) {
fprintf(stderr, "failed to reset device\n");
return r;
}
device = libusb_get_device(handle);
int ret = libusb_get_device_descriptor(device, &desc);
if (ret != LIBUSB_SUCCESS) {
fprintf(stderr, "failed to get device descriptor\n");
return ret;
}
unsigned char string[256];
if (desc.iManufacturer) {
ret = libusb_get_string_descriptor_ascii(handle, desc.iManufacturer, string, sizeof(string));
if (ret > 0)
printf(" Manufacturer: %s\n", (char *)string);
}
if (desc.iProduct) {
ret = libusb_get_string_descriptor_ascii(handle, desc.iProduct, string, sizeof(string));
if (ret > 0)
printf(" Product: %s\n", (char *)string);
}
if (desc.iSerialNumber) {
ret = libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber, string, sizeof(string));
if (ret > 0)
printf(" Serial Number: %s\n", (char *)string);
}
if(libusb_kernel_driver_active(handle, iface)) {
int res = libusb_detach_kernel_driver(handle, iface);
if(res != LIBUSB_SUCCESS && res != LIBUSB_ERROR_NOT_FOUND) {
fprintf(stderr, "failed to detach kernel driver: %s", libusb_strerror(res));
return res;
}
}
int t_res;
// NECESSARY?
printf(" * setting report protocol\n");
t_res = libusb_control_transfer(
handle,
LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE,
0x0B, // set protocol
0x01, // "report"
iface,
NULL, 0,
1000 // timeout
);
if(t_res != LIBUSB_SUCCESS) {
fprintf(stderr, "failed setting report protocol\n");
return t_res;
}
// NECESSARY?
printf(" * setting idle duration\n");
t_res = libusb_control_transfer(
handle,
LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE,
0x0A, // set idle
0, // "infinite"
iface,
NULL, 0,
1000 // timeout
);
if(t_res != LIBUSB_SUCCESS) {
fprintf(stderr, "failed setting report protocol\n");
return t_res;
}
ptransfer = libusb_alloc_transfer(0);
if(ptransfer == NULL) {
fprintf(stderr, "failed allocating transfer\n");
return -1;
}
ptransfer->user_data = NULL;
printf(" * preparing interrupt transfer\n");
void *buf;
buf = malloc(ep_len);
libusb_fill_interrupt_transfer(ptransfer,
handle,
endpoint,
buf, ep_len,
interrupt_cb,
(void*)NULL,
5000);
ptransfer->flags |= LIBUSB_TRANSFER_FREE_BUFFER;
printf(" * submitting interrupt transfer\n");
t_res = libusb_submit_transfer(ptransfer);
if(t_res != LIBUSB_SUCCESS) {
fprintf(stderr, "failed submitting transfer\n");
return t_res;
}
while(1) {
int err = libusb_handle_events(context);
if(err != LIBUSB_SUCCESS && err != LIBUSB_ERROR_INTERRUPTED) {
fprintf(stderr, "error handling events: %s\n", libusb_strerror(err));
return err;
}
}
libusb_exit(context);
return 0;
}
@Raven24
Copy link
Author

Raven24 commented May 18, 2020

Example output when running the test binary and pushing buttons -
the third byte of the data corresponds to what button is pressed
(bits are OR combined, according to the pressed button - 1=left, 2=right, 4=top)

I tried it with and without setting report protocol/idle duration, both seemed to work the same.

Opening Device 07B4:0218
  * performing reset
  Manufacturer:  OLYMPUS IMAGING CORP..
  Product:       HID FootSwitch RS Series
  * setting report protocol
  * setting idle duration
  * preparing interrupt transfer
  * submitting interrupt transfer
  + DATA 00 00 01 00 00 00 00 00
  * re-submitting interrupt transfer
  + DATA 00 00 00 00 00 00 00 00
  * re-submitting interrupt transfer
  + DATA 00 00 02 00 00 00 00 00
  * re-submitting interrupt transfer
  + DATA 00 00 00 00 00 00 00 00
  * re-submitting interrupt transfer
  + DATA 00 00 01 00 00 00 00 00
  * re-submitting interrupt transfer
  + DATA 00 00 02 00 00 00 00 00
  * re-submitting interrupt transfer
  + DATA 00 00 00 00 00 00 00 00
  * re-submitting interrupt transfer
  + DATA 00 00 01 00 00 00 00 00
  * re-submitting interrupt transfer
  + DATA 00 00 03 00 00 00 00 00
  * re-submitting interrupt transfer
  + DATA 00 00 02 00 00 00 00 00
  * re-submitting interrupt transfer
  + DATA 00 00 00 00 00 00 00 00
  * re-submitting interrupt transfer
  + DATA 00 00 01 00 00 00 00 00
  * re-submitting interrupt transfer
  + DATA 00 00 03 00 00 00 00 00
  * re-submitting interrupt transfer
  + DATA 00 00 00 00 00 00 00 00
  * re-submitting interrupt transfer
  + DATA 00 00 01 00 00 00 00 00
  * re-submitting interrupt transfer
  + DATA 00 00 00 00 00 00 00 00
  * re-submitting interrupt transfer
  + DATA 00 00 04 00 00 00 00 00
  * re-submitting interrupt transfer
  + DATA 00 00 00 00 00 00 00 00
  * re-submitting interrupt transfer
  + DATA 00 00 04 00 00 00 00 00
  * re-submitting interrupt transfer
  + DATA 00 00 00 00 00 00 00 00
  * re-submitting interrupt transfer
  + DATA 00 00 04 00 00 00 00 00
  * re-submitting interrupt transfer
  + DATA 00 00 00 00 00 00 00 00
  * re-submitting interrupt transfer
  + DATA 00 00 04 00 00 00 00 00
  * re-submitting interrupt transfer
  + DATA 00 00 00 00 00 00 00 00
  * re-submitting interrupt transfer
  + DATA 00 00 01 00 00 00 00 00
  * re-submitting interrupt transfer
  + DATA 00 00 00 00 00 00 00 00
  * re-submitting interrupt transfer
  + DATA 00 00 02 00 00 00 00 00
  * re-submitting interrupt transfer
  + DATA 00 00 00 00 00 00 00 00
  * re-submitting interrupt transfer

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment