From 60da6c131aa4115b5a0d72b0441285feced4169a Mon Sep 17 00:00:00 2001 From: Mark Date: Sun, 26 Jun 2022 12:39:02 -0700 Subject: [PATCH] Added ergodox hid manager --- src/ergodox.cpp | 118 ++++++++++++++++++++++++++++++++++++++++++++++++ src/ergodox.hpp | 54 ++++++++++++++++++++++ src/test.cpp | 67 ++++----------------------- 3 files changed, 182 insertions(+), 57 deletions(-) create mode 100644 src/ergodox.cpp create mode 100644 src/ergodox.hpp diff --git a/src/ergodox.cpp b/src/ergodox.cpp new file mode 100644 index 0000000..fe2e094 --- /dev/null +++ b/src/ergodox.cpp @@ -0,0 +1,118 @@ +#include "ergodox.hpp" + + + +Ergodox::Ergodox( + unsigned short vendor_id, + unsigned short product_id, + unsigned short usage, + unsigned short usage_page +) : + vendor_id(vendor_id), + product_id(product_id), + usage(usage), + usage_page(usage_page), + handle(NULL) +{ + hid_init(); + open(); +} + + + +/* +Initialize Ergodox interface. + +Should be called once at start of execution. Arguments are the USB parameters of the keyboard. + +Returns instance of singleton. +*/ +Ergodox& Ergodox::init( + unsigned short vendor_id, + unsigned short product_id, + unsigned short usage, + unsigned short usage_page +) { + static bool has_been_initialized = false; + static Ergodox Instance( + vendor_id, + product_id, + usage, + usage_page + ); + + // This isn't strictly necessary, but there is no reason + // to call init() twice. + if (has_been_initialized) { + has_been_initialized = true; + throw std::runtime_error("Ergodox has already been initialized!"); + } + + return Instance; +} + +Ergodox::~Ergodox() { + close(); + hid_exit(); +} + + +/* +Try to open this keyboard's hid device. +Throws a runtime error if device is already open, +or if we can't find a device with the given params. +*/ +void Ergodox::open() { + if (handle != NULL) { + throw std::runtime_error("Device already open"); + } + + struct hid_device_info *devs, *cur_dev; + const char *path_to_open = NULL; + + devs = hid_enumerate(vendor_id, product_id); + cur_dev = devs; + while (cur_dev) { + if (cur_dev->vendor_id == vendor_id && + cur_dev->product_id == product_id && + cur_dev->usage == usage && + cur_dev->usage_page == usage_page + ) { + path_to_open = cur_dev->path; + break; + } + cur_dev = cur_dev->next; + } + + if (path_to_open) { + handle = hid_open_path(path_to_open); + hid_free_enumeration(devs); + } else { + hid_free_enumeration(devs); + throw std::runtime_error("Could not open hid device"); + } +} + + +// Close hid device if it is open. +void Ergodox::close() { + if (handle != NULL) { + hid_close(handle); + } +} + + +/* +Send data to Ergodox. + +@param data Data to send +@param length How many bytes to send +@returns Actual number of bytes written, or -1 on error. +*/ +int Ergodox::write(uint8_t* data, size_t length) const { + if (handle == NULL) { + throw std::runtime_error("Cannot write, device is not open!"); + } + + return hid_write(handle, data, length); +} \ No newline at end of file diff --git a/src/ergodox.hpp b/src/ergodox.hpp new file mode 100644 index 0000000..d178b1d --- /dev/null +++ b/src/ergodox.hpp @@ -0,0 +1,54 @@ +#pragma once + +#include +#include +#include +#include "hidapi.h" + +/* +A singleton Ergodox interface. Wraps all hidapi methods, including +hid_init() and hid_exit(). +*/ +class Ergodox { + public: + static Ergodox& init( + unsigned short vendor_id, + unsigned short product_id, + unsigned short usage, + unsigned short usage_page + ); + + ~Ergodox(); + + int write( + uint8_t* data, + size_t length + ) const; + + + private: + Ergodox( + unsigned short vendor_id, + unsigned short product_id, + unsigned short usage, + unsigned short usage_page + ); + + // Disable copy and assignment + //Ergodox(void); + //Ergodox(Ergodox& other); + //Ergodox& operator=(Ergodox& other); + + void open(); + void close(); + + // USB Device paramaters + const unsigned short vendor_id; + const unsigned short product_id; + const unsigned short usage; + const unsigned short usage_page; + + // HID device. + // NULL if not opened. + hid_device* handle; +}; \ No newline at end of file diff --git a/src/test.cpp b/src/test.cpp index c993ceb..408678e 100644 --- a/src/test.cpp +++ b/src/test.cpp @@ -1,27 +1,17 @@ #include #include #include +#include // For reading FIFO #include #include -// Math libs -#include -#include -// HIDapi -#include -#include "hidapi.h" // Local files #include "utility/bitmap.hpp" #include "utility/buffer.hpp" #include "signal_processing/fft.hpp" - - -#define HID_VEND 0x3297 -#define HID_PROD 0x4976 -#define HID_USAGE 0x61 -#define HID_PAGE 0xff60 +#include "ergodox.hpp" // TODO: @@ -37,36 +27,6 @@ // beat detection -hid_device* get_keyboard() { - struct hid_device_info *devs, *cur_dev; - const char *path_to_open = NULL; - hid_device *handle = NULL; - - devs = hid_enumerate(HID_VEND, HID_PROD); - cur_dev = devs; - while (cur_dev) { - if (cur_dev->vendor_id == HID_VEND && - cur_dev->product_id == HID_PROD && - cur_dev->usage == HID_USAGE&& - cur_dev->usage_page == HID_PAGE - ) { - path_to_open = cur_dev->path; - break; - } - cur_dev = cur_dev->next; - } - - if (path_to_open) { - handle = hid_open_path(path_to_open); - } else { - wprintf(L"Could not find device, exiting.\n"); - exit(1); - } - hid_free_enumeration(devs); - return handle; -} - - void draw_spectrum_bitmap( const std::vector& waveform, Bitmap& bitmap @@ -84,15 +44,13 @@ const size_t height = 150; int main(int argc, char *argv[]) { - - // HID connect - int res; - uint8_t hid_buf[65]; - hid_device *handle; - // Initialize the hidapi library - hid_init(); - // Get Ergodox - handle = get_keyboard(); + uint8_t hid_buf[20]; + Ergodox Dox = Ergodox::init( + 0x3297, + 0x4976, + 0x61, + 0xFF60 + ); // buffer size for waveform: // (44100 / fps * 10), make 10 bigger for slower scrolling @@ -132,12 +90,7 @@ int main(int argc, char *argv[]) { hid_buf[i + 2] = h; } - res = hid_write(handle, hid_buf, 12); + Dox.write(hid_buf, 12); } - - // Close the device - hid_close(handle); - // Finalize the hidapi library - hid_exit(); return 0; } \ No newline at end of file