Skip to content

Commit 65040da

Browse files
committed
Use asynchronous command queue
When using libusb, process commands asynchronously to reduce the effect of serial traffic on audio.
1 parent fa04468 commit 65040da

9 files changed

+152
-10
lines changed

Makefile

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
#Set all your object files (the object files of all the .c files in your project, e.g. main.o my_sub_functions.o )
2-
OBJ = src/main.o src/serial.o src/slip.o src/command.o src/render.o src/ini.o src/config.o src/input.o src/gamecontrollers.o src/fx_cube.o src/usb.o src/audio.o src/usb_audio.o src/ringbuffer.o src/inprint2.o
2+
OBJ = src/main.o src/serial.o src/slip.o src/command.o src/render.o src/ini.o src/config.o src/input.o src/gamecontrollers.o src/fx_cube.o src/usb.o src/audio.o src/usb_audio.o src/ringbuffer.o src/inprint2.o src/command_queue.o
33

44
#Set any dependant header files so that if they are edited they cause a complete re-compile (e.g. main.h some_subfunctions.h some_definitions_file.h ), or leave blank
5-
DEPS = src/serial.h src/slip.h src/command.h src/render.h src/ini.h src/config.h src/input.h src/gamecontrollers.h src/fx_cube.h src/audio.h src/ringbuffer.h src/inline_font.h
5+
DEPS = src/serial.h src/slip.h src/command.h src/render.h src/ini.h src/config.h src/input.h src/gamecontrollers.h src/fx_cube.h src/audio.h src/ringbuffer.h src/inline_font.h src/command_queue.h
66

77
#Any special libraries you are using in your project (e.g. -lbcm2835 -lrt `pkg-config --libs gtk+-3.0` ), or leave blank
88
INCLUDES = $(shell pkg-config --libs sdl2 libserialport | sed 's/-mwindows//')

src/command_queue.c

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#include <SDL.h>
2+
3+
const int command_size = 4096;
4+
int write_cursor = 0;
5+
int read_cursor = 0;
6+
uint8_t **command_buffer;
7+
uint32_t *command_sizes;
8+
9+
void command_queue_init() {
10+
command_buffer = SDL_malloc(command_size * sizeof(uint8_t *));
11+
command_sizes = SDL_malloc(command_size * sizeof(uint32_t));
12+
}
13+
14+
void command_queue_destroy() {
15+
SDL_free(command_buffer);
16+
SDL_free(command_sizes);
17+
}
18+
19+
int command_queue_push(uint8_t *data, uint32_t size) {
20+
uint8_t *recv_buf = SDL_malloc(size * sizeof(uint8_t));
21+
SDL_memcpy(recv_buf, data, size);
22+
23+
SDL_free(command_buffer[write_cursor % command_size]);
24+
command_buffer[write_cursor % command_size] = recv_buf;
25+
command_sizes[write_cursor % command_size] = size;
26+
write_cursor++;
27+
return 1;
28+
}
29+
30+
int command_queue_pop(uint8_t **data, uint32_t *size) {
31+
int compare = write_cursor - read_cursor;
32+
if (compare == 0) {
33+
return 0;
34+
}
35+
*data = command_buffer[read_cursor % command_size];
36+
*size = command_sizes[read_cursor % command_size];
37+
read_cursor++;
38+
return compare;
39+
}

src/command_queue.h

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#ifndef COMMAND_QUEUE_H_
2+
#define COMMAND_QUEUE_H_
3+
#include <stdint.h>
4+
5+
void command_queue_init();
6+
int command_queue_push(uint8_t *data, uint32_t size);
7+
int command_queue_pop(uint8_t **data, uint32_t *size);
8+
void command_queue_destroy();
9+
#endif

src/main.c

+32-5
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,14 @@
1111
#include "SDL2_inprint.h"
1212
#include "audio.h"
1313
#include "command.h"
14+
#include "command_queue.h"
1415
#include "config.h"
15-
#include "input.h"
1616
#include "gamecontrollers.h"
17+
#include "input.h"
1718
#include "render.h"
1819
#include "serial.h"
1920
#include "slip.h"
21+
#include "usb.h"
2022

2123
enum state { QUIT, WAIT_FOR_DEVICE, RUN };
2224

@@ -40,6 +42,8 @@ int main(const int argc, char *argv[]) {
4042
SDL_Log("Using preferred device %s.\n", preferred_device);
4143
}
4244

45+
command_queue_init();
46+
4347
// Initialize the config to defaults read in the params from the
4448
// configfile if present
4549
config_params_s conf = init_config();
@@ -58,15 +62,14 @@ int main(const int argc, char *argv[]) {
5862
static const slip_descriptor_s slip_descriptor = {
5963
.buf = slip_buffer,
6064
.buf_size = sizeof(slip_buffer),
61-
.recv_message = process_command, // the function where complete slip
62-
// packets are processed further
65+
.recv_message = command_queue_push, // the function where complete slip
66+
// packets are processed further
6367
};
6468

6569
static slip_handler_s slip;
6670

6771
uint8_t prev_input = 0;
6872
uint8_t prev_note = 0;
69-
uint16_t zerobyte_packets = 0; // used to detect device disconnection
7073

7174
signal(SIGINT, intHandler);
7275
signal(SIGTERM, intHandler);
@@ -108,6 +111,9 @@ int main(const int argc, char *argv[]) {
108111
reset_display();
109112
}
110113
run = RUN;
114+
#ifdef USE_LIBUSB
115+
async_read(serial_buf, serial_read_size, &slip);
116+
#endif
111117
} else {
112118
SDL_LogCritical(SDL_LOG_CATEGORY_ERROR, "Device not detected on begin loop.");
113119
if (conf.wait_for_device == 1) {
@@ -158,6 +164,9 @@ int main(const int argc, char *argv[]) {
158164
run = RUN;
159165
port_inited = 1;
160166
screensaver_destroy();
167+
#ifdef USE_LIBUSB
168+
async_read(serial_buf, serial_read_size, &slip);
169+
#endif
161170
} else {
162171
SDL_LogCritical(SDL_LOG_CATEGORY_ERROR, "Device not detected.");
163172
run = QUIT;
@@ -227,6 +236,8 @@ int main(const int argc, char *argv[]) {
227236
}
228237
}
229238

239+
#ifndef USE_LIBUSB
240+
uint16_t zerobyte_packets = 0; // used to detect device disconnection
230241
while (1) {
231242
// read serial port
232243
const int bytes_read = serial_read(serial_buf, serial_read_size);
@@ -276,7 +287,22 @@ int main(const int argc, char *argv[]) {
276287
break;
277288
}
278289
}
279-
render_screen();
290+
#endif
291+
292+
uint8_t *command;
293+
uint32_t command_size;
294+
int draws = 0;
295+
while (command_queue_pop(&command, &command_size) > 0) {
296+
if (command_size == 0) {
297+
run = QUIT;
298+
break;
299+
}
300+
process_command(command, command_size);
301+
draws++;
302+
}
303+
if (draws > 0) {
304+
render_screen();
305+
}
280306
SDL_Delay(conf.idle_ms);
281307
}
282308
} while (run > QUIT);
@@ -292,5 +318,6 @@ int main(const int argc, char *argv[]) {
292318
close_serial_port();
293319
SDL_free(serial_buf);
294320
SDL_Quit();
321+
command_queue_destroy();
295322
return 0;
296323
}

src/serial.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ int check_serial_port() {
8989
return device_found;
9090
}
9191

92-
int init_serial(const int verbose, const char *preferred_device) {
92+
int init_serial(const int verbose, char *preferred_device) {
9393
if (m8_port != NULL) {
9494
// Port is already initialized
9595
return 1;

src/serial.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ int init_serial_with_file_descriptor(int file_descriptor);
1414
#define serial_read_size 1024
1515
#endif
1616

17-
int init_serial(int verbose, const char *preferred_device);
17+
int init_serial(int verbose, char *preferred_device);
1818
int list_devices();
1919
int check_serial_port();
2020
int reset_display();

src/usb.c

+57
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
#include <stdlib.h>
1111
#include <string.h>
1212

13+
#include "command_queue.h"
14+
#include "serial.h"
1315
#include "usb.h"
1416

1517
static int ep_out_addr = 0x03;
@@ -111,6 +113,61 @@ int bulk_transfer(int endpoint, uint8_t *serial_buf, int count, unsigned int tim
111113
return actual_length;
112114
}
113115

116+
int bulk_async_transfer(int endpoint, uint8_t *serial_buf, int count, unsigned int timeout_ms,
117+
void (*f)(struct libusb_transfer *), void *user_data) {
118+
struct libusb_transfer *transfer;
119+
transfer = libusb_alloc_transfer(1);
120+
libusb_fill_bulk_stream_transfer(transfer, devh, endpoint, 0, serial_buf, count, f, user_data,
121+
timeout_ms);
122+
int r = libusb_submit_transfer(transfer);
123+
124+
if (r < 0) {
125+
SDL_Log("Error");
126+
libusb_free_transfer(transfer);
127+
return r;
128+
}
129+
return 0;
130+
}
131+
132+
void async_callback(struct libusb_transfer *xfr) {
133+
if (xfr->status != LIBUSB_TRANSFER_COMPLETED) {
134+
if (libusb_submit_transfer(xfr) < 0) {
135+
SDL_Log("error re-submitting URB\n");
136+
}
137+
return;
138+
}
139+
140+
int bytes_read = xfr->actual_length;
141+
if (bytes_read < 0) {
142+
SDL_LogCritical(SDL_LOG_CATEGORY_ERROR, "Error %d reading serial. \n", (int)bytes_read);
143+
command_queue_push(NULL, 0);
144+
} else if (bytes_read > 0) {
145+
uint8_t *serial_buf = xfr->buffer;
146+
uint8_t *cur = serial_buf;
147+
const uint8_t *end = serial_buf + bytes_read;
148+
slip_handler_s *slip = (slip_handler_s *)xfr->user_data;
149+
while (cur < end) {
150+
// process the incoming bytes into commands and draw them
151+
int n = slip_read_byte(slip, *(cur++));
152+
if (n != SLIP_NO_ERROR) {
153+
if (n == SLIP_ERROR_INVALID_PACKET) {
154+
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Invalid SLIP packet!\n");
155+
156+
} else {
157+
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "SLIP error %d\n", n);
158+
}
159+
}
160+
}
161+
}
162+
if (libusb_submit_transfer(xfr) < 0) {
163+
SDL_Log("error re-submitting URB\n");
164+
}
165+
}
166+
167+
int async_read(uint8_t *serial_buf, int count, slip_handler_s *slip) {
168+
return bulk_async_transfer(ep_in_addr, serial_buf, count, 300, &async_callback, slip);
169+
}
170+
114171
int blocking_write(void *buf, int count, unsigned int timeout_ms) {
115172
return bulk_transfer(ep_out_addr, buf, count, timeout_ms);
116173
}

src/usb.h

+3
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@
22
#define M8C_USB_H_
33
#ifdef USE_LIBUSB
44

5+
#include "slip.h"
56
#include <libusb.h>
7+
68
extern libusb_device_handle *devh;
9+
int async_read(uint8_t *serial_buf, int count, slip_handler_s *slip);
710

811
#endif // USE_LIBUSB
912
#endif // M8C_USB_H_

src/usb_audio.c

+8-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ static void audio_callback(void *userdata, Uint8 *stream, int len) {
2525

2626
// If we didn't read the full len bytes, fill the rest with zeros
2727
if (read_len < len) {
28-
SDL_memset(&stream[read_len], 0, len - read_len);
28+
SDL_MixAudio(stream, &stream[read_len], len - read_len, SDL_MIX_MAXVOLUME);
2929
}
3030
}
3131

@@ -45,6 +45,13 @@ static void cb_xfr(struct libusb_transfer *xfr) {
4545
const uint8_t *data = libusb_get_iso_packet_buffer_simple(xfr, i);
4646
if (sdl_audio_device_id != 0) {
4747
uint32_t actual = ring_buffer_push(audio_buffer, data, pack->actual_length);
48+
49+
if (audio_buffer->size < audio_buffer->max_size / 4) {
50+
SDL_PauseAudio(1);
51+
} else if (audio_buffer->size > audio_buffer->max_size / 3) {
52+
SDL_PauseAudio(0);
53+
}
54+
4855
if (actual == -1) {
4956
SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "Buffer overflow!");
5057
}

0 commit comments

Comments
 (0)