Standardize debugging, reindent (sorry, Plan 9 got me into some weird habits)

This commit is contained in:
Neale Pickett 2017-03-18 14:45:39 -06:00
parent 0893c5a302
commit c9ca950835
6 changed files with 448 additions and 639 deletions

View File

@ -1,7 +1,7 @@
CFLAGS += -Wall CFLAGS += -Wall
CFLAGS += -Werror CFLAGS += -Werror
TARGETS = hdjd aac123 explore TARGETS = hdjd explore
CFLAGS += -g #CFLAGS += -g -DDEBUG
all: $(TARGETS) all: $(TARGETS)
@ -15,13 +15,5 @@ explore.o: CFLAGS += $(shell pkg-config --cflags libusb-1.0)
alsa.o: CFLAGS += $(shell pkg-config --cflags alsa) alsa.o: CFLAGS += $(shell pkg-config --cflags alsa)
usb.o: CFLAGS += $(shell pkg-config --cflags libusb-1.0) usb.o: CFLAGS += $(shell pkg-config --cflags libusb-1.0)
aac123: CFLAGS += $(shell pkg-config --cflags alsa)
aac123: LDLIBS += $(shell pkg-config --libs alsa)
aac123: LDLIBS += -lfaad -lmp4v2
aactest: CFLAGS += $(shell pkg-config --cflags alsa)
aactest: LDLIBS += $(shell pkg-config --libs alsa)
aactest: LDLIBS += -lfaad -lmp4v2
clean: clean:
rm -f $(TARGETS) *.o rm -f $(TARGETS) *.o

156
aac123.c
View File

@ -1,156 +0,0 @@
#include <stdio.h>
#include <malloc.h>
#include <alsa/asoundlib.h>
#include <neaacdec.h>
#include <mp4v2/mp4v2.h>
#include "dump.h"
static int
GetAACTrack(MP4FileHandle *infile)
{
/* find AAC track */
MP4TrackId numTracks = MP4GetNumberOfTracks(infile, NULL, 0);
MP4TrackId i;
for (i = 1; i <= numTracks; i++)
{
uint8_t obj_type;
const char *track_type = MP4GetTrackType(infile, i);
if (! track_type) continue;
if (!MP4_IS_AUDIO_TRACK_TYPE(track_type)) continue;
/* MP4GetTrackAudioType */
obj_type = MP4GetTrackEsdsObjectTypeId(infile, i);
if (obj_type == MP4_INVALID_AUDIO_TYPE)
continue;
if (obj_type == MP4_MPEG4_AUDIO_TYPE) {
obj_type = MP4GetTrackAudioMpeg4Type(infile, i);
if (MP4_IS_MPEG4_AAC_AUDIO_TYPE(obj_type))
return i;
} else {
if (MP4_IS_AAC_AUDIO_TYPE(obj_type))
return i;
}
}
/* can't decode this */
return -1;
}
int
play_file(snd_pcm_t *snd, char *fn)
{
int track;
MP4FileHandle infile;
NeAACDecHandle hDecoder;
NeAACDecConfigurationPtr config;
unsigned char *buffer;
uint32_t buffer_size;
unsigned long samplerate;
unsigned char channels;
long sampleId, numSamples;
void *sample_buffer;
infile = MP4Read(fn);
if (! infile) {
fprintf(stderr, "Unable to open stream\n");
return 1;
}
if ((track = GetAACTrack(infile)) < 0) {
fprintf(stderr, "GetAACTrack\n");
return 1;
}
hDecoder = NeAACDecOpen();
config = NeAACDecGetCurrentConfiguration(hDecoder);
config->outputFormat = FAAD_FMT_16BIT;
config->downMatrix = 1;
config->defObjectType = LC;
NeAACDecSetConfiguration(hDecoder, config);
buffer = NULL;
buffer_size = 0;
MP4GetTrackESConfiguration(infile, track, &buffer, &buffer_size);
if (NeAACDecInit2(hDecoder, buffer, buffer_size, &samplerate, &channels) < 0) {
fprintf(stderr, "Initializing decoder\n");
return 1;
}
if (snd_pcm_set_params(snd,
SND_PCM_FORMAT_S16,
SND_PCM_ACCESS_RW_INTERLEAVED,
channels,
samplerate,
1,
500000) < 0) {
fprintf(stderr, "Set ALSA params\n");
return 1;
}
if (buffer) {
free(buffer);
}
DUMP_d(MP4GetTrackMaxSampleSize(infile, track));
numSamples = MP4GetTrackNumberOfSamples(infile, track);
DUMP_d(numSamples);
for (sampleId = 1; sampleId <= numSamples; sampleId++) {
int rc;
unsigned int sample_count;
NeAACDecFrameInfo frameInfo;
buffer = NULL;
buffer_size = 0;
rc = MP4ReadSample(infile, track, sampleId, &buffer, &buffer_size, NULL, NULL, NULL, NULL);
if (rc == 0) {
fprintf(stderr, "Read failed\n");
return 1;
}
sample_buffer = NeAACDecDecode(hDecoder, &frameInfo, buffer, buffer_size);
sample_count = frameInfo.samples;
snd_pcm_writei(snd, sample_buffer, sample_count / channels);
}
return 0;
}
int
main(int argc, char *argv[])
{
int i;
snd_pcm_t *snd;
if (snd_pcm_open(&snd, "default", SND_PCM_STREAM_PLAYBACK, 0) < 0) {
fprintf(stderr, "Opening ALSA\n");
return 1;
}
for (i = 1; i < argc; i += 1) {
char *fn = argv[i];
printf("%s\n", fn);
play_file(snd, fn);
}
return 0;
}

270
alsa.c
View File

@ -19,191 +19,191 @@ struct pollfd pfd[MAX_PFDS];
void alsa_interrupting() void alsa_interrupting()
{ {
//Currently nothing to do. //Currently nothing to do.
} }
int int
alsa_setup(const char *name) alsa_setup(const char *name)
{ {
if (snd_seq_open(&snd_handle, "default", SND_SEQ_OPEN_DUPLEX, 0) < 0) { if (snd_seq_open(&snd_handle, "default", SND_SEQ_OPEN_DUPLEX, 0) < 0) {
perror("snd_seq_open"); perror("snd_seq_open");
return -1; return -1;
} }
snd_seq_nonblock(snd_handle, 1); snd_seq_nonblock(snd_handle, 1);
snd_seq_set_client_name(snd_handle, name); snd_seq_set_client_name(snd_handle, name);
seq_port = seq_port =
snd_seq_create_simple_port(snd_handle, name, snd_seq_create_simple_port(snd_handle, name,
SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_READ | SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_READ |
SND_SEQ_PORT_CAP_SUBS_WRITE, SND_SEQ_PORT_TYPE_MIDI_GENERIC); SND_SEQ_PORT_CAP_SUBS_WRITE, SND_SEQ_PORT_TYPE_MIDI_GENERIC);
// Allocate parser object for converting to and from MIDI // Allocate parser object for converting to and from MIDI
if (snd_midi_event_new(ALSA_BUFSIZE, &midi_event_parser) < 0) { if (snd_midi_event_new(ALSA_BUFSIZE, &midi_event_parser) < 0) {
fatal("ALSA cannot allocate MIDI event parser"); fatal("ALSA cannot allocate MIDI event parser");
return -1; return -1;
} else { } else {
snd_midi_event_no_status(midi_event_parser,1); snd_midi_event_no_status(midi_event_parser,1);
return 0; return 0;
} }
} }
void void
alsa_close() alsa_close()
{ {
if (midi_event_parser) { if (midi_event_parser) {
snd_midi_event_free(midi_event_parser); snd_midi_event_free(midi_event_parser);
} }
if (snd_handle) { if (snd_handle) {
snd_seq_close(snd_handle); snd_seq_close(snd_handle);
} }
} }
void void
alsa_fd_setup(int *nfds, fd_set *rfds, fd_set *wfds) alsa_fd_setup(int *nfds, fd_set *rfds, fd_set *wfds)
{ {
npfd = snd_seq_poll_descriptors_count(snd_handle, POLLIN); npfd = snd_seq_poll_descriptors_count(snd_handle, POLLIN);
int i; int i;
if (npfd > MAX_PFDS) { if (npfd > MAX_PFDS) {
fatal("ALSA wants too many file descriptors"); fatal("ALSA wants too many file descriptors");
} }
snd_seq_poll_descriptors(snd_handle, pfd, npfd, POLLIN); snd_seq_poll_descriptors(snd_handle, pfd, npfd, POLLIN);
for (i = 0; i < npfd; i += 1) { for (i = 0; i < npfd; i += 1) {
if (pfd[i].fd > *nfds) { if (pfd[i].fd > *nfds) {
*nfds = pfd[i].fd; *nfds = pfd[i].fd;
} }
if (pfd[i].events & POLLIN) { if (pfd[i].events & POLLIN) {
FD_SET(pfd[i].fd, rfds); FD_SET(pfd[i].fd, rfds);
} }
} }
} }
void void
alsa_read_ready() alsa_read_ready()
{ {
snd_midi_event_init(midi_event_parser); snd_midi_event_init(midi_event_parser);
for (;;) { for (;;) {
snd_seq_event_t *ev; snd_seq_event_t *ev;
unsigned char buf[ALSA_BUFSIZE]; unsigned char buf[ALSA_BUFSIZE];
long converted; long converted;
int r; int r;
r = snd_seq_event_input(snd_handle, &ev); r = snd_seq_event_input(snd_handle, &ev);
if (r == -EAGAIN) { if (r == -EAGAIN) {
// input queue empty // input queue empty
break; break;
} else if (r == -ENOSPC) { } else if (r == -ENOSPC) {
warn("Input queue overflow"); warn("Input queue overflow");
continue; continue;
} else if (r < 0) { } else if (r < 0) {
warn("snd_seq_event_input() = %d", r); warn("snd_seq_event_input() = %d", r);
continue; continue;
} }
converted = snd_midi_event_decode(midi_event_parser, buf, ALSA_BUFSIZE, ev); converted = snd_midi_event_decode(midi_event_parser, buf, ALSA_BUFSIZE, ev);
if (converted < 0) { if (converted < 0) {
if (ev->type == SND_SEQ_EVENT_CLIENT_START ) { if (ev->type == SND_SEQ_EVENT_CLIENT_START ) {
printf("Client started \n"); DUMPf("Client started \n");
continue; continue;
} else if (ev->type == SND_SEQ_EVENT_CLIENT_EXIT) { } else if (ev->type == SND_SEQ_EVENT_CLIENT_EXIT) {
printf("Client exited \n"); DUMPf("Client exited \n");
continue; continue;
} else if (ev->type == SND_SEQ_EVENT_CLIENT_CHANGE) { } else if (ev->type == SND_SEQ_EVENT_CLIENT_CHANGE) {
printf("Client status/info changed \n"); DUMPf("Client status/info changed \n");
continue; continue;
} else if (ev->type == SND_SEQ_EVENT_PORT_START) { } else if (ev->type == SND_SEQ_EVENT_PORT_START) {
printf("Port created \n"); DUMPf("Port created \n");
continue; continue;
} else if (ev->type == SND_SEQ_EVENT_PORT_EXIT) { } else if (ev->type == SND_SEQ_EVENT_PORT_EXIT) {
printf("Port deleted \n"); DUMPf("Port deleted \n");
continue; continue;
} else if (ev->type == SND_SEQ_EVENT_PORT_CHANGE) { } else if (ev->type == SND_SEQ_EVENT_PORT_CHANGE) {
printf("Port status/info changed \n"); DUMPf("Port status/info changed \n");
continue; continue;
} else if (ev->type == SND_SEQ_EVENT_PORT_SUBSCRIBED) { } else if (ev->type == SND_SEQ_EVENT_PORT_SUBSCRIBED) {
printf("Port connected \n"); DUMPf("Port connected \n");
continue; continue;
} else if (ev->type == SND_SEQ_EVENT_PORT_UNSUBSCRIBED) { } else if (ev->type == SND_SEQ_EVENT_PORT_UNSUBSCRIBED) {
printf("Port disconnected \n"); DUMPf("Port disconnected \n");
continue; continue;
} else { } else {
warn("Can't decode MIDI event type 0x%02x", ev->type); warn("Can't decode MIDI event type 0x%02x", ev->type);
} }
continue; continue;
} }
if (converted < 3) { if (converted < 3) {
int i; int i;
warn("Uh oh, weird MIDI packet with length %ld (does this make sense if prefixed with 90?)", converted); warn("Uh oh, weird MIDI packet with length %ld (does this make sense if prefixed with 90?)", converted);
for (i = 0; i < converted; i += 1) { for (i = 0; i < converted; i += 1) {
fprintf(stderr, " %02x", buf[i]); fprintf(stderr, " %02x", buf[i]);
} }
fprintf(stderr, "\n"); fprintf(stderr, "\n");
} }
usb_write(buf, converted); usb_write(buf, converted);
} }
} }
void void
alsa_check_fds(fd_set *rfds, fd_set *wfds) alsa_check_fds(fd_set *rfds, fd_set *wfds)
{ {
int i; int i;
for (i = 0; i < npfd; i += 1) { for (i = 0; i < npfd; i += 1) {
int fd = pfd[i].fd; int fd = pfd[i].fd;
if (FD_ISSET(fd, rfds) || FD_ISSET(fd, wfds)) { if (FD_ISSET(fd, rfds) || FD_ISSET(fd, wfds)) {
alsa_read_ready(); alsa_read_ready();
return; return;
} }
} }
} }
void void
alsa_write(uint8_t *data, size_t datalen) alsa_write(uint8_t *data, size_t datalen)
{ {
size_t offset = 0; size_t offset = 0;
snd_midi_event_init(midi_event_parser); snd_midi_event_init(midi_event_parser);
while( datalen > offset) { while( datalen > offset) {
snd_seq_event_t ev; snd_seq_event_t ev;
long encoded; long encoded;
int r; int r;
encoded = snd_midi_event_encode(midi_event_parser, data + offset, datalen - offset, &ev); encoded = snd_midi_event_encode(midi_event_parser, data + offset, datalen - offset, &ev);
if (encoded <= 1) { if (encoded <= 1) {
int i; int i;
warn("Unable to encode MIDI message (%ld < %ld)", encoded, (long int)datalen); warn("Unable to encode MIDI message (%ld < %ld)", encoded, (long int)datalen);
fprintf(stderr, " "); fprintf(stderr, " ");
for (i = offset; i < (long int)datalen; i += 1) { for (i = offset; i < (long int)datalen; i += 1) {
fprintf(stderr, "%02x ", data[i]); fprintf(stderr, "%02x ", data[i]);
} }
fprintf(stderr, "\n"); fprintf(stderr, "\n");
return; return;
} }
snd_seq_ev_set_direct(&ev); snd_seq_ev_set_direct(&ev);
snd_seq_ev_set_source(&ev, seq_port); snd_seq_ev_set_source(&ev, seq_port);
snd_seq_ev_set_subs(&ev); snd_seq_ev_set_subs(&ev);
r = snd_seq_event_output(snd_handle, &ev); r = snd_seq_event_output(snd_handle, &ev);
if (r < 0) { if (r < 0) {
warn("Couldn't write an output event"); warn("Couldn't write an output event");
} }
if (r > 200) { if (r > 200) {
warn("Output buffer size %d", r); warn("Output buffer size %d", r);
} }
offset += encoded; offset += encoded;
} }
snd_seq_drain_output(snd_handle); snd_seq_drain_output(snd_handle);
} }

2
dump.h
View File

@ -6,7 +6,7 @@
#include <string.h> #include <string.h>
/* Some things I use for debugging */ /* Some things I use for debugging */
#ifdef NODUMP #ifdef DEBUG
# define DUMPf(fmt, args...) # define DUMPf(fmt, args...)
#else #else
# define DUMPf(fmt, args...) fprintf(stderr, "%s:%d " fmt "\n", __FILE__, __LINE__, ##args) # define DUMPf(fmt, args...) fprintf(stderr, "%s:%d " fmt "\n", __FILE__, __LINE__, ##args)

130
explore.c
View File

@ -19,92 +19,92 @@
#define DUMP_p(v) DUMPf("%s = %p", #v, v) #define DUMP_p(v) DUMPf("%s = %p", #v, v)
struct device { struct device {
char *name; char *name;
uint16_t product_id; uint16_t product_id;
uint8_t ep_in; uint8_t ep_in;
uint8_t ep_out; uint8_t ep_out;
}; };
const struct device devices[] = { const struct device devices[] = {
{"Steel", 0xb102, 0x83, 0x04}, {"Steel", 0xb102, 0x83, 0x04},
{"MP3e2", 0xb105, 0x82, 0x03}, {"MP3e2", 0xb105, 0x82, 0x03},
{"4Set", 0xb10c, 0x84, 0x02}, {"4Set", 0xb10c, 0x84, 0x02},
{0, 0, 0, 0} {0, 0, 0, 0}
}; };
int int
main(int argc, char **argv) main(int argc, char **argv)
{ {
struct libusb_device_handle *dev; struct libusb_device_handle *dev;
struct libusb_device_descriptor ddesc; struct libusb_device_descriptor ddesc;
unsigned char name[100]; unsigned char name[100];
const struct device *d; const struct device *d;
int ret; int ret;
if (libusb_init(NULL) < 0) { if (libusb_init(NULL) < 0) {
return 69; return 69;
} }
for (d = devices; d->product_id; d += 1) { for (d = devices; d->product_id; d += 1) {
dev = libusb_open_device_with_vid_pid(NULL, 0x6f8, d->product_id); dev = libusb_open_device_with_vid_pid(NULL, 0x6f8, d->product_id);
if (dev) { if (dev) {
break; break;
} }
} }
if (!dev) { if (!dev) {
printf("Couldn't find a controller\n"); printf("Couldn't find a controller\n");
return 69; return 69;
} }
// Figure out what this thing is called // Figure out what this thing is called
libusb_get_device_descriptor(libusb_get_device(dev), &ddesc); libusb_get_device_descriptor(libusb_get_device(dev), &ddesc);
{ {
unsigned char *p = name; unsigned char *p = name;
ret = libusb_get_string_descriptor_ascii(dev, ddesc.iManufacturer, name, sizeof(name)); ret = libusb_get_string_descriptor_ascii(dev, ddesc.iManufacturer, name, sizeof(name));
if (ret > 0) { if (ret > 0) {
p = name + ret; p = name + ret;
*p = ' '; *p = ' ';
p += 1; p += 1;
ret = libusb_get_string_descriptor_ascii(dev, ddesc.iProduct, p, sizeof(name) - ret - 1); ret = libusb_get_string_descriptor_ascii(dev, ddesc.iProduct, p, sizeof(name) - ret - 1);
} }
if (ret < 0) { if (ret < 0) {
printf("Can't figure out what to call this thing.\n"); printf("Can't figure out what to call this thing.\n");
return 69; return 69;
} }
} }
printf("Opened a %s\n", name); printf("Opened a %s\n", name);
while (1) { while (1) {
uint8_t data[256]; uint8_t data[256];
int transferred; int transferred;
int i; int i;
if ((ret = libusb_bulk_transfer(dev, d->ep_in, data, sizeof data, &transferred, 0))) { if ((ret = libusb_bulk_transfer(dev, d->ep_in, data, sizeof data, &transferred, 0))) {
break; break;
} }
for (i = 0; i < transferred; i += 1) { for (i = 0; i < transferred; i += 1) {
printf("%02x ", data[i]); printf("%02x ", data[i]);
} }
printf("\n"); printf("\n");
{ {
uint8_t data[16]; uint8_t data[16];
memset(data, 0xff, sizeof data); memset(data, 0xff, sizeof data);
libusb_bulk_transfer(dev, d->ep_out, data, sizeof data, &transferred, 0); libusb_bulk_transfer(dev, d->ep_out, data, sizeof data, &transferred, 0);
} }
} }
if (ret < 0) { if (ret < 0) {
printf("ERROR: %s\n", libusb_error_name(ret)); printf("ERROR: %s\n", libusb_error_name(ret));
} }
libusb_exit(NULL); libusb_exit(NULL);
return 0; return 0;
} }

517
usb.c
View File

@ -12,21 +12,21 @@
#define MAX_PFDS 20 #define MAX_PFDS 20
struct device { struct device {
uint16_t product_id; uint16_t product_id;
uint8_t interface_number; uint8_t interface_number;
uint8_t ep_in; uint8_t ep_in;
uint8_t ep_out; uint8_t ep_out;
uint8_t ep_in2; uint8_t ep_in2;
uint8_t interface_number2; uint8_t interface_number2;
}; };
const struct device devices[] = { const struct device devices[] = {
{ 0xb102, 1, 0x83, 0x04, 0x0, 0 }, // Steel { 0xb102, 1, 0x83, 0x04, 0x0, 0 }, // Steel
{ 0xb105, 1, 0x82, 0x03, 0x0, 0 }, // MP3e2 { 0xb105, 1, 0x82, 0x03, 0x0, 0 }, // MP3e2
{ 0xb120, 1, 0x82, 0x03, 0x0, 0 }, // Hercules MP3 LE / Glow { 0xb120, 1, 0x82, 0x03, 0x0, 0 }, // Hercules MP3 LE / Glow
{ 0xb107, 1, 0x83, 0x03, 0x0, 0 }, // Hercules Mk4 { 0xb107, 1, 0x83, 0x03, 0x0, 0 }, // Hercules Mk4
{ 0xb100, 1, 0x86, 0x06, 0x0, 0 }, // Hercules Mk2 { 0xb100, 1, 0x86, 0x06, 0x0, 0 }, // Hercules Mk2
{ 0xb109, 5, 0x83, 0x03, 0x84, 0}, // 4-Mx { 0xb109, 5, 0x83, 0x03, 0x84, 0}, // 4-Mx
{ 0, 0, 0, 0 } { 0, 0, 0, 0 }
}; };
static const int MANUFACTURER_HERCULES = 0x6f8; static const int MANUFACTURER_HERCULES = 0x6f8;
@ -40,334 +40,307 @@ struct libusb_transfer *xfer_in2;
static int writes_pending = 0; static int writes_pending = 0;
static int reads_pending = 0; static int reads_pending = 0;
void
usb_debug_msg(char *action, int ep, uint8_t data[], size_t datalen)
{
#ifdef DEBUG
fprintf(stderr, "%s on ep%02x:", action, ep);
for (int i = 0; i < datalen; i += 1) {
fprintf(stderr, " %02x", data[i]);
}
fprintf(stderr, "\n");
#endif
}
void usb_xfer_done(struct libusb_transfer *xfer); void usb_xfer_done(struct libusb_transfer *xfer);
void usb_xfer_done_additional(struct libusb_transfer *xfer); void usb_xfer_done_additional(struct libusb_transfer *xfer);
void void
usb_interrupting() usb_interrupting()
{ {
libusb_cancel_transfer(xfer_in); libusb_cancel_transfer(xfer_in);
if (dev_info->ep_in2 != 0x0) { if (dev_info->ep_in2 != 0x0) {
libusb_cancel_transfer(xfer_in2); libusb_cancel_transfer(xfer_in2);
} }
} }
static void static void
usb_initiate_transfer() usb_initiate_transfer()
{ {
static const int buffsize = 256; static const int buffsize = 256;
unsigned char *buf; unsigned char *buf;
buf = (unsigned char *)malloc(buffsize); buf = (unsigned char *)malloc(buffsize);
// Tell libusb we want to know about bulk transfers // Tell libusb we want to know about bulk transfers
xfer_in = libusb_alloc_transfer(0); xfer_in = libusb_alloc_transfer(0);
//timeout if in 1000 milliseconds it hasn't been sent //timeout if in 1000 milliseconds it hasn't been sent
xfer_in->timeout=1000; xfer_in->timeout=1000;
xfer_in->flags |=LIBUSB_TRANSFER_ADD_ZERO_PACKET; 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_fill_bulk_transfer(xfer_in, usb_dev, dev_info->ep_in, buf, buffsize, usb_xfer_done, NULL, 0);
libusb_submit_transfer(xfer_in); libusb_submit_transfer(xfer_in);
reads_pending += 1; reads_pending += 1;
} }
static void static void
usb_initiate_transfer_additional() usb_initiate_transfer_additional()
{ {
static const int buffsize = 256; static const int buffsize = 256;
unsigned char *buf; unsigned char *buf;
buf = (unsigned char *)malloc(buffsize); buf = (unsigned char *)malloc(buffsize);
// Tell libusb we want to know about bulk transfers // Tell libusb we want to know about bulk transfers
xfer_in2 = libusb_alloc_transfer(0); xfer_in2 = libusb_alloc_transfer(0);
//timeout if in 1000 milliseconds it hasn't been sent //timeout if in 1000 milliseconds it hasn't been sent
xfer_in2->timeout=1000; xfer_in2->timeout=1000;
xfer_in2->flags |=LIBUSB_TRANSFER_ADD_ZERO_PACKET; 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_fill_bulk_transfer(xfer_in2, usb_dev, dev_info->ep_in2, buf, buffsize, usb_xfer_done_additional, NULL, 0);
libusb_submit_transfer(xfer_in2); libusb_submit_transfer(xfer_in2);
} }
void void
usb_xfer_done(struct libusb_transfer *xfer) usb_xfer_done(struct libusb_transfer *xfer)
{ {
uint8_t *data = xfer->buffer; uint8_t *data = xfer->buffer;
int datalen = xfer->actual_length; int datalen = xfer->actual_length;
reads_pending -= 1; reads_pending -= 1;
if ( xfer->status == LIBUSB_TRANSFER_COMPLETED ) { if ( xfer->status == LIBUSB_TRANSFER_COMPLETED ) {
#ifndef NDEBUG usb_debug_msg("Receiving", dev_info->ep_in, data, datalen);
printf("Receiving on %02x:", dev_info->ep_in); alsa_write(data, datalen);
int i; }
for (i = 0; i < datalen; i += 1) { free(data);
printf("%02x ", data[i]); libusb_free_transfer(xfer);
} if ( xfer->status == LIBUSB_TRANSFER_COMPLETED ) {
printf("\n"); usb_initiate_transfer();
#endif } else if ( xfer->status != LIBUSB_TRANSFER_CANCELLED ) {
alsa_write(data, datalen); fatal("Stopping EP_IN, because of status %d.\nSoftware needs restarting", xfer->status);
} }
free(data);
libusb_free_transfer(xfer);
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 void
usb_xfer_done_additional(struct libusb_transfer *xfer) usb_xfer_done_additional(struct libusb_transfer *xfer)
{ {
uint8_t *data = xfer->buffer; if ( xfer->status == LIBUSB_TRANSFER_COMPLETED ) {
if ( xfer->status == LIBUSB_TRANSFER_COMPLETED ) { // We don't need to use the information of this call, but it is needed that we
//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.
//poll this, or else it hangs and doesn't receive more data. usb_debug_msg("Receiving", dev_info->ep_in2, xfer->buffer, xfer->actual_length);
#ifndef NDEBUG }
int datalen = xfer->actual_length;
printf("Receiving on %02x:", dev_info->ep_in2); if ( xfer->status == LIBUSB_TRANSFER_COMPLETED ) {
int i; usb_initiate_transfer_additional();
for (i = 0; i < datalen; i += 1) { } else if ( xfer->status != LIBUSB_TRANSFER_CANCELLED ) {
printf("%02x ", data[i]); fatal("Stopping EP_IN2, because of status %d\nSoftware needs restarting", xfer->status);
} }
printf("\n");
#endif free(xfer->buffer);
} libusb_free_transfer(xfer);
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 int
usb_setup(char *name, size_t namelen) usb_setup(char *name, size_t namelen)
{ {
int ret; int ret;
ret=libusb_init(&context); ret=libusb_init(&context);
if (ret < 0) { if (ret < 0) {
fatal("ERROR: %s\n%s", libusb_error_name(ret), libusb_strerror(ret)); fatal("ERROR: %s\n%s", libusb_error_name(ret), libusb_strerror(ret));
return -1; return -1;
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
// Enable debug // Enable debug
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
#ifndef NDEBUG #ifdef DEBUG
libusb_set_debug(context, LIBUSB_LOG_LEVEL_WARNING); libusb_set_debug(context, LIBUSB_LOG_LEVEL_WARNING);
#endif #endif
if (libusb_pollfds_handle_timeouts(context) == 0) { if (libusb_pollfds_handle_timeouts(context) == 0) {
fatal("I'm too dumb to handle events on such an old system."); fatal("I'm too dumb to handle events on such an old system.");
return -1; return -1;
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
// Get device list // Get device list
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
struct libusb_device_descriptor founddesc = {0}; struct libusb_device_descriptor founddesc = {0};
{ {
libusb_device **devs; libusb_device **devs;
ssize_t count; //holding number of devices in list 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"); 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); count = libusb_get_device_list(context, &devs);
if ( count < 0) { if ( count < 0) {
fatal("Error getting the device list: %s\n%s", libusb_error_name(count), libusb_strerror(count)); fatal("Error getting the device list: %s\n%s", libusb_error_name(count), libusb_strerror(count));
return -1; return -1;
} else if (count == 0) { } else if (count == 0) {
warn("Seems that the USB device list is empty. Is the controller connected? "); 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};
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) { size_t idx;
usb_dev = libusb_open_device_with_vid_pid(context, MANUFACTURER_HERCULES, dev_info->product_id); for (idx = 0; idx < count; idx+=1) {
if (usb_dev) { libusb_device *device = devs[idx];
break; struct libusb_device_descriptor listdesc = {0};
} else if (dev_info->product_id == founddesc.idProduct) {
fatal("The controller %04x:%04x could not be opened.\n" 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." "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); "You might need to create an udev rule at /etc/udev/rules.d/", founddesc.idVendor,founddesc.idProduct);
}
}
if (! usb_dev) {
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
{
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) {
char *p = name + ret;
*p = ' ';
p += 1;
ret = libusb_get_string_descriptor_ascii(usb_dev, ddesc.iProduct, (unsigned char *)p, namelen - ret - 1);
}
if (ret < 0) {
warn("I can't figure out what to call this thing.");
}
printf("Opened [%s]\n", name);
}
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;
} }
}
if (! usb_dev) {
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
{
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) {
char *p = name + ret;
*p = ' ';
p += 1;
ret = libusb_get_string_descriptor_ascii(usb_dev, ddesc.iProduct, (unsigned char *)p, namelen - ret - 1);
}
if (ret < 0) {
warn("I can't figure out what to call this thing.");
}
printf("Opened [%s]\n", name);
}
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;
}
} }
void void
usb_finish() { usb_finish() {
int ret; int ret;
if (usb_dev) { if (usb_dev) {
ret = libusb_release_interface(usb_dev, dev_info->interface_number); ret = libusb_release_interface(usb_dev, dev_info->interface_number);
if (ret != 0 && ret != LIBUSB_ERROR_NOT_FOUND) { if (ret != 0 && ret != LIBUSB_ERROR_NOT_FOUND) {
warn("Couldn't release interface %d. %s\n%s", dev_info->interface_number, warn("Couldn't release interface %d. %s\n%s", dev_info->interface_number,
libusb_error_name(ret), libusb_strerror(ret)); libusb_error_name(ret), libusb_strerror(ret));
}
libusb_close(usb_dev);
usb_dev=NULL;
} }
libusb_exit(context); libusb_close(usb_dev);
usb_dev=NULL;
}
libusb_exit(context);
} }
void void
usb_fd_setup(int *nfds, fd_set *rfds, fd_set *wfds) usb_fd_setup(int *nfds, fd_set *rfds, fd_set *wfds)
{ {
usb_fds = libusb_get_pollfds(context); usb_fds = libusb_get_pollfds(context);
if (usb_fds == NULL) { if (usb_fds == NULL) {
warn("could not get the filedescriptors! This is unexpected"); warn("could not get the filedescriptors! This is unexpected");
} }
int i; int i;
for (i = 0; usb_fds[i]; i += 1) { for (i = 0; usb_fds[i]; i += 1) {
const struct libusb_pollfd *ufd = usb_fds[i]; const struct libusb_pollfd *ufd = usb_fds[i];
if (ufd->fd > *nfds) { if (ufd->fd > *nfds) {
*nfds = ufd->fd; *nfds = ufd->fd;
} }
if (ufd->events & POLLIN) { if (ufd->events & POLLIN) {
FD_SET(ufd->fd, rfds); FD_SET(ufd->fd, rfds);
} }
if (ufd->events & POLLOUT) { if (ufd->events & POLLOUT) {
FD_SET(ufd->fd, wfds); FD_SET(ufd->fd, wfds);
} }
} }
if (reads_pending + writes_pending > 100) { if (reads_pending + writes_pending > 100) {
warn("%d(r)+%d(w) = %d outstanding USB transactions!", reads_pending, writes_pending, reads_pending + writes_pending); warn("%d(r)+%d(w) = %d outstanding USB transactions!", reads_pending, writes_pending, reads_pending + writes_pending);
} }
} }
void void
usb_check_fds(fd_set *rfds, fd_set *wfds) usb_check_fds(fd_set *rfds, fd_set *wfds)
{ {
if (usb_fds == NULL) { if (usb_fds == NULL) {
return; 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(context);
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(context);
return;
}
}
#if LIBUSB_API_VERSION >= 0x01000104 #if LIBUSB_API_VERSION >= 0x01000104
libusb_free_pollfds(usb_fds); libusb_free_pollfds(usb_fds);
usb_fds = NULL; usb_fds = NULL;
#endif // LIBUSB_API_VERSION >= 0x01000104 #endif // LIBUSB_API_VERSION >= 0x01000104
} }
void void
usb_write_done(struct libusb_transfer *xfer) usb_write_done(struct libusb_transfer *xfer)
{ {
if ( xfer->status == LIBUSB_TRANSFER_TIMED_OUT ) { if ( xfer->status == LIBUSB_TRANSFER_TIMED_OUT ) {
warn("Send timed out"); warn("Send timed out");
#ifndef NDEBUG } else if ( xfer->status && xfer->status != LIBUSB_TRANSFER_CANCELLED) {
uint8_t *data = xfer->buffer; warn("USB Write status %d", xfer->status);
int datalen = xfer->actual_length; }
int i; writes_pending -= 1;
for (i = 0; i < datalen; i += 1) { usb_debug_msg("Sent", dev_info->ep_out, xfer->buffer, xfer->actual_length);
printf("%02x ", data[i]); free(xfer->buffer);
} libusb_free_transfer(xfer);
printf("\n");
#endif
} else if ( xfer->status && xfer->status != LIBUSB_TRANSFER_CANCELLED) {
warn("USB Write status %d", xfer->status);
}
writes_pending -= 1;
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);
} }
void void
usb_write(uint8_t *data, size_t datalen) usb_write(uint8_t *data, size_t datalen)
{ {
struct libusb_transfer *xfer; struct libusb_transfer *xfer;
unsigned char *buf; unsigned char *buf;
writes_pending += 1; writes_pending += 1;
xfer = libusb_alloc_transfer(0); xfer = libusb_alloc_transfer(0);
//timeout if in 1000 milliseconds it hasn't been sent //timeout if in 1000 milliseconds it hasn't been sent
xfer->timeout=1000; xfer->timeout=1000;
buf = (unsigned char *)malloc(datalen); buf = (unsigned char *)malloc(datalen);
memcpy(buf, data, datalen); memcpy(buf, data, datalen);
libusb_fill_bulk_transfer(xfer, usb_dev, dev_info->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); 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
usb_debug_msg("Preparing to send", dev_info->ep_out, data, datalen);
} }