diff --git a/examples/sigrok-conv.sh b/examples/sigrok-conv.sh index 070edac9..c7560989 100755 --- a/examples/sigrok-conv.sh +++ b/examples/sigrok-conv.sh @@ -1,61 +1,3 @@ #!/bin/bash -if [ -z "$1" ] ; then - echo input file missing - echo "Usage: $0 input.cu8 output.sr [sample rate in kHz]" - exit 1 -fi -if [ ! -r "$1" ] ; then - echo input not found - echo "Usage: $0 input.cu8 output.sr [sample rate in kHz]" - exit 1 -fi -file=$1 - -if [ -z "$2" ] ; then - echo output file missing - echo "Usage: $0 input.cu8 output.sr [sample rate in kHz]" - exit 1 -fi -if [ -e "$2" ] ; then - echo output already exists - echo "Usage: $0 input.cu8 output.sr [sample rate in kHz]" - exit 1 -fi -out=$2 - -if [ -z "$3" ] ; then - rate=250 -else - rate=$3 -fi - -if [ ! -z "$4" ] ; then - echo too many arguments - echo "Usage: $0 input.cu8 output.sr [sample rate in kHz]" - exit 1 -fi - -# create channels -rtl_433 -s ${rate}k -r "$file" -w F32:I:analog-1-4-1 -w F32:Q:analog-1-5-1 -w F32:AM:analog-1-6-1 -w F32:FM:analog-1-7-1 -w U8:LOGIC:logic-1-1 >/dev/null 2>&1 -# create version tag -echo -n "2" >version -# create meta data -cat >metadata <<EOF -[device 1] -capturefile=logic-1 -total probes=3 -samplerate=$rate kHz -total analog=4 -probe1=FRAME -probe2=ASK -probe3=FSK -analog4=I -analog5=Q -analog6=AM -analog7=FM -unitsize=1 -EOF - -zip "$out" version metadata analog-1-4-1 analog-1-5-1 analog-1-6-1 analog-1-7-1 logic-1-1 -rm version metadata analog-1-4-1 analog-1-5-1 analog-1-6-1 analog-1-7-1 logic-1-1 +echo 'Please use "rtl_433 [-s <samplerate>] -w <output>.sr -r <input>.cu8"' diff --git a/examples/sigrok-open.sh b/examples/sigrok-open.sh index 6a10dfed..39ad80bc 100755 --- a/examples/sigrok-open.sh +++ b/examples/sigrok-open.sh @@ -1,67 +1,3 @@ #!/bin/bash -if [ -z "$1" ] ; then - echo input file missing - echo "Usage: $0 input.cu8 [sample rate in kHz]" - exit 1 -fi -if [ ! -r "$1" ] ; then - echo input not found - echo "Usage: $0 input.cu8 [sample rate in kHz]" - exit 1 -fi -file=$1 - -filename=$(basename "$file") -tempdir=$(mktemp -d) -out="$tempdir/$filename.sr" -trap "rm -f -- '$out'; rmdir -- '$tempdir'" EXIT - -if [ -z "$2" ] ; then - rate=250 -else - rate=$2 -fi - -if [ ! -z "$3" ] ; then - echo too many arguments - echo "Usage: $0 input.cu8 [sample rate in kHz]" - exit 1 -fi - -# create channels -rtl_433 -s ${rate}k -r "$file" -w F32:I:analog-1-4-1 -w F32:Q:analog-1-5-1 -w F32:AM:analog-1-6-1 -w F32:FM:analog-1-7-1 -w U8:LOGIC:logic-1-1 >/dev/null 2>&1 -# create version tag -echo -n "2" >version -# create meta data -cat >metadata <<EOF -[device 1] -capturefile=logic-1 -total probes=3 -samplerate=$rate kHz -total analog=4 -probe1=FRAME -probe2=ASK -probe3=FSK -analog4=I -analog5=Q -analog6=AM -analog7=FM -unitsize=1 -EOF - -zip "$out" version metadata analog-1-4-1 analog-1-5-1 analog-1-6-1 analog-1-7-1 logic-1-1 -rm version metadata analog-1-4-1 analog-1-5-1 analog-1-6-1 analog-1-7-1 logic-1-1 - -case "$OSTYPE" in - darwin*) - open -b org.sigrok.PulseView --fresh --new --wait-apps --args -i "$out" - ;; - *) - pulseview -i "$out" - ;; -esac - -rm -f -- "$out" -rmdir -- "$tempdir" -trap - EXIT +echo 'Please use "rtl_433 [-s <samplerate>] -W <output>.sr -r <input>.cu8"' diff --git a/include/r_api.h b/include/r_api.h index e8711576..790282f5 100644 --- a/include/r_api.h +++ b/include/r_api.h @@ -86,6 +86,10 @@ void add_null_output(struct r_cfg *cfg, char *param); void start_outputs(struct r_cfg *cfg, char const **well_known); +void add_sr_dumper(struct r_cfg *cfg, char const *spec, int overwrite); + +void close_dumpers(struct r_cfg *cfg); + void add_dumper(struct r_cfg *cfg, char const *spec, int overwrite); void add_infile(struct r_cfg *cfg, char *in_file); diff --git a/include/rtl_433.h b/include/rtl_433.h index c42fb6bc..c41331e1 100644 --- a/include/rtl_433.h +++ b/include/rtl_433.h @@ -94,6 +94,8 @@ typedef struct r_cfg { char *output_tag; list_t output_handler; struct dm_state *demod; + char const *sr_filename; + int sr_execopen; int old_model_keys; /* stats*/ unsigned frames_count; ///< stats counter for interval diff --git a/include/write_sigrok.h b/include/write_sigrok.h new file mode 100644 index 00000000..521631ae --- /dev/null +++ b/include/write_sigrok.h @@ -0,0 +1,31 @@ +/** @file + Sigrok Pulseview format writer. + + Copyright (C) 2020 by Christian Zuckschwerdt <zany@triq.net> + + 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 2 of the License, or + (at your option) any later version. +*/ + +#ifndef INCLUDE_WRITE_SIGROK_ +#define INCLUDE_WRITE_SIGROK_ + +/** Write a Sigrok file from data dump files. + + @param filename file to write + @param samplerate sample rate for the channels + @param probes number of binary channels, needs "logic-1-1" file + @param analogs number of analog channels, needs "analog-1-N-1" with N starting at probes+1 + @param labels channel labels, probes+analog strings or NULL for generic labels +*/ +void write_sigrok(char const *filename, unsigned samplerate, unsigned probes, unsigned analogs, char const *labels[]); + +/** Open a file in a forked Pulseview. + + @param filename file to open in Pulseview +*/ +void open_pulseview(char const *filename); + +#endif /* INCLUDE_WRITE_SIGROK_ */ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 400931c1..e6470058 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -29,6 +29,7 @@ add_library(r_433 STATIC sdr.c term_ctl.c util.c + write_sigrok.c devices/acurite.c devices/akhan_100F14.c devices/alecto.c diff --git a/src/r_api.c b/src/r_api.c index f181212a..fad2293c 100644 --- a/src/r_api.c +++ b/src/r_api.c @@ -28,6 +28,7 @@ #include "optparse.h" #include "output_mqtt.h" #include "output_influx.h" +#include "write_sigrok.h" #include "compat_time.h" #include "fatal.h" @@ -878,8 +879,45 @@ void add_null_output(r_cfg_t *cfg, char *param) list_push(&cfg->output_handler, NULL); } +void add_sr_dumper(r_cfg_t *cfg, char const *spec, int overwrite) +{ + // create channels + add_dumper(cfg, "U8:LOGIC:logic-1-1", overwrite); + add_dumper(cfg, "F32:I:analog-1-4-1", overwrite); + add_dumper(cfg, "F32:Q:analog-1-5-1", overwrite); + add_dumper(cfg, "F32:AM:analog-1-6-1", overwrite); + add_dumper(cfg, "F32:FM:analog-1-7-1", overwrite); + cfg->sr_filename = spec; + cfg->sr_execopen = overwrite; +} + +void close_dumpers(struct r_cfg *cfg) +{ + char const *labels[] = { + "FRAME", // probe1 + "ASK", // probe2 + "FSK", // probe3 + "I", // analog4 + "Q", // analog5 + "AM", // analog6 + "FM", // analog7 + }; + if (cfg->sr_filename) { + write_sigrok(cfg->sr_filename, cfg->samp_rate, 3, 4, labels); + } + if (cfg->sr_execopen) { + open_pulseview(cfg->sr_filename); + } +} + void add_dumper(r_cfg_t *cfg, char const *spec, int overwrite) { + size_t spec_len = strlen(spec); + if (spec_len >= 3 && !strcmp(&spec[spec_len - 3], ".sr")) { + add_sr_dumper(cfg, spec, overwrite); + return; + } + file_info_t *dumper = calloc(1, sizeof(*dumper)); if (!dumper) FATAL_CALLOC("add_dumper()"); diff --git a/src/rtl_433.c b/src/rtl_433.c index 2c625825..e98c7c2f 100644 --- a/src/rtl_433.c +++ b/src/rtl_433.c @@ -48,6 +48,7 @@ #include "term_ctl.h" #include "compat_paths.h" #include "fatal.h" +#include "write_sigrok.h" #ifdef _WIN32 #include <io.h> @@ -1465,12 +1466,18 @@ int main(int argc, char **argv) { fclose(in_file = stdin); } + close_dumpers(cfg); free(test_mode_buf); free(test_mode_float_buf); r_free_cfg(cfg); exit(0); } + if (cfg->sr_filename) { + fprintf(stderr, "SR writing not recommended for live input\n"); + exit(1); + } + // Normal case, no test data, no in files r = sdr_open(&cfg->dev, &demod->sample_size, cfg->dev_query, cfg->verbosity); if (r < 0) { diff --git a/src/write_sigrok.c b/src/write_sigrok.c new file mode 100644 index 00000000..5135c5a9 --- /dev/null +++ b/src/write_sigrok.c @@ -0,0 +1,184 @@ +/** @file + Sigrok Pulseview format writer. + + Copyright (C) 2020 by Christian Zuckschwerdt <zany@triq.net> + + 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 2 of the License, or + (at your option) any later version. +*/ + +#include <stdio.h> +#include <stdlib.h> +#ifndef _MSC_VER +#include <unistd.h> +#endif + +#include "write_sigrok.h" + +void write_sigrok(char const *filename, unsigned samplerate, unsigned probes, unsigned analogs, char const *labels[]) +{ +#ifdef _WIN32 + fprintf(stderr, "Writing Sigrok not implemented for win32\n"); +#else + // e.g. uses channels + // U8:LOGIC:logic-1-1 + // F32:I:analog-1-4-1 + // F32:Q:analog-1-5-1 + // F32:AM:analog-1-6-1 + // F32:FM:analog-1-7-1 + + // probe1=FRAME + // probe2=ASK + // probe3=FSK + // analog4=I + // analog5=Q + // analog6=AM + // analog7=FM + + // create version tag + FILE *fp = fopen("version", "w"); + if (!fp) { + perror("creating Sigrok \"version\" file"); + return; + } + fprintf(fp, "2"); + fclose(fp); + + // create meta data + fp = fopen("metadata", "w"); + if (!fp) { + perror("creating Sigrok \"metadata\" file"); + return; + } + fprintf(fp, + "[device 1]\n" + "samplerate=%u kHz\n" + "capturefile=logic-1\n" + "unitsize=1\n" + "total probes=%u\n" + "total analog=%u\n", + samplerate / 1000, probes, analogs); + if (labels) { + char const **label = labels; + for (unsigned i = 1; i <= probes; ++i) + fprintf(fp, "probe%u=%s\n", i, *label++); + for (unsigned i = probes + 1; i <= probes + analogs; ++i) + fprintf(fp, "analog%u=%s\n", i, *label++); + } + else { + for (unsigned i = 1; i <= probes; ++i) + fprintf(fp, "probe%u=L%u\n", i, i); + for (unsigned i = probes + 1; i <= probes + analogs; ++i) + fprintf(fp, "analog%u=A%u\n", i, i); + } + + // EOF + fclose(fp); + + char *argv[30] = {0}; + int arg = 0; + argv[arg++] = "zip"; + argv[arg++] = (char *)filename; // "out.sr" + argv[arg++] = "version"; + argv[arg++] = "metadata"; + + if (probes) { + argv[arg++] = "logic-1-1"; + } + + char **argv_analog = &argv[arg]; + for (unsigned i = probes + 1; i <= probes + analogs; ++i) { + asprintf(&argv[arg++], "analog-1-%u-1", i); + } + + pid_t pid = fork(); + if (pid < 0) { + perror("forking zip"); + return; + } + else if (pid == 0) { + // child process because return value zero + execvp(argv[0], argv); + // execvp() returns only on error + for (int i = 0; i < arg; ++i) + fprintf(stderr, "%s ", argv[i]); + fprintf(stderr, "\n"); + perror("execvp"); + exit(1); + } + else { + // parent process because return value non-zero + wait(NULL); + printf("Done!\n"); + } + + // rm version metadata logic-1-1 analog-1-4-1 analog-1-5-1 analog-1-6-1 analog-1-7-1 + if (unlink("version")) { + perror("unlinking Sigrok \"version\" file"); + } + if (unlink("metadata")) { + perror("unlinking Sigrok \"metadata\" file"); + } + + if (probes) { + if (unlink("logic-1-1")) { + perror("unlinking Sigrok \"logic-1-1\" file"); + } + } + for (unsigned i = 0; i < analogs; ++i) { + if (unlink(argv_analog[i])) { + perror("unlinking Sigrok \"analog-1-N-1\" file"); + } + free(argv_analog[i]); + } +#endif +} + +void open_pulseview(char const *filename) +{ +#ifdef _WIN32 + fprintf(stderr, "Opening Pulseview not implemented for win32\n"); +#else + char *argv[9] = {0}; + int arg = 0; + char *abspath = realpath(filename, NULL); +#ifdef __APPLE__ + argv[arg++] = "open"; + argv[arg++] = "-b"; + argv[arg++] = "org.sigrok.PulseView"; + argv[arg++] = "--fresh"; + argv[arg++] = "--new"; + argv[arg++] = "--args"; + argv[arg++] = "-i"; + argv[arg++] = (char *)abspath; +#else + argv[arg++] = "pulseview"; + argv[arg++] = "-i"; + argv[arg++] = abspath; +#endif + + fprintf(stderr, "Opening Pulseview...\n"); + pid_t pid = fork(); + if (pid < 0) { + perror("forking pulseview"); + return; + } + else if (pid == 0) { + // child process because return value zero + execvp(argv[0], argv); + // execvp() returns only on error + for (int i = 0; i < arg; ++i) + fprintf(stderr, "%s ", argv[i]); + fprintf(stderr, "\n"); + perror("execvp"); + exit(1); + } + else { + // parent process because return value non-zero + wait(NULL); + } + free(abspath); +#endif +}