Added support for DJ Console 4-Mx and improved the overall code

This commit is contained in:
JosepMaJAZ 2017-01-16 21:09:02 +01:00
parent f5a8148993
commit ce7c770a86
5 changed files with 319 additions and 72 deletions

71
alsa.c
View File

@ -7,12 +7,20 @@
#include "log.h"
#include "dump.h"
static snd_seq_t *snd_handle;
static int seq_port;
static snd_midi_event_t *midi_event_parser;
#define ALSA_BUFSIZE 4096
#define MAX_PFDS 20
static snd_seq_t *snd_handle = NULL;
static int seq_port;
static snd_midi_event_t *midi_event_parser = NULL;
int npfd;
struct pollfd pfd[MAX_PFDS];
void alsa_interrupting()
{
//Currently nothing to do.
}
int
alsa_setup(const char *name)
@ -31,22 +39,25 @@ alsa_setup(const char *name)
// Allocate parser object for converting to and from MIDI
if (snd_midi_event_new(ALSA_BUFSIZE, &midi_event_parser) < 0) {
fatal("ALSA cannot allocate MIDI event parser");
}
return 0;
return -1;
} else {
snd_midi_event_no_status(midi_event_parser,1);
return 0;
}
}
void
alsa_close()
{
snd_midi_event_free(midi_event_parser);
if (midi_event_parser) {
snd_midi_event_free(midi_event_parser);
}
if (snd_handle) {
snd_seq_close(snd_handle);
}
}
#define MAX_PFDS 20
int npfd;
struct pollfd pfd[MAX_PFDS];
void
alsa_fd_setup(int *nfds, fd_set *rfds, fd_set *wfds)
{
@ -66,8 +77,6 @@ alsa_fd_setup(int *nfds, fd_set *rfds, fd_set *wfds)
FD_SET(pfd[i].fd, rfds);
}
}
}
void
@ -96,7 +105,33 @@ alsa_read_ready()
converted = snd_midi_event_decode(midi_event_parser, buf, ALSA_BUFSIZE, ev);
if (converted < 0) {
warn("Can't decode MIDI event type %x", ev->type);
if (ev->type == SND_SEQ_EVENT_CLIENT_START ) {
printf("Client started \n");
continue;
} else if (ev->type == SND_SEQ_EVENT_CLIENT_EXIT) {
printf("Client exited \n");
continue;
} else if (ev->type == SND_SEQ_EVENT_CLIENT_CHANGE) {
printf("Client status/info changed \n");
continue;
} else if (ev->type == SND_SEQ_EVENT_PORT_START) {
printf("Port created \n");
continue;
} else if (ev->type == SND_SEQ_EVENT_PORT_EXIT) {
printf("Port deleted \n");
continue;
} else if (ev->type == SND_SEQ_EVENT_PORT_CHANGE) {
printf("Port status/info changed \n");
continue;
} else if (ev->type == SND_SEQ_EVENT_PORT_SUBSCRIBED) {
printf("Port connected \n");
continue;
} else if (ev->type == SND_SEQ_EVENT_PORT_UNSUBSCRIBED) {
printf("Port disconnected \n");
continue;
} else {
warn("Can't decode MIDI event type 0x%02x", ev->type);
}
continue;
}
@ -137,7 +172,7 @@ alsa_write(uint8_t *data, size_t datalen)
snd_midi_event_init(midi_event_parser);
for (; datalen > offset;) {
while( datalen > offset) {
snd_seq_event_t ev;
long encoded;
int r;
@ -146,9 +181,9 @@ alsa_write(uint8_t *data, size_t datalen)
if (encoded <= 1) {
int i;
warn("Unable to encode MIDI message (%ld < %ld)", encoded, datalen);
warn("Unable to encode MIDI message (%ld < %ld)", encoded, (long int)datalen);
fprintf(stderr, " ");
for (i = offset; i < datalen; i += 1) {
for (i = offset; i < (long int)datalen; i += 1) {
fprintf(stderr, "%02x ", data[i]);
}
fprintf(stderr, "\n");

2
alsa.h
View File

@ -5,6 +5,8 @@
#include <sys/select.h>
int alsa_setup(const char *name);
void alsa_close();
void alsa_interrupting();
void alsa_fd_setup(int *nfds, fd_set *rfds, fd_set *wfds);
void alsa_read_ready();
void alsa_check_fds(fd_set *rfds, fd_set *wfds);

22
hdjd.c
View File

@ -1,3 +1,4 @@
#include <signal.h>
#include <stdio.h>
#include <stdint.h>
#include <sys/select.h>
@ -5,30 +6,42 @@
#include "usb.h"
#include "dump.h"
static volatile int keepRunning = 1;
void intHandler(int dummy) {
keepRunning = 0;
usb_interrupting();
alsa_interrupting();
}
int
setup()
{
char name[100];
if (usb_setup(name, sizeof(name)) < 0) {
usb_finish();
return -1;
}
if (alsa_setup(name) < 0) {
alsa_close();
return -1;
}
return 0;
}
int
main(int argc, char *argv[])
{
if (setup() < 0) {
return 69;
}
for (;;) {
signal(SIGINT, intHandler);
while (keepRunning) {
fd_set rfds;
fd_set wfds;
int nfds = 0;
@ -47,9 +60,10 @@ main(int argc, char *argv[])
alsa_check_fds(&rfds, &wfds);
usb_check_fds(&rfds, &wfds);
//DUMP();
}
printf("Exiting...\n");
usb_finish();
alsa_close();
return 0;
}

282
usb.c
View File

@ -9,82 +9,211 @@
#include "log.h"
#include "dump.h"
static struct libusb_device_handle *usb_dev;
static const struct device *d;
static int writes_pending = 0;
static int reads_pending = 0;
#define MAX_PFDS 20
struct device {
uint16_t product_id;
uint8_t interface_number;
uint8_t ep_in;
uint8_t ep_out;
uint8_t ep_in2;
uint8_t interface_number2;
};
const struct device devices[] = {
{ 0xb102, 1, 0x83, 0x04 }, // Steel
{ 0xb105, 1, 0x82, 0x03 }, // MP3e2
{ 0xb102, 1, 0x83, 0x04, 0x0, 0 }, // Steel
{ 0xb105, 1, 0x82, 0x03, 0x0, 0 }, // MP3e2
{ 0xb120, 1, 0x82, 0x03, 0x0, 0 }, // Hercules MP3 LE / Glow
{ 0xb107, 1, 0x83, 0x03, 0x0, 0 }, // Hercules Mk4
{ 0xb100, 1, 0x86, 0x06, 0x0, 0 }, // Hercules Mk2
{ 0xb109, 5, 0x83, 0x03, 0x84, 0}, // 4-Mx
{ 0, 0, 0, 0 }
};
void usb_xfer_done(struct libusb_transfer *transfer);
static const int MANUFACTURER_HERCULES = 0x6f8;
static libusb_context *context = NULL;
static struct libusb_device_handle *usb_dev = NULL;
static const struct device *dev_info;
const struct libusb_pollfd **usb_fds = NULL;
struct libusb_transfer *xfer_in;
struct libusb_transfer *xfer_in2;
static int writes_pending = 0;
static int reads_pending = 0;
void usb_xfer_done(struct libusb_transfer *xfer);
void usb_xfer_done_additional(struct libusb_transfer *xfer);
void
usb_interrupting()
{
libusb_cancel_transfer(xfer_in);
if (dev_info->ep_in2 != 0x0) {
libusb_cancel_transfer(xfer_in2);
}
}
static void
usb_initiate_transfer()
{
static const int buffsize = 256;
unsigned char *buf;
buf = (unsigned char *)malloc(256);
buf = (unsigned char *)malloc(buffsize);
// Tell libusb we want to know about bulk transfers
struct libusb_transfer *xfer = libusb_alloc_transfer(0);
libusb_fill_bulk_transfer(xfer, usb_dev, d->ep_in, buf, 256, usb_xfer_done, NULL, 0);
libusb_submit_transfer(xfer);
xfer_in = libusb_alloc_transfer(0);
//timeout if in 1000 milliseconds it hasn't been sent
xfer_in->timeout=1000;
xfer_in->flags |=LIBUSB_TRANSFER_ADD_ZERO_PACKET;
libusb_fill_bulk_transfer(xfer_in, usb_dev, dev_info->ep_in, buf, buffsize, usb_xfer_done, NULL, 0);
libusb_submit_transfer(xfer_in);
reads_pending += 1;
}
static void
usb_initiate_transfer_additional()
{
static const int buffsize = 256;
unsigned char *buf;
buf = (unsigned char *)malloc(buffsize);
// Tell libusb we want to know about bulk transfers
xfer_in2 = libusb_alloc_transfer(0);
//timeout if in 1000 milliseconds it hasn't been sent
xfer_in2->timeout=1000;
xfer_in2->flags |=LIBUSB_TRANSFER_ADD_ZERO_PACKET;
libusb_fill_bulk_transfer(xfer_in2, usb_dev, dev_info->ep_in2, buf, buffsize, usb_xfer_done_additional, NULL, 0);
libusb_submit_transfer(xfer_in2);
}
void
usb_xfer_done(struct libusb_transfer *xfer)
{
uint8_t *data = xfer->buffer;
int datalen = xfer->actual_length;
reads_pending -= 1;
alsa_write(data, datalen);
if ( xfer->status == LIBUSB_TRANSFER_COMPLETED ) {
#ifndef NDEBUG
printf("Receiving on %02x:", dev_info->ep_in);
int i;
for (i = 0; i < datalen; i += 1) {
printf("%02x ", data[i]);
}
printf("\n");
#endif
alsa_write(data, datalen);
}
free(data);
libusb_free_transfer(xfer);
usb_initiate_transfer();
if ( xfer->status == LIBUSB_TRANSFER_COMPLETED ) {
usb_initiate_transfer();
} else if ( xfer->status != LIBUSB_TRANSFER_CANCELLED ) {
fatal("Stopping EP_IN, because of status %d.\nSoftware needs restarting", xfer->status);
}
}
void
usb_xfer_done_additional(struct libusb_transfer *xfer)
{
uint8_t *data = xfer->buffer;
if ( xfer->status == LIBUSB_TRANSFER_COMPLETED ) {
//We don't need to use the information of this call, but it is needed that we
//poll this, or else it hangs and doesn't receive more data.
#ifndef NDEBUG
int datalen = xfer->actual_length;
printf("Receiving on %02x:", dev_info->ep_in2);
int i;
for (i = 0; i < datalen; i += 1) {
printf("%02x ", data[i]);
}
printf("\n");
#endif
}
free(data);
libusb_free_transfer(xfer);
if ( xfer->status == LIBUSB_TRANSFER_COMPLETED ) {
usb_initiate_transfer_additional();
} else if ( xfer->status != LIBUSB_TRANSFER_CANCELLED ) {
fatal("Stopping EP_IN2, because of status %d\nSoftware needs restarting", xfer->status);
}
}
int
usb_setup(char *name, size_t namelen)
{
if (libusb_init(NULL) < 0) {
int ret;
ret=libusb_init(&context);
if (ret < 0) {
fatal("ERROR: %s\n%s", libusb_error_name(ret), libusb_strerror(ret));
return -1;
}
//----------------------------------------------------------------------------
// Enable debug
//----------------------------------------------------------------------------
#ifndef NDEBUG
libusb_set_debug(context, LIBUSB_LOG_LEVEL_WARNING);
#endif
if (libusb_pollfds_handle_timeouts(NULL) == 0) {
if (libusb_pollfds_handle_timeouts(context) == 0) {
fatal("I'm too dumb to handle events on such an old system.");
return -1;
}
//----------------------------------------------------------------------------
// Get device list
//----------------------------------------------------------------------------
struct libusb_device_descriptor founddesc = {0};
{
libusb_device **devs;
ssize_t count; //holding number of devices in list
printf("Locating Hercules USB devices...\n(You can also use the lsusb command to locate this information)\n");
count = libusb_get_device_list(context, &devs);
if ( count < 0) {
fatal("Error getting the device list: %s\n%s", libusb_error_name(count), libusb_strerror(count));
return -1;
} else if (count == 0) {
warn("Seems that the USB device list is empty. Is the controller connected? ");
}
size_t idx;
for (idx = 0; idx < count; idx+=1) {
libusb_device *device = devs[idx];
struct libusb_device_descriptor listdesc = {0};
for (d = devices; d->product_id; d += 1) {
usb_dev = libusb_open_device_with_vid_pid(NULL, 0x6f8, d->product_id);
if (usb_dev) {
break;
}
ret = libusb_get_device_descriptor(device, &listdesc);
if ( ret != 0) {
warn("Could not get descriptor for device index %ld: %s\n%s",
(long int)idx, libusb_error_name(count), libusb_strerror(count));
} else if (listdesc.idVendor == MANUFACTURER_HERCULES) {
printf("Vendor:Device = %04x:%04x\n", listdesc.idVendor, listdesc.idProduct);
founddesc = listdesc;
}
}
libusb_free_device_list(devs, 1); //free the list, unref the devices in it
//----------------------------------------------------------------------------
}
for (dev_info = devices; dev_info->product_id; dev_info += 1) {
usb_dev = libusb_open_device_with_vid_pid(context, MANUFACTURER_HERCULES, dev_info->product_id);
if (usb_dev) {
break;
} else if (dev_info->product_id == founddesc.idProduct) {
fatal("The controller %04x:%04x could not be opened.\n"
"Check that you have enough permissions over /dev/bus/usb/ subfolder elements.\n."
"You might need to create an udev rule at /etc/udev/rules.d/", founddesc.idVendor,founddesc.idProduct);
}
}
if (! usb_dev) {
fatal("Couldn't find a controller.");
if (founddesc.idVendor != MANUFACTURER_HERCULES) {
fatal("Couldn't find a Hercules controller.");
}
else {
fatal("The controller %04x:%04x is not supported.", founddesc.idVendor,founddesc.idProduct);
}
return -1;
}
// Figure out what it's called
{
int ret;
struct libusb_device_descriptor ddesc;
name[0]='\0';
libusb_get_device_descriptor(libusb_get_device(usb_dev), &ddesc);
ret = libusb_get_string_descriptor_ascii(usb_dev, ddesc.iManufacturer, (unsigned char *)name, namelen);
if (ret > 0) {
@ -100,22 +229,49 @@ usb_setup(char *name, size_t namelen)
printf("Opened [%s]\n", name);
}
if (0 != libusb_claim_interface(usb_dev, d->interface_number)) {
fatal("Couldn't claim interface %d", d->interface_number);
}
ret = libusb_claim_interface(usb_dev, dev_info->interface_number);
if (ret == 0 ) {
if (dev_info->ep_in2 != 0x0) {
libusb_claim_interface(usb_dev, dev_info->interface_number2);
usb_initiate_transfer_additional();
}
usb_initiate_transfer();
return 0;
} else {
if (ret == LIBUSB_ERROR_BUSY) {
fatal("Couldn't claim interface %d. Already in use?", dev_info->interface_number);
} else {
fatal("Couldn't claim interface %d. %s\n%s", dev_info->interface_number,
libusb_error_name(ret), libusb_strerror(ret));
}
return -1;
}
}
usb_initiate_transfer();
return 0;
void
usb_finish() {
int ret;
if (usb_dev) {
ret = libusb_release_interface(usb_dev, dev_info->interface_number);
if (ret != 0 && ret != LIBUSB_ERROR_NOT_FOUND) {
warn("Couldn't release interface %d. %s\n%s", dev_info->interface_number,
libusb_error_name(ret), libusb_strerror(ret));
}
libusb_close(usb_dev);
usb_dev=NULL;
}
libusb_exit(context);
}
void
usb_fd_setup(int *nfds, fd_set *rfds, fd_set *wfds)
{
const struct libusb_pollfd **usb_fds = libusb_get_pollfds(NULL);
int i;
usb_fds = libusb_get_pollfds(context);
if (usb_fds == NULL) {
warn("could not get the filedescriptors! This is unexpected");
}
int i;
for (i = 0; usb_fds[i]; i += 1) {
const struct libusb_pollfd *ufd = usb_fds[i];
@ -130,37 +286,64 @@ usb_fd_setup(int *nfds, fd_set *rfds, fd_set *wfds)
}
}
if (reads_pending + writes_pending > 10) {
if (reads_pending + writes_pending > 100) {
warn("%d(r)+%d(w) = %d outstanding USB transactions!", reads_pending, writes_pending, reads_pending + writes_pending);
}
}
void
usb_check_fds(fd_set *rfds, fd_set *wfds)
{
const struct libusb_pollfd **usb_fds = libusb_get_pollfds(NULL);
int i;
if (usb_fds == NULL) {
return;
}
int i;
for (i = 0; usb_fds[i]; i += 1) {
int fd = usb_fds[i]->fd;
if (FD_ISSET(fd, rfds) || FD_ISSET(fd, wfds)) {
libusb_handle_events(NULL);
libusb_handle_events(context);
return;
}
}
#if LIBUSB_API_VERSION >= 0x01000104
libusb_free_pollfds(usb_fds);
usb_fds = NULL;
#endif // LIBUSB_API_VERSION >= 0x01000104
}
void
usb_write_done(struct libusb_transfer *xfer)
{
if (xfer->status) {
if ( xfer->status == LIBUSB_TRANSFER_TIMED_OUT ) {
warn("Send timed out");
#ifndef NDEBUG
uint8_t *data = xfer->buffer;
int datalen = xfer->actual_length;
int i;
for (i = 0; i < datalen; i += 1) {
printf("%02x ", data[i]);
}
printf("\n");
#endif
} else if ( xfer->status && xfer->status != LIBUSB_TRANSFER_CANCELLED) {
warn("USB Write status %d", xfer->status);
}
writes_pending -= 1;
free(xfer->buffer);
uint8_t *data = xfer->buffer;
#ifndef NDEBUG
int datalen = xfer->actual_length;
printf("Sent on %02x:", dev_info->ep_out);
int i;
for (i = 0; i < datalen; i += 1) {
printf("%02x ", data[i]);
}
printf("\n");
#endif
free(data);
libusb_free_transfer(xfer);
}
@ -172,8 +355,19 @@ usb_write(uint8_t *data, size_t datalen)
writes_pending += 1;
xfer = libusb_alloc_transfer(0);
//timeout if in 1000 milliseconds it hasn't been sent
xfer->timeout=1000;
buf = (unsigned char *)malloc(datalen);
memcpy(buf, data, datalen);
libusb_fill_bulk_transfer(xfer, usb_dev, d->ep_out, buf, datalen, usb_write_done, NULL, 0);
libusb_fill_bulk_transfer(xfer, usb_dev, dev_info->ep_out, buf, datalen, usb_write_done, NULL, 0);
libusb_submit_transfer(xfer);
#ifndef NDEBUG
printf("Preparing to send on %02x:", dev_info->ep_out);
int i;
for (i = 0; i < datalen; i += 1) {
printf("%02x ", data[i]);
}
printf("\n");
#endif
}

2
usb.h
View File

@ -5,6 +5,8 @@
#include <sys/select.h>
int usb_setup(char *name, size_t namelen);
void usb_finish();
void usb_interrupting();
void usb_fd_setup(int *nfds, fd_set *rfds, fd_set *wfds);
void usb_check_fds(fd_set *rfds, fd_set *wfds);
void usb_write(uint8_t *data, size_t datalen);