rtl_433/src/write_sigrok.c

277 lines
7.5 KiB
C

/** @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>
#include <string.h>
#ifndef _MSC_VER
#include <unistd.h>
#endif
#ifndef _WIN32
#include <sys/types.h>
#include <sys/wait.h>
#endif
#ifdef _WIN32
#include <windows.h>
#endif
#include "fatal.h"
#include "write_sigrok.h"
void write_sigrok(char const *filename, unsigned samplerate, unsigned probes, unsigned analogs, char const *labels[])
{
// 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);
#ifdef _WIN32
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
char cmd_line[MAX_PATH] = "";
strcat_s(cmd_line, MAX_PATH, "7z.exe");
strcat_s(cmd_line, MAX_PATH, " a");
strcat_s(cmd_line, MAX_PATH, " -bb0 ");
strcat_s(cmd_line, MAX_PATH, " -sdel ");
strcat_s(cmd_line, MAX_PATH, " -tzip ");
strcat_s(cmd_line, MAX_PATH, filename);
strcat_s(cmd_line, MAX_PATH, " version");
strcat_s(cmd_line, MAX_PATH, " metadata");
if (probes) {
strcat_s(cmd_line, MAX_PATH, " logic-1-1");
}
char str_buf[64];
for (unsigned i = probes + 1; i <= probes + analogs; ++i) {
snprintf(str_buf, sizeof(str_buf), " analog-1-%u-1", i);
strcat_s(cmd_line, MAX_PATH, str_buf);
}
// Start the child process.
if (CreateProcess(NULL, // No module name (use command line)
cmd_line, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi) // Pointer to PROCESS_INFORMATION structure
) {
// Wait until child process exits.
WaitForSingleObject(pi.hProcess, INFINITE);
DWORD exit_code;
if (FALSE == GetExitCodeProcess(pi.hProcess, &exit_code)) {
perror("GetExitCodeProcess() failure");
}
// Close process and thread handles.
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
if (exit_code != 0) {
perror("7z.exe execution failed");
return;
}
}
else {
perror("CreateProcess for 7z.exe failed.");
return;
}
#else
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_dups[30] = {0}; // store only dups to help the checker match the free()
char **argv_analog = &argv[arg];
char str_buf[64];
for (unsigned i = probes + 1; i <= probes + analogs; ++i) {
snprintf(str_buf, sizeof(str_buf), "analog-1-%u-1", i);
char* dup = strdup(str_buf);
if (!dup) {
FATAL_STRDUP("write_sigrok()");
}
argv[arg++] = dup;
argv_dups[arg++] = dup;
}
int status = 0;
pid_t pid = fork();
if (pid < 0) {
perror("forking zip");
}
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(&status);
if (WIFEXITED(status)) {
if (WEXITSTATUS(status)) {
fprintf(stderr, "zip exited with status: %d\n", WEXITSTATUS(status));
}
}
}
// 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 && argv_analog[i]; ++i) {
if (unlink(argv_analog[i])) {
perror("unlinking Sigrok \"analog-1-N-1\" file");
}
}
for (int i = 0; i < arg; ++i) {
free(argv_dups[i]);
}
#endif // !_WIN32
}
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");
int status = 0;
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(&status);
if (WIFEXITED(status)) {
if (WEXITSTATUS(status)) {
fprintf(stderr, "pulseview open exited with status: %d\n", WEXITSTATUS(status));
}
}
}
free(abspath);
#endif
}