/* * hsdaoh - High Speed Data Acquisition over MS213x USB3 HDMI capture sticks * * Copyright (C) 2024 by Steve Markgraf * * SPDX-License-Identifier: GPL-2.0+ * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #ifndef _WIN32 #include #else #include #include #include #include "getopt/getopt.h" #endif #include "hsdaoh.h" #define DEFAULT_SAMPLE_RATE 30000000 static int do_exit = 0; static uint32_t bytes_to_read = 0; static hsdaoh_dev_t *dev = NULL; void usage(void) { fprintf(stderr, "hsdaoh_file, HDMI data acquisition tool\n\n" "Usage:\n" "\t[-s samplerate (default: 30 MHz)]\n" "\t[-d device_index (default: 0)]\n" "\t[-p ppm_error (default: 0)]\n" "\t[-n number of samples to read (default: 0, infinite)]\n" "\tfilename (a '-' dumps samples to stdout)\n\n"); exit(1); } #ifdef _WIN32 BOOL WINAPI sighandler(int signum) { if (CTRL_C_EVENT == signum) { fprintf(stderr, "Signal caught, exiting!\n"); do_exit = 1; hsdaoh_stop_stream(dev); return TRUE; } return FALSE; } #else static void sighandler(int signum) { signal(SIGPIPE, SIG_IGN); fprintf(stderr, "Signal caught, exiting!\n"); do_exit = 1; hsdaoh_stop_stream(dev); } #endif static void hsdaoh_callback(unsigned char *buf, uint32_t len, void *ctx) { size_t nbytes = 0; if (ctx) { if (do_exit) return; if ((bytes_to_read > 0) && (bytes_to_read < len)) { len = bytes_to_read; do_exit = 1; hsdaoh_stop_stream(dev); } while (nbytes < len) { nbytes += fwrite(buf + nbytes, 1, len - nbytes, (FILE*)ctx); if (ferror((FILE*)ctx)) { fprintf(stderr, "Error writing file, samples lost, exiting!\n"); hsdaoh_stop_stream(dev); break; } } if (bytes_to_read > 0) bytes_to_read -= len; } } int main(int argc, char **argv) { #ifndef _WIN32 struct sigaction sigact; #endif char *filename = NULL; int n_read; int r, opt; int ppm_error = 0; FILE *file; int dev_index = 0; uint32_t samp_rate = DEFAULT_SAMPLE_RATE; while ((opt = getopt(argc, argv, "d:s:n:p:d:")) != -1) { switch (opt) { case 'd': dev_index = (uint32_t)atoi(optarg); break; case 's': samp_rate = (uint32_t)atof(optarg); break; case 'p': ppm_error = atoi(optarg); break; case 'n': bytes_to_read = (uint32_t)atof(optarg) * 2; break; default: usage(); break; } } if (argc <= optind) { usage(); } else { filename = argv[optind]; } if (dev_index < 0) { exit(1); } r = hsdaoh_open(&dev, (uint32_t)dev_index); if (r < 0) { fprintf(stderr, "Failed to open hsdaoh device #%d.\n", dev_index); exit(1); } #ifndef _WIN32 sigact.sa_handler = sighandler; sigemptyset(&sigact.sa_mask); sigact.sa_flags = 0; sigaction(SIGINT, &sigact, NULL); sigaction(SIGTERM, &sigact, NULL); sigaction(SIGQUIT, &sigact, NULL); sigaction(SIGPIPE, &sigact, NULL); #else SetConsoleCtrlHandler( (PHANDLER_ROUTINE) sighandler, TRUE ); #endif /* Set the sample rate */ r = hsdaoh_set_sample_rate(dev, samp_rate, 0); if (r < 0) fprintf(stderr, "WARNING: Failed to set sample rate.\n"); if (strcmp(filename, "-") == 0) { /* Write samples to stdout */ file = stdout; #ifdef _WIN32 _setmode(_fileno(stdin), _O_BINARY); #endif } else { file = fopen(filename, "wb"); if (!file) { fprintf(stderr, "Failed to open %s\n", filename); goto out; } } fprintf(stderr, "Reading samples...\n"); r = hsdaoh_start_stream(dev, hsdaoh_callback, (void *)file); while (!do_exit) { usleep(50000); } if (do_exit) fprintf(stderr, "\nUser cancel, exiting...\n"); else fprintf(stderr, "\nLibrary error %d, exiting...\n", r); if (file != stdout) fclose(file); hsdaoh_close(dev); out: return r >= 0 ? r : -r; }