amidi: add timestamp option for dump

Added -T / --timestamp option (with parameter "realtime", "monotonic" or "raw") which prints
a timestamp before each received message when using the --dump mode.

Fixes: https://github.com/alsa-project/alsa-utils/pull/108
Signed-off-by: Folkert van Heusden <mail@vanheusden.com>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
This commit is contained in:
folkert van heusden 2021-08-24 11:49:43 +02:00 committed by Jaroslav Kysela
parent dea51861a8
commit 9a8fcec5aa

View file

@ -36,11 +36,13 @@
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
#include <alsa/asoundlib.h> #include <alsa/asoundlib.h>
#include <time.h>
#include "aconfig.h" #include "aconfig.h"
#include "version.h" #include "version.h"
#define NSEC_PER_SEC 1000000000L #define NSEC_PER_SEC 1000000000L
static int do_print_timestamp = 0;
static int do_device_list, do_rawmidi_list; static int do_device_list, do_rawmidi_list;
static char *port_name = "default"; static char *port_name = "default";
static char *send_file_name; static char *send_file_name;
@ -80,6 +82,10 @@ static void usage(void)
"-r, --receive=file write received data into a file\n" "-r, --receive=file write received data into a file\n"
"-S, --send-hex=\"...\" send hexadecimal bytes\n" "-S, --send-hex=\"...\" send hexadecimal bytes\n"
"-d, --dump print received data as hexadecimal bytes\n" "-d, --dump print received data as hexadecimal bytes\n"
"-T, --timestamp=... adds a timestamp in front of each dumped message\n"
" realtime\n"
" monotonic\n"
" raw\n"
"-t, --timeout=seconds exits when no data has been received\n" "-t, --timeout=seconds exits when no data has been received\n"
" for the specified duration\n" " for the specified duration\n"
"-a, --active-sensing include active sensing bytes\n" "-a, --active-sensing include active sensing bytes\n"
@ -356,7 +362,7 @@ static void parse_data(void)
/* /*
* prints MIDI commands, formatting them nicely * prints MIDI commands, formatting them nicely
*/ */
static void print_byte(unsigned char byte) static void print_byte(unsigned char byte, struct timespec *ts)
{ {
static enum { static enum {
STATE_UNKNOWN, STATE_UNKNOWN,
@ -426,7 +432,18 @@ static void print_byte(unsigned char byte)
if (running_status) if (running_status)
fputs("\n ", stdout); fputs("\n ", stdout);
} }
printf("%c%02X", newline ? '\n' : ' ', byte);
if (newline) {
printf("\n");
/* Nanoseconds does not make a lot of sense for serial MIDI (the
* 31250 bps one) but I'm not sure about MIDI over USB.
*/
if (do_print_timestamp)
printf("%lld.%.9ld) ", (long long)ts->tv_sec, ts->tv_nsec);
}
printf("%02X", byte);
} }
static void sig_handler(int dummy) static void sig_handler(int dummy)
@ -454,7 +471,7 @@ static void add_send_hex_data(const char *str)
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
static const char short_options[] = "hVlLp:s:r:S::dt:aci:"; static const char short_options[] = "hVlLp:s:r:S::dt:aci:T:";
static const struct option long_options[] = { static const struct option long_options[] = {
{"help", 0, NULL, 'h'}, {"help", 0, NULL, 'h'},
{"version", 0, NULL, 'V'}, {"version", 0, NULL, 'V'},
@ -465,6 +482,7 @@ int main(int argc, char *argv[])
{"receive", 1, NULL, 'r'}, {"receive", 1, NULL, 'r'},
{"send-hex", 2, NULL, 'S'}, {"send-hex", 2, NULL, 'S'},
{"dump", 0, NULL, 'd'}, {"dump", 0, NULL, 'd'},
{"timestamp", 1, NULL, 'T'},
{"timeout", 1, NULL, 't'}, {"timeout", 1, NULL, 't'},
{"active-sensing", 0, NULL, 'a'}, {"active-sensing", 0, NULL, 'a'},
{"clock", 0, NULL, 'c'}, {"clock", 0, NULL, 'c'},
@ -475,6 +493,7 @@ int main(int argc, char *argv[])
int ignore_active_sensing = 1; int ignore_active_sensing = 1;
int ignore_clock = 1; int ignore_clock = 1;
int do_send_hex = 0; int do_send_hex = 0;
clockid_t cid = CLOCK_REALTIME;
struct itimerspec itimerspec = { .it_interval = { 0, 0 } }; struct itimerspec itimerspec = { .it_interval = { 0, 0 } };
while ((c = getopt_long(argc, argv, short_options, while ((c = getopt_long(argc, argv, short_options,
@ -509,6 +528,19 @@ int main(int argc, char *argv[])
case 'd': case 'd':
dump = 1; dump = 1;
break; break;
case 'T':
do_print_timestamp = 1;
if (optarg == NULL)
error("Clock type missing");
else if (strcasecmp(optarg, "realtime") == 0)
cid = CLOCK_REALTIME;
else if (strcasecmp(optarg, "monotonic") == 0)
cid = CLOCK_MONOTONIC;
else if (strcasecmp(optarg, "raw") == 0)
cid = CLOCK_MONOTONIC_RAW;
else
error("Clock type not known");
break;
case 't': case 't':
if (optarg) if (optarg)
timeout = atof(optarg); timeout = atof(optarg);
@ -611,6 +643,7 @@ int main(int argc, char *argv[])
} }
if (inputp) { if (inputp) {
int need_timestamp = 0;
int read = 0; int read = 0;
int npfds; int npfds;
struct pollfd *pfds; struct pollfd *pfds;
@ -644,10 +677,12 @@ int main(int argc, char *argv[])
goto _exit; goto _exit;
} }
} }
for (;;) { for (;;) {
unsigned char buf[256]; unsigned char buf[256];
int i, length; int i, length;
unsigned short revents; unsigned short revents;
struct timespec ts;
err = poll(pfds, npfds, -1); err = poll(pfds, npfds, -1);
if (stop || (err < 0 && errno == EINTR)) if (stop || (err < 0 && errno == EINTR))
@ -657,6 +692,11 @@ int main(int argc, char *argv[])
break; break;
} }
if (clock_gettime(cid, &ts) < 0) {
error("clock_getres (%d) failed: %s", cid, strerror(errno));
break;
}
err = snd_rawmidi_poll_descriptors_revents(input, &pfds[1], npfds - 1, &revents); err = snd_rawmidi_poll_descriptors_revents(input, &pfds[1], npfds - 1, &revents);
if (err < 0) { if (err < 0) {
error("cannot get poll events: %s", snd_strerror(errno)); error("cannot get poll events: %s", snd_strerror(errno));
@ -688,14 +728,12 @@ int main(int argc, char *argv[])
continue; continue;
read += length; read += length;
if (receive_file != -1) { if (receive_file != -1)
ssize_t wlength = write(receive_file, buf, length); write(receive_file, buf, length);
if (wlength != length)
error("write error: %s", wlength < 0 ? strerror(errno) : "short");
}
if (dump) { if (dump) {
for (i = 0; i < length; ++i) for (i = 0; i < length; ++i)
print_byte(buf[i]); print_byte(buf[i], &ts);
fflush(stdout); fflush(stdout);
} }