From 6055d50eaf556f72653db7afa64b7003f8598684 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?BENEDEK=20L=C3=A1szl=C3=B3?= Date: Fri, 21 Feb 2025 10:48:00 +0100 Subject: [PATCH] make recorder configurable --- CMakeLists.txt | 4 +- Readme.md | 37 ++++++- src/pico-radio/CMakeLists.txt | 7 -- src/pico-radio/main.c | 80 -------------- src/recorder/CMakeLists.txt | 7 ++ src/recorder/main.c | 194 ++++++++++++++++++++++++++++++++++ 6 files changed, 235 insertions(+), 94 deletions(-) delete mode 100644 src/pico-radio/CMakeLists.txt delete mode 100644 src/pico-radio/main.c create mode 100644 src/recorder/CMakeLists.txt create mode 100644 src/recorder/main.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 866051c..b2dd0c9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ project(pico-radio C) set(CMAKE_EXPORT_COMPILE_COMMANDS true) -include_directories(include /opt/picoscope/include) +include_directories(include /opt/picoscope/include third-party/c-flags/single-header) link_directories(/opt/picoscope/lib) -add_subdirectory(src/pico-radio) +add_subdirectory(src/recorder) diff --git a/Readme.md b/Readme.md index 023bac0..92b917f 100644 --- a/Readme.md +++ b/Readme.md @@ -1,7 +1,34 @@ # Pico Radio -## Fast-streaming buffer format -1. Channel A min -2. Channel A max -3. Channel B min -4. Channel B max +## recorder +### Arguments +``` + --type, -t + Description: type for output + Default: float + + --range, -r + Description: voltage range + Default: 10V + + --channel, -c + Description: channel + Default: 0 + + --buffersize, -b + Description: buffersize + Default: 10000 + + --max_buffersize, -mb + Description: max buffersize the driver stores + Default: 50000 + + --sample_interval, -s + Description: sample interval + Default: 1000 + + --time_units, -u + Description: time units + Default: ns + +``` \ No newline at end of file diff --git a/src/pico-radio/CMakeLists.txt b/src/pico-radio/CMakeLists.txt deleted file mode 100644 index 0300524..0000000 --- a/src/pico-radio/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -file(GLOB_RECURSE SOURCES "./*.c") -add_executable(pico-radio ${SOURCES}) -target_compile_options(pico-radio PRIVATE -Wall -Wextra) -target_link_libraries(pico-radio ps2000) -set_target_properties(pico-radio PROPERTIES - RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" -) \ No newline at end of file diff --git a/src/pico-radio/main.c b/src/pico-radio/main.c deleted file mode 100644 index a303ed3..0000000 --- a/src/pico-radio/main.c +++ /dev/null @@ -1,80 +0,0 @@ -#include -#include -#include -#include -#include - -#include - -bool stop = false; - -void capture_stop(int signal) { - (void)signal; - stop = true; -} - -static const uint32_t buffersize = 10000; - -void get_overview_buffers(int16_t** overviewBuffers, int16_t overflow, uint32_t triggeredAt, int16_t triggered, int16_t auto_stop, uint32_t nValues) { - (void)overflow; - (void)triggeredAt; - (void)triggered; - (void)auto_stop; - - fprintf(stderr, "nValues: %u\n", nValues); - - static float floatbuff[10000]; // TODO variable - for (unsigned i = 0; i < nValues; i++) { - floatbuff[i] = overviewBuffers[0][i]; - floatbuff[i] /= 32768; // TODO limit.h - } - fwrite(floatbuff, sizeof(float), nValues, stdout); -} - -int main(int argc, char** argv) { - (void)argc; - (void)argv; - - int16_t unit = ps2000_open_unit(); - - if (ps2000_set_channel(unit, PS2000_CHANNEL_A, true, false, PS2000_10V) == 0) { - fprintf(stderr, "set_channel failed!\n"); - ps2000_close_unit(unit); - return 1; - } - - if (ps2000_set_trigger(unit, PS2000_NONE, 0, 0, 0, 0) == 0) { - fprintf(stderr, "set_trigger failed!\n"); - ps2000_close_unit(unit); - return 1; - } - - if (ps2000_run_streaming_ns(unit, 1000, PS2000_NS, buffersize, false, 1, 50000) == 0) { - fprintf(stderr, "run_streaming_ns failed!\n"); - ps2000_close_unit(unit); - return 1; - } - - signal(SIGINT, &capture_stop); - - while (!stop) { - if (ps2000_get_streaming_last_values(unit, &get_overview_buffers) == 0) { - // fprintf(stderr, "callback won't be called!\n"); - } - /* - int16_t overrun = 0; - if (ps2000_overview_buffer_status(unit, &overrun) != 0) { - fprintf(stderr, "failed to check overrun!\n"); - } else if (overrun) { - fprintf(stderr, "overrun!\n"); - } - - // usleep(0); - */ - } - - ps2000_stop(unit); - ps2000_close_unit(unit); - - return 0; -} \ No newline at end of file diff --git a/src/recorder/CMakeLists.txt b/src/recorder/CMakeLists.txt new file mode 100644 index 0000000..4a921f7 --- /dev/null +++ b/src/recorder/CMakeLists.txt @@ -0,0 +1,7 @@ +file(GLOB_RECURSE SOURCES "./*.c") +add_executable(recorder ${SOURCES}) +target_compile_options(recorder PRIVATE -Wall -Wextra) +target_link_libraries(recorder ps2000) +set_target_properties(recorder PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" +) \ No newline at end of file diff --git a/src/recorder/main.c b/src/recorder/main.c new file mode 100644 index 0000000..0a72318 --- /dev/null +++ b/src/recorder/main.c @@ -0,0 +1,194 @@ +#include +#include +#include +#include +#include + +#include +#include + +const char* DEFAULT_TYPE = "float"; +const char* DEFAULT_RANGE = "10V"; +const uint8_t DEFAULT_CHANNEL = 0; +const uint32_t DEFAULT_BUFFERSIZE = 10000; +const uint32_t DEFAULT_MAX_BUFFERSIZE = DEFAULT_BUFFERSIZE * 5; +const uint32_t DEFAULT_SAMPLE_INTERVAL = 1000; +const char* DEFAULT_TIME_UNITS = "ns"; + +bool stop = false; +uint8_t* channel; +uint32_t* max_buffersize; + +void capture_stop(int signal) { + (void)signal; + stop = true; +} + +void get_overview_buffers_float(int16_t** overviewBuffers, int16_t overflow, uint32_t triggeredAt, int16_t triggered, int16_t auto_stop, uint32_t nValues) { + (void)overflow; + (void)triggeredAt; + (void)triggered; + (void)auto_stop; + + /* this buffer lives the whole lifetime of the application + and so doesn't need to be cleaned up, the os will do it for us */ + static float* float_buffer = NULL; + if (float_buffer == NULL) { + float_buffer = (float*)malloc(sizeof(float) * *max_buffersize); + + if (float_buffer == NULL) { + fprintf(stderr, "failed to allocate buffers\n"); + stop = true; + return; + } + } + + // int16 -> float + for (uint32_t i = 0; i < nValues; i++) { + float_buffer[i] = overviewBuffers[*channel][i]; + float_buffer[i] /= INT16_MAX; + } + + fwrite(float_buffer, sizeof(float), nValues, stdout); +} + +void get_overview_buffers_int16(int16_t** overviewBuffers, int16_t overflow, uint32_t triggeredAt, int16_t triggered, int16_t auto_stop, uint32_t nValues) { + (void)overflow; + (void)triggeredAt; + (void)triggered; + (void)auto_stop; + + fwrite(overviewBuffers[*channel], sizeof(int16_t), nValues, stdout); +} + +PS2000_RANGE parse_range(char* range) { + if (strcmp(range, "10mV") == 0) + return PS2000_10MV; + if (strcmp(range, "20mV") == 0) + return PS2000_20MV; + if (strcmp(range, "50mV") == 0) + return PS2000_50MV; + if (strcmp(range, "100mV") == 0) + return PS2000_100MV; + if (strcmp(range, "200mV") == 0) + return PS2000_200MV; + if (strcmp(range, "500mV") == 0) + return PS2000_500MV; + if (strcmp(range, "1V") == 0) + return PS2000_1V; + if (strcmp(range, "2V") == 0) + return PS2000_2V; + if (strcmp(range, "5V") == 0) + return PS2000_5V; + if (strcmp(range, "10V") == 0) + return PS2000_10V; + if (strcmp(range, "20V") == 0) + return PS2000_20V; + if (strcmp(range, "50V") == 0) + return PS2000_50V; + return PS2000_MAX_RANGES; +} + +PS2000_TIME_UNITS parse_units(char* unit) { + if (strcmp(unit, "fs")) + return PS2000_FS; + if (strcmp(unit, "ps")) + return PS2000_PS; + if (strcmp(unit, "ns")) + return PS2000_US; + if (strcmp(unit, "us")) + return PS2000_US; + if (strcmp(unit, "ms")) + return PS2000_MS; + if (strcmp(unit, "s")) + return PS2000_S; + return PS2000_MAX_TIME_UNITS; +} + +void cleanup(int16_t unit) { + ps2000_stop(unit); + ps2000_close_unit(unit); +} + +int main(int argc, char** argv) { + // parse arguments + if (argc > 0) + c_flags_set_application_name(argv[0]); + + char** type = c_flag_string("type", "t", "type for output", DEFAULT_TYPE); + char** range = c_flag_string("range", "r", "voltage range", DEFAULT_RANGE); + channel = c_flag_uint8("channel", "c", "channel", DEFAULT_CHANNEL); + uint32_t* buffersize = c_flag_uint32("buffersize", "b", "buffersize", DEFAULT_BUFFERSIZE); + max_buffersize = c_flag_uint32("max_buffersize", "mb", "max buffersize the driver stores", DEFAULT_MAX_BUFFERSIZE); + uint32_t* sample_interval = c_flag_uint32("sample_interval", "s", "sample interval", DEFAULT_SAMPLE_INTERVAL); + char** time_units = c_flag_string("time_units", "u", "time units", DEFAULT_TIME_UNITS); + + c_flags_parse(&argc, &argv, true); + + // validate arguments + GetOverviewBuffersMaxMin get_overview_buffers_func; + if (strcmp(*type, "float") == 0) { + get_overview_buffers_func = get_overview_buffers_float; + } else if (strcmp(*type, "int16")) { + get_overview_buffers_func = get_overview_buffers_int16; + } else { + fprintf(stderr, "unknown output type: %s\n", *type); + return -1; + } + + PS2000_RANGE selected_range = parse_range(*range); + if (selected_range == PS2000_MAX_RANGES) { + fprintf(stderr, "invalid voltage range: %s\n", *range); + return -1; + } + + PS2000_TIME_UNITS selected_units = parse_units(*time_units); + if (selected_units == PS2000_MAX_TIME_UNITS) { + fprintf(stderr, "invalid time unit: %s\n", *time_units); + return -1; + } + + if (*channel > 1) { + fprintf(stderr, "channel out of range: %u\n", *channel); + return -1; + } + + if (*max_buffersize <= *buffersize) { + fprintf(stderr, "max buffersize needs to be bigger than buffersize\n"); + return -1; + } + + // configure picoscope + int16_t unit = ps2000_open_unit(); + + if (ps2000_set_channel(unit, PS2000_CHANNEL_A + *channel, true, false, selected_range) == 0) { + fprintf(stderr, "set_channel failed!\n"); + cleanup(unit); + return -1; + } + + // disable interrupts + if (ps2000_set_trigger(unit, PS2000_NONE, 0, 0, 0, 0) == 0) { + fprintf(stderr, "set_trigger failed!\n"); + cleanup(unit); + return -1; + } + + // start data capture without aggregation + if (ps2000_run_streaming_ns(unit, *sample_interval, selected_units, *buffersize, false, 1, *max_buffersize) == 0) { + fprintf(stderr, "run_streaming_ns failed!\n"); + cleanup(unit); + return -1; + } + + // start reading data + signal(SIGINT, &capture_stop); + + while (!stop) { + ps2000_get_streaming_last_values(unit, get_overview_buffers_func); + } + + cleanup(unit); + + return 0; +} \ No newline at end of file