Compare commits

...

2 Commits

Author SHA1 Message Date
Mark 60da6c131a
Added ergodox hid manager 2022-06-26 12:39:02 -07:00
Mark a447b5f8c8
Cleaned up makefile 2022-06-26 12:36:36 -07:00
4 changed files with 201 additions and 64 deletions

View File

@ -22,22 +22,31 @@ libs: $(BUILD_DIR)/hid.o
# Flags and autodetection # Flags and autodetection
# -MMD and -MP generate makefiles with extension .d. # -MMD and -MP generate makefiles with extension .d.
CPPFLAGS := -Wall -MMD -MP -I src -I libs/hidapi/hidapi CPPFLAGS := -MMD -MP \
-Wall \
-I src \
-I libs/hidapi/hidapi
# udev: required by hidapi
LDFLAGS := -l fftw3 -l udev LDFLAGS := -l fftw3 -l udev
# Find all cpp files in source dirs # Find all cpp files in source dirs
SRCS := $(shell find $(SRC_DIRS) -name '*.cpp') SRCS := $(shell find $(SRC_DIRS) -name '*.cpp')
# Turns ./build/a.cpp into ./build/a.cpp.o # Turns src/a.cpp into build/src/a.cpp.o
OBJS := $(SRCS:%=$(BUILD_DIR)/%.o) SRC_OBJS := $(SRCS:%=$(BUILD_DIR)/%.o)
LIB_OBJS := $(BUILD_DIR)/hid.o LIB_OBJS := $(BUILD_DIR)/hid.o
# Turns ./build/a.cpp.o into ./build/a.cpp.d OBJS = $(SRC_OBJS) $(LIB_OBJS)
# Turns build/a.cpp.o into build/a.cpp.d
DEPS := $(OBJS:.o=.d) DEPS := $(OBJS:.o=.d)
################################################# #################################################
# Build targets # Build targets
HIDAPI_PATH := libs/hidapi
### Libraries
# Build hidapi # Build hidapi
HIDAPI_PATH := libs/hidapi
$(BUILD_DIR)/hid.o: $(BUILD_DIR)/hid.o:
@mkdir -p $(BUILD_DIR) @mkdir -p $(BUILD_DIR)
@ -49,15 +58,18 @@ $(BUILD_DIR)/hid.o:
$(HIDAPI_PATH)/linux/hid.c \ $(HIDAPI_PATH)/linux/hid.c \
-o $(BUILD_DIR)/hid.o -o $(BUILD_DIR)/hid.o
### Source
# C++ build step # C++ build step
$(BUILD_DIR)/%.cpp.o: %.cpp $(BUILD_DIR)/hid.o $(BUILD_DIR)/%.cpp.o: %.cpp
mkdir -p $(dir $@) mkdir -p $(dir $@)
g++ $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@ g++ $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@
# Final build step # Final build step
$(TARGET_EXEC) : $(OBJS) $(TARGET_EXEC) : $(OBJS)
g++ $(OBJS) $(LIB_OBJS) -o $@ $(LDFLAGS) g++ $(OBJS) -o $@ $(LDFLAGS)

118
src/ergodox.cpp Normal file
View File

@ -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);
}

54
src/ergodox.hpp Normal file
View File

@ -0,0 +1,54 @@
#pragma once
#include <stdexcept>
#include <cstdint>
#include <wchar.h>
#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;
};

View File

@ -1,27 +1,17 @@
#include <stdio.h> #include <stdio.h>
#include <cstdint> #include <cstdint>
#include <vector> #include <vector>
#include <stdexcept>
// For reading FIFO // For reading FIFO
#include <fcntl.h> #include <fcntl.h>
#include <unistd.h> #include <unistd.h>
// Math libs
#include <math.h>
#include <fftw3.h>
// HIDapi
#include <wchar.h>
#include "hidapi.h"
// Local files // Local files
#include "utility/bitmap.hpp" #include "utility/bitmap.hpp"
#include "utility/buffer.hpp" #include "utility/buffer.hpp"
#include "signal_processing/fft.hpp" #include "signal_processing/fft.hpp"
#include "ergodox.hpp"
#define HID_VEND 0x3297
#define HID_PROD 0x4976
#define HID_USAGE 0x61
#define HID_PAGE 0xff60
// TODO: // TODO:
@ -37,36 +27,6 @@
// beat detection // 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( void draw_spectrum_bitmap(
const std::vector<size_t>& waveform, const std::vector<size_t>& waveform,
Bitmap& bitmap Bitmap& bitmap
@ -84,15 +44,13 @@ const size_t height = 150;
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
uint8_t hid_buf[20];
// HID connect Ergodox Dox = Ergodox::init(
int res; 0x3297,
uint8_t hid_buf[65]; 0x4976,
hid_device *handle; 0x61,
// Initialize the hidapi library 0xFF60
hid_init(); );
// Get Ergodox
handle = get_keyboard();
// buffer size for waveform: // buffer size for waveform:
// (44100 / fps * 10), make 10 bigger for slower scrolling // (44100 / fps * 10), make 10 bigger for slower scrolling
@ -132,12 +90,7 @@ int main(int argc, char *argv[]) {
hid_buf[i + 2] = h; 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; return 0;
} }