diff --git a/include/recorder/config.h b/include/recorder/config.h new file mode 100644 index 0000000..1e56478 --- /dev/null +++ b/include/recorder/config.h @@ -0,0 +1,24 @@ +#ifndef RECORDER_CONFIG_H +#define RECORDER_CONFIG_H + +#include +#include + +#include + +typedef struct { + uint32_t buffersize; + uint32_t max_buffersize; + uint32_t sample_interval; + PS2000_RANGE range; + PS2000_TIME_UNITS time_units; + bool iq_mode; + bool dc_mode; +} config; + +PS2000_RANGE parse_range(char* range); +PS2000_TIME_UNITS parse_units(char* unit); + +config* get_config(int argc, char** argv); + +#endif \ No newline at end of file diff --git a/include/recorder/config_defaults.h b/include/recorder/config_defaults.h new file mode 100644 index 0000000..40119f8 --- /dev/null +++ b/include/recorder/config_defaults.h @@ -0,0 +1,15 @@ +#ifndef RECORDER_CONFIG_DEFAULTS_H +#define RECORDER_CONFIG_DEFAULTS_H + +#include +#include + +const char* DEFAULT_RANGE = "10V"; +const bool DEFAULT_IQ_MODE = true; +const bool DEFAULT_DC_MODE = false; +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"; + +#endif \ No newline at end of file diff --git a/src/recorder/config.c b/src/recorder/config.c new file mode 100644 index 0000000..bc4b561 --- /dev/null +++ b/src/recorder/config.c @@ -0,0 +1,93 @@ +#include +#include + +#include + +#include +#include + +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") == 0) + return PS2000_FS; + if (strcmp(unit, "ps") == 0) + return PS2000_PS; + if (strcmp(unit, "ns") == 0) + return PS2000_US; + if (strcmp(unit, "us") == 0) + return PS2000_US; + if (strcmp(unit, "ms") == 0) + return PS2000_MS; + if (strcmp(unit, "s") == 0) + return PS2000_S; + return PS2000_MAX_TIME_UNITS; +} + +config* get_config(int argc, char** argv) { + if (argc > 0) + c_flags_set_application_name(argv[0]); + + char** range = c_flag_string("range", "r", "voltage range", DEFAULT_RANGE); + bool* dc_mode = c_flag_bool("dc", "dc", "dc mode", DEFAULT_DC_MODE); + bool* iq_mode = c_flag_bool("iq_mode", "iq", "IQ mode", DEFAULT_IQ_MODE); + uint32_t* buffersize = c_flag_uint32("buffersize", "b", "buffersize", DEFAULT_BUFFERSIZE); + uint32_t* 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); + + config* cfg = (config*)malloc(sizeof(config)); + cfg->dc_mode = *dc_mode; + cfg->iq_mode = *iq_mode; + cfg->buffersize = *buffersize; + cfg->max_buffersize = *max_buffersize; + cfg->sample_interval = *sample_interval; + + // validate arguments + cfg->range = parse_range(*range); + if (cfg->range == PS2000_MAX_RANGES) { + fprintf(stderr, "invalid voltage range: %s\n", *range); + return NULL; + } + + cfg->time_units = parse_units(*time_units); + if (cfg->time_units == PS2000_MAX_TIME_UNITS) { + fprintf(stderr, "invalid time unit: %s\n", *time_units); + return NULL; + } + + if (*max_buffersize <= *buffersize) { + fprintf(stderr, "max buffersize needs to be bigger than buffersize\n"); + return NULL; + } + + return cfg; +} \ No newline at end of file diff --git a/src/recorder/main.c b/src/recorder/main.c index f831fe0..8c7213f 100644 --- a/src/recorder/main.c +++ b/src/recorder/main.c @@ -2,23 +2,16 @@ #include #include #include +#include #include -#include #include -const char* DEFAULT_TYPE = "float"; -const char* DEFAULT_RANGE = "10V"; -const uint8_t DEFAULT_CHANNEL = 0; -const bool DEFAULT_DC_MODE = false; -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"; +#include bool stop = false; -uint8_t* channel; -uint32_t* max_buffersize; +config* cfg; +float* buffer; // ctrl+c -> stop void capture_stop(int signal) { @@ -26,150 +19,68 @@ void capture_stop(int 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 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; - /* 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; + if (cfg->iq_mode) { + for (uint32_t i = 0; i < nValues; i++) { + buffer[(i * 2) + 0] = overviewBuffers[0][i] / (float)INT16_MAX; + buffer[(i * 2) + 1] = overviewBuffers[2][i] / (float)INT16_MAX; } + + fwrite(buffer, sizeof(float), nValues * 2, stdout); + } else { + for (uint32_t i = 0; i < nValues; i++) { + buffer[i] = overviewBuffers[0][i] / (float)INT16_MAX; + } + + fwrite(buffer, sizeof(float), nValues, stdout); } - - // 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") == 0) - return PS2000_FS; - if (strcmp(unit, "ps") == 0) - return PS2000_PS; - if (strcmp(unit, "ns") == 0) - return PS2000_US; - if (strcmp(unit, "us") == 0) - return PS2000_US; - if (strcmp(unit, "ms") == 0) - return PS2000_MS; - if (strcmp(unit, "s") == 0) - return PS2000_S; - return PS2000_MAX_TIME_UNITS; } void cleanup(int16_t unit) { ps2000_stop(unit); ps2000_close_unit(unit); + + if (buffer != NULL) { + free(buffer); + } + + free(cfg); } 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); - bool* dc = c_flag_bool("dc", "dc", "dc mode", DEFAULT_DC_MODE); - 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_unit = parse_units(*time_units); - if (selected_unit == 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; - } + cfg = get_config(argc, argv); // configure picoscope int16_t unit = ps2000_open_unit(); + if (unit == -1) { + fprintf(stderr, "failed to open a unit!\n"); + return -1; + } else if (unit == 0) { + fprintf(stderr, "no units to open!\n"); + return -1; + } - if (ps2000_set_channel(unit, PS2000_CHANNEL_A + *channel, true, *dc, selected_range) == 0) { - fprintf(stderr, "set_channel failed!\n"); + // configure channels + if (ps2000_set_channel(unit, PS2000_CHANNEL_A, true, cfg->dc_mode, cfg->range) == 0) { + fprintf(stderr, "set_channel A failed!\n"); cleanup(unit); return -1; } + if (cfg->iq_mode) { + if (ps2000_set_channel(unit, PS2000_CHANNEL_B, true, cfg->dc_mode, cfg->range) == 0) { + fprintf(stderr, "set_channel B 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"); @@ -177,8 +88,11 @@ int main(int argc, char** argv) { return -1; } + // allocate buffer + buffer = (float*)malloc(sizeof(float) * (cfg->max_buffersize) * (cfg->iq_mode ? 2 : 1)); + // start data capture without aggregation - if (ps2000_run_streaming_ns(unit, *sample_interval, selected_unit, *buffersize, false, 1, *max_buffersize) == 0) { + if (ps2000_run_streaming_ns(unit, cfg->sample_interval, cfg->time_units, cfg->buffersize, false, 1, cfg->max_buffersize) == 0) { fprintf(stderr, "run_streaming_ns failed!\n"); cleanup(unit); return -1; @@ -188,7 +102,7 @@ int main(int argc, char** argv) { signal(SIGINT, &capture_stop); while (!stop) { - ps2000_get_streaming_last_values(unit, get_overview_buffers_func); + ps2000_get_streaming_last_values(unit, &get_overview_buffers); } cleanup(unit);