diff options
Diffstat (limited to 'src/tts-uart.c')
-rw-r--r-- | src/tts-uart.c | 270 |
1 files changed, 270 insertions, 0 deletions
diff --git a/src/tts-uart.c b/src/tts-uart.c new file mode 100644 index 0000000..32f8ae7 --- /dev/null +++ b/src/tts-uart.c @@ -0,0 +1,270 @@ +/* + * bin2tts.c + * + * Convert binary file to TTS (transisition/timestamp) format. + * + * Copyright (C) 2016 Daniel Thompson <daniel.thompson@linaro.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + */ + +#include <assert.h> +#include <errno.h> +#include <getopt.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +struct ctx { + bool auto_baud; + int baud_rate; + uint32_t mask; + bool verbose; + + double t_period; + + double t_start; + double t_next; + double t_stop; + uint16_t frame; + int n_bits; + + double t_prev; + double t_narrow; + + + bool prev_pin; +}; + +/* + * + * -------+ +-----+-----+-----+-----+-----+-----+-----+-----+-----+------- + * |START| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | P |STOP + * +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+ + * + * ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ + */ + +void handle_start(struct ctx *ctx, double t_now) +{ + if (ctx->verbose) + fprintf(stderr, "[%10.6f] START\n", t_now); + + ctx->t_start = t_now; + ctx->t_next = t_now + 1.501 * ctx->t_period; + ctx->t_stop = t_now + 9.409 * ctx->t_period; + ctx->frame = 0; + ctx->n_bits = 0; +} + +void handle_data(struct ctx *ctx, bool pin, double t_now) +{ + while (ctx->t_next < t_now) { + if (ctx->verbose) + fprintf(stderr, "[%10.6f] D%d -> %d\n", ctx->t_next, + ctx->n_bits, pin); + ctx->frame = ctx->frame >> 1 | (pin ? 0x80 : 0); + + ctx->t_next += ctx->t_period; + ctx->n_bits++; + } +} + +void handle_stop(struct ctx *ctx) +{ + if (ctx->prev_pin) { + if (ctx->verbose) { + fprintf(stderr, "[%10.6f] STOP. Got 0x%02x\n", ctx->t_next, ctx->frame); + } + handle_data(ctx, 1, ctx->prev_pin); + + putchar(ctx->frame); + fflush(stdout); + } else { + fprintf(stderr, "[%10.6f] Framing error\n", ctx->t_next); + } + + ctx->t_start = 0; +} + +void handle_error(struct ctx *ctx) +{ + fprintf(stderr, "[%10.6f] Framing error\n", ctx->t_stop); + + ctx->t_start = 0; +} + +void handle_edge(struct ctx *ctx, bool pin, double t_now) +{ + double t_pulse = t_now - ctx->t_prev; + + assert(t_pulse >= 0); + if (pin != ctx->prev_pin) + if (t_pulse < ctx->t_narrow || ctx->t_narrow == 0) + ctx->t_narrow = t_pulse; + + if (ctx->baud_rate) { + if (0 != ctx->t_start && t_now > ctx->t_stop) + handle_stop(ctx); + + if (0 == ctx->t_start) { + if (!pin) + handle_start(ctx, t_now); + } else { + handle_data(ctx, ctx->prev_pin, t_now); + } + } + + ctx->prev_pin = pin; + ctx->t_prev = t_now; +} + +void do_auto_baud(struct ctx *ctx) +{ + int baud_rates[] = { 110, 300, 600, 1200, 2400, 4800, + 9600, 14400, 19200, 28800, 38400, 56000, + 57600, 115200, + 128000, 153600, 230400, 256000, 460800, 921600, + 0 }; + + /* + * At the moment we assume that beating between analyzer s/freq + * and baud rate mean that the quantized baud will been rounded + * *down* from the true narrowest pulse. + */ + double quantized_baud = 1 / ctx->t_narrow; + + int i; + + for (i=0; baud_rates[i]; i++) + if (baud_rates[i] > quantized_baud) + break; + + if (i == 0 || !baud_rates[i]) + printf("Baud rate looks bad (%s signal?). Estimated at %d.\n", + i ? "noisy" : "no", (int)quantized_baud); + else + printf( + "Detected baud rate of %d (rounded from estimate of %d)\n", + baud_rates[i-1], (int) quantized_baud); +} + +void decode(struct ctx *ctx, FILE *f) +{ + uint32_t seconds; + uint32_t nanoseconds; + double t; + uint32_t data; + + ctx->t_period = 1.0 / ctx->baud_rate; + ctx->prev_pin = true; + + while (!feof(f)) { + int res = fscanf(f, "[%5d.%09d] 0x%02x\n", &seconds, + &nanoseconds, &data); + if (res != 3) { + printf("Can't parse input: %d\n", res); + break; + } + + t = (double) seconds + nanoseconds / 1000000000.0; + bool pin = data & ctx->mask; + + if (ctx->verbose) + fprintf(stderr, "[%10.6f] Pin %d -> %d\n", t, ctx->prev_pin, pin); + + handle_edge(ctx, pin, t); + } + + if (ctx->auto_baud) + do_auto_baud(ctx); +} + +void show_usage(bool full) +{ + FILE *f = full ? stdout : stderr; + + fprintf(f, "Usage: tts-uart [OPTION]... [FILE]...\n"); + + if (!full) { + fprintf(f, "Try --help for more information.\n"); + return; + } + + fprintf(f, +"\n" +"Mandatory arguments to long options are mandatory for short options too.\n" +" --auto-baud try to detect the baud rate\n" +" -b, --baud-rate=B set the baud rate to B\n" +" -h, --help show this help, then exit\n" +" -m, --mask=M used to select the right bit for decoding\n" +" -v, --verbose show timestamps for each bit\n" + ); +} + +int main(int argc, char *argv[]) +{ + int c; + struct ctx ctx = { + .auto_baud = false, + .mask = 0x01, + }; + + const struct option opts[] = { + { "auto-baud", no_argument, 0, 256 }, + { "baud-rate", required_argument, 0, 'b' }, + { "help", no_argument, 0, 'h' }, + { "mask", required_argument, 0, 'm' }, + { "verbose", no_argument, 0, 'v' }, + { 0 }, + }; + + while ((c = getopt_long(argc, argv, "b:m:h", opts, NULL)) != -1) { + switch (c) { + case 256: // --auto-baud + ctx.auto_baud = true; + break; + case 'b': + ctx.baud_rate = strtol(optarg, NULL, 0); + break; + case 'h': + show_usage(true); + return 0; + case 'm': + ctx.mask = strtol(optarg, NULL, 0); + break; + case 'v': + ctx.verbose = true; + break; + default: + fprintf(stderr, "Try --help for more information.\n"); + return 1; + } + } + + if (optind >= argc) { + decode(&ctx, stdin); + } else while (optind < argc) { + FILE *f = fopen(argv[optind], "rb"); + + if (!f) { + fprintf(stderr, "Cannot open '%s' (%s)\n", argv[optind], + strerror(errno)); + return 10; + } + + decode(&ctx, f); + + fclose(f); + optind++; + } + + return 0; +} + |