From 26fd31d79267cf055f3c9e0a0085d6d7acb54db5 Mon Sep 17 00:00:00 2001 From: Alexandra Date: Thu, 16 Jan 2025 14:21:13 +0000 Subject: [PATCH 1/5] feat: smu node-type Signed-off-by: Manuel Pitz Signed-off-by: Alexandra --- CMakeLists.txt | 2 + etc/examples/nodes/smu.conf | 69 ++++++++ include/villas/nodes/smu.hpp | 236 ++++++++++++++++++++++++++ lib/nodes/CMakeLists.txt | 4 + lib/nodes/smu.cpp | 308 ++++++++++++++++++++++++++++++++++ tests/integration/node-smu.sh | 52 ++++++ 6 files changed, 671 insertions(+) create mode 100644 etc/examples/nodes/smu.conf create mode 100644 include/villas/nodes/smu.hpp create mode 100644 lib/nodes/smu.cpp create mode 100644 tests/integration/node-smu.sh diff --git a/CMakeLists.txt b/CMakeLists.txt index 9bb409fe4..b4da26772 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -195,6 +195,7 @@ cmake_dependent_option(WITH_NODE_REDIS "Build with redis node-type" cmake_dependent_option(WITH_NODE_RTP "Build with rtp node-type" "${WITH_DEFAULTS}" "re_FOUND" OFF) cmake_dependent_option(WITH_NODE_SHMEM "Build with shmem node-type" "${WITH_DEFAULTS}" "HAS_SEMAPHORE; HAS_MMAN" OFF) cmake_dependent_option(WITH_NODE_SIGNAL "Build with signal node-type" "${WITH_DEFAULTS}" "" OFF) +cmake_dependent_option(WITH_NODE_SMU "Build with smu node-type" "${WITH_DEFAULTS}" "" OFF) cmake_dependent_option(WITH_NODE_SOCKET "Build with socket node-type" "${WITH_DEFAULTS}" "LIBNL3_ROUTE_FOUND" OFF) cmake_dependent_option(WITH_NODE_STATS "Build with stats node-type" "${WITH_DEFAULTS}" "" OFF) cmake_dependent_option(WITH_NODE_TEMPER "Build with temper node-type" "${WITH_DEFAULTS}" "LIBUSB_FOUND" OFF) @@ -300,6 +301,7 @@ add_feature_info(NODE_REDIS WITH_NODE_REDIS "Build with add_feature_info(NODE_RTP WITH_NODE_RTP "Build with rtp node-type") add_feature_info(NODE_SHMEM WITH_NODE_SHMEM "Build with shmem node-type") add_feature_info(NODE_SIGNAL WITH_NODE_SIGNAL "Build with signal node-type") +add_feature_info(NODE_SMU WITH_NODE_SMU "Build with smu node-type") add_feature_info(NODE_SOCKET WITH_NODE_SOCKET "Build with socket node-type") add_feature_info(NODE_STATS WITH_NODE_STATS "Build with stats node-type") add_feature_info(NODE_TEMPER WITH_NODE_TEMPER "Build with temper node-type") diff --git a/etc/examples/nodes/smu.conf b/etc/examples/nodes/smu.conf new file mode 100644 index 000000000..e0a406ad7 --- /dev/null +++ b/etc/examples/nodes/smu.conf @@ -0,0 +1,69 @@ +# SPDX-FileCopyrightText: 2014-2024 Institute for Automation of Complex Power Systems, RWTH Aachen University +# SPDX-License-Identifier: Apache-2.0 + +http = { + enabled = false +} +logging = { + # level = "warn" +} +nodes = { + smu = { + type = "smu" + signals = ( + { name = "ch1" type = "float"}, + { name = "ch2" type = "float"}, + { name = "signal3" type = "float"}, + { name = "signal4" type = "float"}, + { name = "signal5" type = "float"}, + { name = "signal6" type = "float"}, + { name = "signal7" type = "float"} + ) + vectorize = 1000 + sample_rate = "FS_10kSPS" + dumper = ( + { name = "ch1" path = "/tmp/ch1"}, + { name = "ch2" path = "/tmp/ch2"} + ) + } + + file = { + type = "file" + format = "csv" + uri = "./data.csv" + } +} + +paths = ( + { + enabled = true + #queuelen = 20000 + in = "smu" + out = "file" + hooks = ( + { + type = "scale" + scale = 0.000305185 #10/32767 + offset = 0 #1280 + signal = "ch1" + }, + { + type = "ip-dft-pmu" + enabled = true + estimation_range = 10. + nominal_freq = 50. + number_plc = 10. + sample_rate = 10000 + dft_rate = 10 + window_type = "hann" + signals = ["ch1"] + angle_unit = "degree" + timestamp_align = "center" + add_channel_name = true + phase_offset = 0 + frequency_offset = 0.0015 + amplitude_offset = 0 + } + ) + } +) diff --git a/include/villas/nodes/smu.hpp b/include/villas/nodes/smu.hpp new file mode 100644 index 000000000..a76acac16 --- /dev/null +++ b/include/villas/nodes/smu.hpp @@ -0,0 +1,236 @@ + /* Node-type for SMU data acquisition. + * + * Author: Manuel Pitz + * SPDX-FileCopyrightText: 2014-2023 Institute for Automation of Complex Power Systems, RWTH Aachen University + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#include +#include + + +extern "C" { + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +} + + +#define SMU_NCH 8 + +namespace villas { +namespace node { + +//static const smu_dsp_t dsp_cfg_default = {FR_1PPS, {"1","1","1","1","1","1","1","1"}, {"V1", "V2", "V3", "V4", "I1", "I2", "I3", "I4"}}; +//const smu_dsp_t dsp_cfg_default = {FR_10PPS, {"1","1","1","1","1","1","1","1"}, {"V1", "V2", "V3", "V4", "I1", "I2", "I3", "I4"}, "dsp_raw"}; +//const smu_net_t net_cfg_default = {"id", "", 7080, IPv4, TCP, "JSON", "", 7090, IPv4, TCP, "net_raw", ""}; + +/// ---------- SMU: DAQ settings section ---------- + +/** + * @brief DAQ sampling rate (kHz / kSPS) + * + */ +typedef enum : unsigned char +{ + FS_1kSPS = 1, + FS_2kSPS = 2, + FS_5kSPS = 5, + FS_10kSPS = 10, + FS_20kSPS = 20, + FS_25kSPS = 25, + FS_50kSPS = 50, + FS_100kSPS = 100, + FS_200kSPS = 200 +} daq_rate_t; + +/** + * @brief DAQ buffer frame rate (Hz / FPS) + * + */ +typedef enum : unsigned char +{ + FB_10FPS = 10, + FB_20FPS = 20, + FB_50FPS = 50, + FB_100FPS = 100, + FB_200FPS = 200 +} daq_buff_t; + +/** + * @brief DAQ acquisition mode + * + */ +typedef enum : unsigned char +{ + MODE_ONESHOT, /*!< DAQ runs for 1 second */ + MODE_FREERUN, /*!< DAQ runs continuously */ + MODE_VIRTUAL, /*!< DAQ runs virtually */ + MODE_MAX +} daq_mode_t; + +/** + * @brief DAQ synchronization mode + * + */ +typedef enum : unsigned char +{ + SYNC_NONE, /*!< Time base synchronization disabled */ + SYNC_PPS, /*!< Time base synchronization from GPS via pulse-per-second */ + SYNC_NTP, /*!< Time base synchronization from Server via network-time-protocol */ + SYNC_MAX +} daq_sync_t; + +/** + * @brief DAQ parameters + * + */ +typedef struct +{ + daq_rate_t rate; /*!< DAQ sampling rate */ + daq_buff_t buff; /*!< DAQ buffer frame rate */ + daq_mode_t mode; /*!< DAQ acquisition mode */ + daq_sync_t sync; /*!< DAQ synchronization mode */ +} __attribute__((__packed__)) smu_daq_t; + +/// ---------- SMU: DSP settings section ---------- + +/** + * @brief DSP reporting rate (Hz / PPS) + * + */ +typedef enum : unsigned short int +{ + FR_EVENT = 0, + FR_1PPS = 1, + FR_2PPS = 2, + FR_5PPS = 5, + FR_10PPS = 10, + FR_20PPS = 20, + FR_25PPS = 25, + FR_50PPS = 50, + FR_100PPS = 100 +} dsp_rate_t; + + +/** + * @brief SMU multi-channel sample code + * + */ +typedef struct { + int16_t ch[SMU_NCH]; +} __attribute__((__packed__)) smu_mcsc_t; + +/** + * @brief SMU multi-channel sample real + * + */ +typedef struct { + float ch[SMU_NCH]; +} __attribute__((__packed__)) smu_mcsr_t; + +/** + * @brief SMU multi-channel conversion coefficients + * + */ +typedef struct { + float k[SMU_NCH]; +} __attribute__((__packed__)) smu_mcsk_t; + +typedef struct { + int64_t tv_sec; + long tv_nsec; +} __attribute__((__packed__)) timespec64_t; +/** + * @brief IOCTL definitions + * + * Here are defined the different IOCTL commands used + * to communicate from the userspace to the kernel module. + */ +#define SMU_DEV "/dev/smu" +#define SMU_IOC_MAGIC 'k' +#define SMU_IOC_REG_TASK _IO (SMU_IOC_MAGIC, 0) +#define SMU_IOC_RESET _IO (SMU_IOC_MAGIC, 1) +#define SMU_IOC_START _IO (SMU_IOC_MAGIC, 2) +#define SMU_IOC_STOP _IO (SMU_IOC_MAGIC, 3) +#define SMU_IOC_GET_TIME _IOR(SMU_IOC_MAGIC, 4, timespec64_t*) +#define SMU_IOC_SET_CONF _IOW(SMU_IOC_MAGIC, 5, smu_conf_t*) +#define SMU_IOC_GET_CONF _IOR(SMU_IOC_MAGIC, 6, smu_conf_t*) + + +/** + * @brief Signal definitions + * + * Here are defined the different values used to send + * signals to the userspace + */ +#define SMU_SIG_SYNC 41 +#define SMU_SIG_DATA 42 + +#define PAGE_NUM 800 +#define PAGE_SIZE 4096 +#define MMAP_SIZE (PAGE_SIZE*PAGE_NUM) + +class SMUNode : public Node { + +private: + daq_mode_t mode; + daq_rate_t sample_rate; + daq_buff_t fps; + daq_sync_t sync; + smu_daq_t daq_cfg; + Dumper dumpers[SMU_NCH]; + static inline int fd; + uint8_t* shared_mem; + uint32_t shared_mem_pos; + uint32_t shared_mem_inc; + uint32_t shared_mem_dim; + struct sigaction act; + + + size_t buffer_size; + static inline std::atomic mem_pos = 0; + static inline pthread_mutex_t mutex; + static inline pthread_cond_t cv; + static inline timespec64_t sync_signal_mem_pos = {0}; + static inline timespec sample_time ={0}; + static inline int smp_cnt = 0; + +protected: + virtual + int _read(struct Sample * smps[], unsigned cnt); + +public: + SMUNode(const uuid_t &id = {}, const std::string &name = ""); + static void data_available_signal(int, siginfo_t *info, void*); + static void sync_signal(int, siginfo_t *info, void*); + + virtual + int parse(json_t *json) override; + + virtual + int prepare(); + + virtual + int start(); + + virtual + int stop(); +}; + +} /* namespace node */ +} /* namespace villas */ diff --git a/lib/nodes/CMakeLists.txt b/lib/nodes/CMakeLists.txt index 1a9185257..eaaefe034 100644 --- a/lib/nodes/CMakeLists.txt +++ b/lib/nodes/CMakeLists.txt @@ -36,6 +36,10 @@ if(WITH_NODE_TEST_RTT) list(APPEND NODE_SRC test_rtt.cpp) endif() +if(WITH_NODE_SMU) + list(APPEND NODE_SRC smu.cpp) +endif() + if(WITH_NODE_SOCKET) list(APPEND NODE_SRC socket.cpp) endif() diff --git a/lib/nodes/smu.cpp b/lib/nodes/smu.cpp new file mode 100644 index 000000000..03e1d9e15 --- /dev/null +++ b/lib/nodes/smu.cpp @@ -0,0 +1,308 @@ + /* Node-type for SMU data acquisition. + * + * Author: Manuel Pitz + * SPDX-FileCopyrightText: 2014-2023 Institute for Automation of Complex Power Systems, RWTH Aachen University + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + + +using namespace villas; +using namespace villas::node; +using namespace villas::utils; + +SMUNode::SMUNode(const uuid_t &id, const std::string &name) : + Node(id, name), + mode(MODE_FREERUN), + sample_rate(FS_10kSPS), + fps(FB_10FPS), + sync(SYNC_PPS), + daq_cfg({sample_rate, fps, mode, sync}), + shared_mem(nullptr), // initalization + shared_mem_pos(0), // initalization + shared_mem_inc(0), // initalization + shared_mem_dim(0), // initalization + buffer_size(0) +{ + return; +} + +int SMUNode::prepare() +{ + assert(state == State::CHECKED); + return Node::prepare(); +} + +int SMUNode::parse(json_t *json) +{ + int ret = Node::parse(json); + if (ret) + return ret; + + json_error_t err; + + + json_t *jsonDumpers = nullptr; + + char *modeIn = nullptr; + char *syncIn = nullptr; + char *fpsIn = nullptr; + char *sample_rateIn = nullptr; + json_t *in_json = nullptr; + + + ret = json_unpack_ex(json, &err, 0, "{ s?: s, s?: s, s?: s, s?: s, s?: o, s?: o }", + "mode", &modeIn, + "sync", &syncIn, + "fps", &fpsIn, + "sample_rate", &sample_rateIn, + "dumper", &jsonDumpers, + "in", &in_json + ); + if (ret) + throw ConfigError(json, err, "node-config-node-smu"); + + if (jsonDumpers) { + auto signals = getInputSignals(); + + size_t i; + json_t *jsonDumper; + ret = json_unpack_ex(jsonDumpers, &err, 0, "{ o }", + &jsonDumper + ); + json_array_foreach(jsonDumpers, i, jsonDumper) { + char *nameIn = nullptr; + char *pathIn = nullptr; + + ret = json_unpack_ex(jsonDumper, &err, 0, "{ s: s, s: s }", + "name", &nameIn, + "path", &pathIn + ); + if (ret) + throw ConfigError(json, err, "node-config-node-smu", "Failed to parse dumper configuration"); + + int idx = signals->getIndexByName(nameIn); + if (idx == -1) + throw ConfigError(json, err, "node-config-node-smu", "Could not find signal {} for dumper", nameIn); + + dumpers[idx].setPath(pathIn); + dumpers[idx].openSocket(); + dumpers[idx].setActive(); + + } + + } + + if(!modeIn || strcmp(modeIn, "MODE_FREERUN")==0) + mode = MODE_FREERUN; + else if (strcmp(modeIn, "MODE_ONESHOT")==0) + mode = MODE_ONESHOT; + else if (strcmp(modeIn, "MODE_VIRTUAL")==0) + mode = MODE_VIRTUAL; + else if (strcmp(modeIn, "MODE_MAX")==0) + mode = MODE_MAX; + + if(!syncIn || strcmp(syncIn, "SYNC_PPS")==0) + sync = SYNC_PPS; + else if (strcmp(syncIn, "SYNC_NONE")==0) + sync = SYNC_NONE; + else if (strcmp(syncIn, "SYNC_NTP")==0) + sync = SYNC_NTP; + else if (strcmp(syncIn, "SYNC_MAX")==0) + sync = SYNC_MAX; + + if(!fpsIn || strcmp(fpsIn, "FB_10FPS")==0) + fps = FB_10FPS; + else if (strcmp(fpsIn, "FB_20FPS")==0) + fps = FB_20FPS; + else if (strcmp(fpsIn, "FB_50FPS")==0) + fps = FB_50FPS; + else if (strcmp(fpsIn, "FB_100FPS")==0) + fps = FB_100FPS; + else if (strcmp(fpsIn, "FB_200FPS")==0) + fps = FB_200FPS; + + if (!sample_rateIn || strcmp(sample_rateIn, "FS_10kSPS")==0) + sample_rate = FS_10kSPS; + else if (strcmp(sample_rateIn, "FS_1kSPS")==0) + sample_rate = FS_1kSPS; + else if (strcmp(sample_rateIn, "FS_2kSPS")==0) + sample_rate = FS_2kSPS; + else if (strcmp(sample_rateIn, "FS_5kSPS")==0) + sample_rate = FS_5kSPS; + else if (strcmp(sample_rateIn, "FS_20kSPS")==0) + sample_rate = FS_20kSPS; + else if (strcmp(sample_rateIn, "FS_25kSPS")==0) + sample_rate = FS_25kSPS; + else if (strcmp(sample_rateIn, "FS_50kSPS")==0) + sample_rate = FS_50kSPS; + else if (strcmp(sample_rateIn, "FS_100kSPS")==0) + sample_rate = FS_100kSPS; + else if (strcmp(sample_rateIn, "FS_200kSPS")==0) { + sample_rate = FS_200kSPS; + } + + + + if (json_is_object(in_json) && json_object_get(in_json, "vectorize")) { + throw ConfigError(json, "node-config-node-smu", "Vectorize cannot be overwritten for this node type!"); + } + in.vectorize = sample_rate * 1000 / fps; + + return 0; +} + +int SMUNode::start() +{ + assert(state == State::PREPARED || + state == State::PAUSED); + + int ret = Node::start(); + + + daq_cfg.rate = sample_rate; + daq_cfg.buff = fps; + daq_cfg.mode = mode; + daq_cfg.sync = sync; + + + fd = ::open(SMU_DEV, O_RDWR); + if (fd < 0) + logger->warn("Fail to open the device driver"); + + // Associate kernel-to-user Task ID + if (ioctl(fd, SMU_IOC_REG_TASK, 0)){ + logger->warn("Fail to register the driver"); + ::close(fd); + // return; + } + + // Map kernel-to-user shared memory + void *sh_mem = mmap(nullptr, MMAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + shared_mem = (uint8_t*)sh_mem; + if (shared_mem == MAP_FAILED) + logger->warn("Fail to map driver memory"); + + // Install PPS signal handler + sigemptyset(&act.sa_mask); + act.sa_flags = (SA_SIGINFO | SA_RESTART); + act.sa_sigaction = sync_signal; + if (sigaction(SMU_SIG_SYNC, &act, nullptr)) + logger->warn("Fail to install PPS handler"); + + // Install ADC signal handler + sigemptyset(&act.sa_mask); + act.sa_flags = (SA_SIGINFO | SA_RESTART); + act.sa_sigaction = data_available_signal; + if (sigaction(SMU_SIG_DATA, &act, nullptr)) + logger->warn("Fail to install ADC handler"); + + // Update DAQ memory configuration + shared_mem_pos = 0; + shared_mem_inc = sizeof(smu_mcsc_t); + shared_mem_dim = daq_cfg.rate; + + // Stop DAQ driver + if (ioctl(fd, SMU_IOC_STOP, 0)) + logger->warn("Fail to stop the driver"); + + // Configure DAQ driver + if (::write(fd, &daq_cfg, sizeof(daq_cfg.rate))) + logger->warn("Fail to configure the driver"); + + // Start DAQ driver + if (ioctl(fd, SMU_IOC_START, 0)) { + logger->warn("Fail to start the driver"); + } + + if (!ret) + state = State::STARTED; + + return ret; +} + +int SMUNode::stop() +{ + // Stop DAQ driver + if(!ioctl(fd, SMU_IOC_STOP, 0)) { + // Unmap kernel-to-user shared memory + munmap(shared_mem, MMAP_SIZE); + while(close(fd) != 0){} + } + + return 1; +} + +void SMUNode::sync_signal(int, siginfo_t *info, void*) +{ + + + ioctl(fd, SMU_IOC_GET_TIME,&sync_signal_mem_pos); + sample_time.tv_nsec = sync_signal_mem_pos.tv_nsec; //macht nix + sample_time.tv_sec = sync_signal_mem_pos.tv_sec; + + if (sample_time.tv_nsec > 500000000) + sample_time.tv_sec += 1; + //std::cout << "\n\npps event\n\n"; +} + +void SMUNode::data_available_signal(int, siginfo_t *info, void*) +{ + + mem_pos = (info->si_value.sival_int); + /* Signal uldaq_read() about new data */ + pthread_cond_signal(&cv); +} + + +int SMUNode::_read(struct Sample *smps[], unsigned cnt) +{ + struct timespec ts; + ts.tv_sec = sample_time.tv_sec; + pthread_mutex_lock(&mutex); + + pthread_cond_wait(&cv, &mutex); + size_t mem_pos_local = mem_pos; + + smu_mcsc_t* p = (smu_mcsc_t*)shared_mem; + + + for (unsigned j = 0; j < cnt; j++) { + struct Sample *t = smps[j]; + ts.tv_nsec = mem_pos_local * 1e6 / (sample_rate);//current_sample*1e9* 1/(sample_rate * 1000) + + for (unsigned i = 0; i < 8; i++) { //auslagern, Steffen fragen + int16_t data = p[mem_pos_local].ch[i]; + t->data[i].f = ((double)data); + if (dumpers[i].isActive()) + dumpers[i].writeDataBinary(1, &(t->data[i].f)); + } + + mem_pos_local++; + + t->flags = (int) SampleFlags::HAS_TS_ORIGIN | (int) SampleFlags::HAS_DATA | (int) SampleFlags::HAS_SEQUENCE; + t->ts.origin = ts; + t->sequence = sequence++; + t->length = 8; + t->signals = in.signals; + + + } + + pthread_mutex_unlock(&mutex); + + return cnt; +} + +static char n[] = "smu"; +static char d[] = "SMU data acquisition"; +static NodePlugin p; diff --git a/tests/integration/node-smu.sh b/tests/integration/node-smu.sh new file mode 100644 index 000000000..e020295bb --- /dev/null +++ b/tests/integration/node-smu.sh @@ -0,0 +1,52 @@ +#!/usr/bin/env bash +# +# Integration loopback test using villas node for smu node-type. +# +# Author: Alexandra Bach +# SPDX-FileCopyrightText: 2014-2023 Institute for Automation of Complex Power Systems, RWTH Aachen University +# SPDX-License-Identifier: Apache-2.0 + +echo "Test not yet supported" +exit 99 + +set -e + +DIR=$(mktemp -d) +pushd ${DIR} + +function finish { + popd + rm -rf ${DIR} +} +trap finish EXIT + +mkdir ./logs + +cat > config.json < Date: Thu, 24 Apr 2025 08:51:11 +0000 Subject: [PATCH 2/5] fix config and apply clang Signed-off-by: Alexandra --- include/villas/nodes/smu.hpp | 292 ++++++++------------ lib/nodes/smu.cpp | 490 ++++++++++++++++------------------ tests/integration/node-smu.sh | 38 ++- 3 files changed, 358 insertions(+), 462 deletions(-) diff --git a/include/villas/nodes/smu.hpp b/include/villas/nodes/smu.hpp index a76acac16..8870f5cda 100644 --- a/include/villas/nodes/smu.hpp +++ b/include/villas/nodes/smu.hpp @@ -1,4 +1,4 @@ - /* Node-type for SMU data acquisition. +/* Node-type for SMU data acquisition. * * Author: Manuel Pitz * SPDX-FileCopyrightText: 2014-2023 Institute for Automation of Complex Power Systems, RWTH Aachen University @@ -8,228 +8,158 @@ #pragma once #include +#include #include #include -#include - extern "C" { +#include +#include +#include +#include #include #include -#include -#include -#include #include -#include -#include +#include +#include +#include #include -#include -#include #include } - #define SMU_NCH 8 namespace villas { namespace node { -//static const smu_dsp_t dsp_cfg_default = {FR_1PPS, {"1","1","1","1","1","1","1","1"}, {"V1", "V2", "V3", "V4", "I1", "I2", "I3", "I4"}}; -//const smu_dsp_t dsp_cfg_default = {FR_10PPS, {"1","1","1","1","1","1","1","1"}, {"V1", "V2", "V3", "V4", "I1", "I2", "I3", "I4"}, "dsp_raw"}; -//const smu_net_t net_cfg_default = {"id", "", 7080, IPv4, TCP, "JSON", "", 7090, IPv4, TCP, "net_raw", ""}; - -/// ---------- SMU: DAQ settings section ---------- - -/** - * @brief DAQ sampling rate (kHz / kSPS) - * - */ -typedef enum : unsigned char -{ - FS_1kSPS = 1, - FS_2kSPS = 2, - FS_5kSPS = 5, - FS_10kSPS = 10, - FS_20kSPS = 20, - FS_25kSPS = 25, - FS_50kSPS = 50, - FS_100kSPS = 100, - FS_200kSPS = 200 -} daq_rate_t; - -/** - * @brief DAQ buffer frame rate (Hz / FPS) - * - */ -typedef enum : unsigned char -{ - FB_10FPS = 10, - FB_20FPS = 20, - FB_50FPS = 50, - FB_100FPS = 100, - FB_200FPS = 200 -} daq_buff_t; - -/** - * @brief DAQ acquisition mode - * - */ -typedef enum : unsigned char +typedef enum : unsigned char // DAQ sampling rate (kHz / kSPS) +{ FS_1kSPS = 1, + FS_2kSPS = 2, + FS_5kSPS = 5, + FS_10kSPS = 10, + FS_20kSPS = 20, + FS_25kSPS = 25, + FS_50kSPS = 50, + FS_100kSPS = 100, + FS_200kSPS = 200 } daq_rate_t; + +typedef enum : unsigned char // DAQ buffer frame rate (Hz / FPS) +{ FB_10FPS = 10, + FB_20FPS = 20, + FB_50FPS = 50, + FB_100FPS = 100, + FB_200FPS = 200 } daq_buff_t; + +typedef enum : unsigned char // DAQ acquisition mode +{ MODE_ONESHOT, /*!< DAQ runs for 1 second */ + MODE_FREERUN, /*!< DAQ runs continuously */ + MODE_VIRTUAL, /*!< DAQ runs virtually */ + MODE_MAX } daq_mode_t; + +typedef enum : unsigned char // DAQ synchronization mode +{ SYNC_NONE, /*!< Time base synchronization disabled */ + SYNC_PPS, /*!< Time base synchronization from GPS via pulse-per-second */ + SYNC_NTP, /*!< Time base synchronization from Server via network-time-protocol */ + SYNC_MAX } daq_sync_t; + +typedef struct // DAQ parameters { - MODE_ONESHOT, /*!< DAQ runs for 1 second */ - MODE_FREERUN, /*!< DAQ runs continuously */ - MODE_VIRTUAL, /*!< DAQ runs virtually */ - MODE_MAX -} daq_mode_t; - -/** - * @brief DAQ synchronization mode - * - */ -typedef enum : unsigned char -{ - SYNC_NONE, /*!< Time base synchronization disabled */ - SYNC_PPS, /*!< Time base synchronization from GPS via pulse-per-second */ - SYNC_NTP, /*!< Time base synchronization from Server via network-time-protocol */ - SYNC_MAX -} daq_sync_t; - -/** - * @brief DAQ parameters - * - */ -typedef struct -{ - daq_rate_t rate; /*!< DAQ sampling rate */ - daq_buff_t buff; /*!< DAQ buffer frame rate */ - daq_mode_t mode; /*!< DAQ acquisition mode */ - daq_sync_t sync; /*!< DAQ synchronization mode */ + daq_rate_t rate; /*!< DAQ sampling rate */ + daq_buff_t buff; /*!< DAQ buffer frame rate */ + daq_mode_t mode; /*!< DAQ acquisition mode */ + daq_sync_t sync; /*!< DAQ synchronization mode */ } __attribute__((__packed__)) smu_daq_t; -/// ---------- SMU: DSP settings section ---------- - -/** - * @brief DSP reporting rate (Hz / PPS) - * - */ -typedef enum : unsigned short int +typedef enum : unsigned short int // DSP reporting rate (Hz / PPS) +{ FR_EVENT = 0, + FR_1PPS = 1, + FR_2PPS = 2, + FR_5PPS = 5, + FR_10PPS = 10, + FR_20PPS = 20, + FR_25PPS = 25, + FR_50PPS = 50, + FR_100PPS = 100 } dsp_rate_t; + +typedef struct // SMU multi-channel sample code { - FR_EVENT = 0, - FR_1PPS = 1, - FR_2PPS = 2, - FR_5PPS = 5, - FR_10PPS = 10, - FR_20PPS = 20, - FR_25PPS = 25, - FR_50PPS = 50, - FR_100PPS = 100 -} dsp_rate_t; - - -/** - * @brief SMU multi-channel sample code - * - */ -typedef struct { - int16_t ch[SMU_NCH]; + int16_t ch[SMU_NCH]; } __attribute__((__packed__)) smu_mcsc_t; -/** - * @brief SMU multi-channel sample real - * - */ -typedef struct { - float ch[SMU_NCH]; +typedef struct // SMU multi-channel sample real +{ + float ch[SMU_NCH]; } __attribute__((__packed__)) smu_mcsr_t; -/** - * @brief SMU multi-channel conversion coefficients - * - */ -typedef struct { - float k[SMU_NCH]; +typedef struct // SMU multi-channel conversion coefficients +{ + float k[SMU_NCH]; } __attribute__((__packed__)) smu_mcsk_t; typedef struct { - int64_t tv_sec; - long tv_nsec; + int64_t tv_sec; + long tv_nsec; } __attribute__((__packed__)) timespec64_t; -/** - * @brief IOCTL definitions - * - * Here are defined the different IOCTL commands used - * to communicate from the userspace to the kernel module. - */ -#define SMU_DEV "/dev/smu" -#define SMU_IOC_MAGIC 'k' -#define SMU_IOC_REG_TASK _IO (SMU_IOC_MAGIC, 0) -#define SMU_IOC_RESET _IO (SMU_IOC_MAGIC, 1) -#define SMU_IOC_START _IO (SMU_IOC_MAGIC, 2) -#define SMU_IOC_STOP _IO (SMU_IOC_MAGIC, 3) -#define SMU_IOC_GET_TIME _IOR(SMU_IOC_MAGIC, 4, timespec64_t*) -#define SMU_IOC_SET_CONF _IOW(SMU_IOC_MAGIC, 5, smu_conf_t*) -#define SMU_IOC_GET_CONF _IOR(SMU_IOC_MAGIC, 6, smu_conf_t*) - - -/** - * @brief Signal definitions - * - * Here are defined the different values used to send - * signals to the userspace - */ -#define SMU_SIG_SYNC 41 -#define SMU_SIG_DATA 42 -#define PAGE_NUM 800 -#define PAGE_SIZE 4096 -#define MMAP_SIZE (PAGE_SIZE*PAGE_NUM) +// IOCTL commands to communicate from the userspace to the kernel module +#define SMU_DEV "/dev/smu" +#define SMU_IOC_MAGIC 'k' +#define SMU_IOC_REG_TASK _IO(SMU_IOC_MAGIC, 0) +#define SMU_IOC_RESET _IO(SMU_IOC_MAGIC, 1) +#define SMU_IOC_START _IO(SMU_IOC_MAGIC, 2) +#define SMU_IOC_STOP _IO(SMU_IOC_MAGIC, 3) +#define SMU_IOC_GET_TIME _IOR(SMU_IOC_MAGIC, 4, timespec64_t *) +#define SMU_IOC_SET_CONF _IOW(SMU_IOC_MAGIC, 5, smu_conf_t *) +#define SMU_IOC_GET_CONF _IOR(SMU_IOC_MAGIC, 6, smu_conf_t *) + +// Signal definitions +#define SMU_SIG_SYNC 41 +#define SMU_SIG_DATA 42 + +#define PAGE_NUM 800 +#define PAGE_SIZE 4096 +#define MMAP_SIZE (PAGE_SIZE * PAGE_NUM) class SMUNode : public Node { private: - daq_mode_t mode; - daq_rate_t sample_rate; - daq_buff_t fps; - daq_sync_t sync; - smu_daq_t daq_cfg; - Dumper dumpers[SMU_NCH]; - static inline int fd; - uint8_t* shared_mem; - uint32_t shared_mem_pos; - uint32_t shared_mem_inc; - uint32_t shared_mem_dim; - struct sigaction act; - - - size_t buffer_size; - static inline std::atomic mem_pos = 0; - static inline pthread_mutex_t mutex; - static inline pthread_cond_t cv; - static inline timespec64_t sync_signal_mem_pos = {0}; - static inline timespec sample_time ={0}; - static inline int smp_cnt = 0; + daq_mode_t mode; + daq_rate_t sample_rate; + daq_buff_t fps; + daq_sync_t sync; + smu_daq_t daq_cfg; + Dumper dumpers[SMU_NCH]; + static inline int fd; + uint8_t *shared_mem; + uint32_t shared_mem_pos; + uint32_t shared_mem_inc; + uint32_t shared_mem_dim; + struct sigaction act; + + size_t buffer_size; + static inline std::atomic mem_pos = 0; + static inline pthread_mutex_t mutex; + static inline pthread_cond_t cv; + static inline timespec64_t sync_signal_mem_pos = {0}; + static inline timespec sample_time = {0}; + static inline int smp_cnt = 0; protected: - virtual - int _read(struct Sample * smps[], unsigned cnt); + virtual int _read(struct Sample *smps[], unsigned cnt); public: - SMUNode(const uuid_t &id = {}, const std::string &name = ""); - static void data_available_signal(int, siginfo_t *info, void*); - static void sync_signal(int, siginfo_t *info, void*); + SMUNode(const uuid_t &id = {}, const std::string &name = ""); + static void data_available_signal(int, siginfo_t *info, void *); + static void sync_signal(int, siginfo_t *info, void *); - virtual - int parse(json_t *json) override; + virtual int parse(json_t *json) override; - virtual - int prepare(); + virtual int prepare(); - virtual - int start(); + virtual int start(); - virtual - int stop(); + virtual int stop(); }; } /* namespace node */ diff --git a/lib/nodes/smu.cpp b/lib/nodes/smu.cpp index 03e1d9e15..65e8a3e7f 100644 --- a/lib/nodes/smu.cpp +++ b/lib/nodes/smu.cpp @@ -1,308 +1,280 @@ - /* Node-type for SMU data acquisition. +/* Node-type for SMU data acquisition. * * Author: Manuel Pitz * SPDX-FileCopyrightText: 2014-2023 Institute for Automation of Complex Power Systems, RWTH Aachen University * SPDX-License-Identifier: Apache-2.0 */ -#include +#include +#include #include #include -#include -#include +#include #include #include #include - using namespace villas; using namespace villas::node; using namespace villas::utils; -SMUNode::SMUNode(const uuid_t &id, const std::string &name) : - Node(id, name), - mode(MODE_FREERUN), - sample_rate(FS_10kSPS), - fps(FB_10FPS), - sync(SYNC_PPS), - daq_cfg({sample_rate, fps, mode, sync}), - shared_mem(nullptr), // initalization - shared_mem_pos(0), // initalization - shared_mem_inc(0), // initalization - shared_mem_dim(0), // initalization - buffer_size(0) -{ - return; +SMUNode::SMUNode(const uuid_t &id, const std::string &name) + : Node(id, name), mode(MODE_FREERUN), sample_rate(FS_10kSPS), fps(FB_10FPS), + sync(SYNC_PPS), daq_cfg({sample_rate, fps, mode, sync}), + shared_mem(nullptr), // initalization + shared_mem_pos(0), // initalization + shared_mem_inc(0), // initalization + shared_mem_dim(0), // initalization + buffer_size(0) { + return; } -int SMUNode::prepare() -{ - assert(state == State::CHECKED); - return Node::prepare(); +int SMUNode::prepare() { + assert(state == State::CHECKED); + return Node::prepare(); } -int SMUNode::parse(json_t *json) -{ - int ret = Node::parse(json); - if (ret) - return ret; - - json_error_t err; - - - json_t *jsonDumpers = nullptr; - - char *modeIn = nullptr; - char *syncIn = nullptr; - char *fpsIn = nullptr; - char *sample_rateIn = nullptr; - json_t *in_json = nullptr; - - - ret = json_unpack_ex(json, &err, 0, "{ s?: s, s?: s, s?: s, s?: s, s?: o, s?: o }", - "mode", &modeIn, - "sync", &syncIn, - "fps", &fpsIn, - "sample_rate", &sample_rateIn, - "dumper", &jsonDumpers, - "in", &in_json - ); - if (ret) - throw ConfigError(json, err, "node-config-node-smu"); - - if (jsonDumpers) { - auto signals = getInputSignals(); - - size_t i; - json_t *jsonDumper; - ret = json_unpack_ex(jsonDumpers, &err, 0, "{ o }", - &jsonDumper - ); - json_array_foreach(jsonDumpers, i, jsonDumper) { - char *nameIn = nullptr; - char *pathIn = nullptr; - - ret = json_unpack_ex(jsonDumper, &err, 0, "{ s: s, s: s }", - "name", &nameIn, - "path", &pathIn - ); - if (ret) - throw ConfigError(json, err, "node-config-node-smu", "Failed to parse dumper configuration"); - - int idx = signals->getIndexByName(nameIn); - if (idx == -1) - throw ConfigError(json, err, "node-config-node-smu", "Could not find signal {} for dumper", nameIn); - - dumpers[idx].setPath(pathIn); - dumpers[idx].openSocket(); - dumpers[idx].setActive(); - - } - +int SMUNode::parse(json_t *json) { + int ret = Node::parse(json); + if (ret) + return ret; + + json_error_t err; + + json_t *jsonDumpers = nullptr; + + char *modeIn = nullptr; + char *syncIn = nullptr; + char *fpsIn = nullptr; + char *sample_rateIn = nullptr; + json_t *in_json = nullptr; + + ret = json_unpack_ex(json, &err, 0, + "{ s?: s, s?: s, s?: s, s?: s, s?: o, s?: o }", "mode", + &modeIn, "sync", &syncIn, "fps", &fpsIn, "sample_rate", + &sample_rateIn, "dumper", &jsonDumpers, "in", &in_json); + if (ret) + throw ConfigError(json, err, "node-config-node-smu"); + + if (jsonDumpers) { + auto signals = getInputSignals(); + + size_t i; + json_t *jsonDumper; + ret = json_unpack_ex(jsonDumpers, &err, 0, "{ o }", &jsonDumper); + json_array_foreach(jsonDumpers, i, jsonDumper) { + char *nameIn = nullptr; + char *pathIn = nullptr; + + ret = json_unpack_ex(jsonDumper, &err, 0, "{ s: s, s: s }", "name", + &nameIn, "path", &pathIn); + if (ret) + throw ConfigError(json, err, "node-config-node-smu", + "Failed to parse dumper configuration"); + + int idx = signals->getIndexByName(nameIn); + if (idx == -1) + throw ConfigError(json, err, "node-config-node-smu", + "Could not find signal {} for dumper", nameIn); + + dumpers[idx].setPath(pathIn); + dumpers[idx].openSocket(); + dumpers[idx].setActive(); } - - if(!modeIn || strcmp(modeIn, "MODE_FREERUN")==0) - mode = MODE_FREERUN; - else if (strcmp(modeIn, "MODE_ONESHOT")==0) - mode = MODE_ONESHOT; - else if (strcmp(modeIn, "MODE_VIRTUAL")==0) - mode = MODE_VIRTUAL; - else if (strcmp(modeIn, "MODE_MAX")==0) - mode = MODE_MAX; - - if(!syncIn || strcmp(syncIn, "SYNC_PPS")==0) - sync = SYNC_PPS; - else if (strcmp(syncIn, "SYNC_NONE")==0) - sync = SYNC_NONE; - else if (strcmp(syncIn, "SYNC_NTP")==0) - sync = SYNC_NTP; - else if (strcmp(syncIn, "SYNC_MAX")==0) - sync = SYNC_MAX; - - if(!fpsIn || strcmp(fpsIn, "FB_10FPS")==0) - fps = FB_10FPS; - else if (strcmp(fpsIn, "FB_20FPS")==0) - fps = FB_20FPS; - else if (strcmp(fpsIn, "FB_50FPS")==0) - fps = FB_50FPS; - else if (strcmp(fpsIn, "FB_100FPS")==0) - fps = FB_100FPS; - else if (strcmp(fpsIn, "FB_200FPS")==0) - fps = FB_200FPS; - - if (!sample_rateIn || strcmp(sample_rateIn, "FS_10kSPS")==0) - sample_rate = FS_10kSPS; - else if (strcmp(sample_rateIn, "FS_1kSPS")==0) - sample_rate = FS_1kSPS; - else if (strcmp(sample_rateIn, "FS_2kSPS")==0) - sample_rate = FS_2kSPS; - else if (strcmp(sample_rateIn, "FS_5kSPS")==0) - sample_rate = FS_5kSPS; - else if (strcmp(sample_rateIn, "FS_20kSPS")==0) - sample_rate = FS_20kSPS; - else if (strcmp(sample_rateIn, "FS_25kSPS")==0) - sample_rate = FS_25kSPS; - else if (strcmp(sample_rateIn, "FS_50kSPS")==0) - sample_rate = FS_50kSPS; - else if (strcmp(sample_rateIn, "FS_100kSPS")==0) - sample_rate = FS_100kSPS; - else if (strcmp(sample_rateIn, "FS_200kSPS")==0) { - sample_rate = FS_200kSPS; - } - - - - if (json_is_object(in_json) && json_object_get(in_json, "vectorize")) { - throw ConfigError(json, "node-config-node-smu", "Vectorize cannot be overwritten for this node type!"); - } - in.vectorize = sample_rate * 1000 / fps; - - return 0; + } + + if (!modeIn || strcmp(modeIn, "MODE_FREERUN") == 0) + mode = MODE_FREERUN; + else if (strcmp(modeIn, "MODE_ONESHOT") == 0) + mode = MODE_ONESHOT; + else if (strcmp(modeIn, "MODE_VIRTUAL") == 0) + mode = MODE_VIRTUAL; + else if (strcmp(modeIn, "MODE_MAX") == 0) + mode = MODE_MAX; + + if (!syncIn || strcmp(syncIn, "SYNC_PPS") == 0) + sync = SYNC_PPS; + else if (strcmp(syncIn, "SYNC_NONE") == 0) + sync = SYNC_NONE; + else if (strcmp(syncIn, "SYNC_NTP") == 0) + sync = SYNC_NTP; + else if (strcmp(syncIn, "SYNC_MAX") == 0) + sync = SYNC_MAX; + + if (!fpsIn || strcmp(fpsIn, "FB_10FPS") == 0) + fps = FB_10FPS; + else if (strcmp(fpsIn, "FB_20FPS") == 0) + fps = FB_20FPS; + else if (strcmp(fpsIn, "FB_50FPS") == 0) + fps = FB_50FPS; + else if (strcmp(fpsIn, "FB_100FPS") == 0) + fps = FB_100FPS; + else if (strcmp(fpsIn, "FB_200FPS") == 0) + fps = FB_200FPS; + + if (!sample_rateIn || strcmp(sample_rateIn, "FS_10kSPS") == 0) + sample_rate = FS_10kSPS; + else if (strcmp(sample_rateIn, "FS_1kSPS") == 0) + sample_rate = FS_1kSPS; + else if (strcmp(sample_rateIn, "FS_2kSPS") == 0) + sample_rate = FS_2kSPS; + else if (strcmp(sample_rateIn, "FS_5kSPS") == 0) + sample_rate = FS_5kSPS; + else if (strcmp(sample_rateIn, "FS_20kSPS") == 0) + sample_rate = FS_20kSPS; + else if (strcmp(sample_rateIn, "FS_25kSPS") == 0) + sample_rate = FS_25kSPS; + else if (strcmp(sample_rateIn, "FS_50kSPS") == 0) + sample_rate = FS_50kSPS; + else if (strcmp(sample_rateIn, "FS_100kSPS") == 0) + sample_rate = FS_100kSPS; + else if (strcmp(sample_rateIn, "FS_200kSPS") == 0) { + sample_rate = FS_200kSPS; + } + + if (json_is_object(in_json) && json_object_get(in_json, "vectorize")) { + throw ConfigError(json, "node-config-node-smu", + "Vectorize cannot be overwritten for this node type!"); + } + in.vectorize = sample_rate * 1000 / fps; + + return 0; } -int SMUNode::start() -{ - assert(state == State::PREPARED || - state == State::PAUSED); - - int ret = Node::start(); - - - daq_cfg.rate = sample_rate; - daq_cfg.buff = fps; - daq_cfg.mode = mode; - daq_cfg.sync = sync; - - - fd = ::open(SMU_DEV, O_RDWR); - if (fd < 0) - logger->warn("Fail to open the device driver"); - - // Associate kernel-to-user Task ID - if (ioctl(fd, SMU_IOC_REG_TASK, 0)){ - logger->warn("Fail to register the driver"); - ::close(fd); - // return; - } - - // Map kernel-to-user shared memory - void *sh_mem = mmap(nullptr, MMAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - shared_mem = (uint8_t*)sh_mem; - if (shared_mem == MAP_FAILED) - logger->warn("Fail to map driver memory"); - - // Install PPS signal handler - sigemptyset(&act.sa_mask); - act.sa_flags = (SA_SIGINFO | SA_RESTART); - act.sa_sigaction = sync_signal; - if (sigaction(SMU_SIG_SYNC, &act, nullptr)) - logger->warn("Fail to install PPS handler"); - - // Install ADC signal handler - sigemptyset(&act.sa_mask); - act.sa_flags = (SA_SIGINFO | SA_RESTART); - act.sa_sigaction = data_available_signal; - if (sigaction(SMU_SIG_DATA, &act, nullptr)) - logger->warn("Fail to install ADC handler"); - - // Update DAQ memory configuration - shared_mem_pos = 0; - shared_mem_inc = sizeof(smu_mcsc_t); - shared_mem_dim = daq_cfg.rate; - - // Stop DAQ driver - if (ioctl(fd, SMU_IOC_STOP, 0)) - logger->warn("Fail to stop the driver"); - - // Configure DAQ driver - if (::write(fd, &daq_cfg, sizeof(daq_cfg.rate))) - logger->warn("Fail to configure the driver"); - - // Start DAQ driver - if (ioctl(fd, SMU_IOC_START, 0)) { - logger->warn("Fail to start the driver"); - } - - if (!ret) - state = State::STARTED; - - return ret; +int SMUNode::start() { + assert(state == State::PREPARED || state == State::PAUSED); + + int ret = Node::start(); + + daq_cfg.rate = sample_rate; + daq_cfg.buff = fps; + daq_cfg.mode = mode; + daq_cfg.sync = sync; + + fd = ::open(SMU_DEV, O_RDWR); + if (fd < 0) + logger->warn("Fail to open the device driver"); + + // Associate kernel-to-user Task ID + if (ioctl(fd, SMU_IOC_REG_TASK, 0)) { + logger->warn("Fail to register the driver"); + ::close(fd); + } + + // Map kernel-to-user shared memory + void *sh_mem = + mmap(nullptr, MMAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + shared_mem = (uint8_t *)sh_mem; + if (shared_mem == MAP_FAILED) + logger->warn("Fail to map driver memory"); + + // Install PPS signal handler + sigemptyset(&act.sa_mask); + act.sa_flags = (SA_SIGINFO | SA_RESTART); + act.sa_sigaction = sync_signal; + if (sigaction(SMU_SIG_SYNC, &act, nullptr)) + logger->warn("Fail to install PPS handler"); + + // Install ADC signal handler + sigemptyset(&act.sa_mask); + act.sa_flags = (SA_SIGINFO | SA_RESTART); + act.sa_sigaction = data_available_signal; + if (sigaction(SMU_SIG_DATA, &act, nullptr)) + logger->warn("Fail to install ADC handler"); + + // Update DAQ memory configuration + shared_mem_pos = 0; + shared_mem_inc = sizeof(smu_mcsc_t); + shared_mem_dim = daq_cfg.rate; + + // Stop DAQ driver + if (ioctl(fd, SMU_IOC_STOP, 0)) + logger->warn("Fail to stop the driver"); + + // Configure DAQ driver + if (::write(fd, &daq_cfg, sizeof(daq_cfg.rate))) + logger->warn("Fail to configure the driver"); + + // Start DAQ driver + if (ioctl(fd, SMU_IOC_START, 0)) { + logger->warn("Fail to start the driver"); + } + + if (!ret) + state = State::STARTED; + + return ret; } -int SMUNode::stop() -{ - // Stop DAQ driver - if(!ioctl(fd, SMU_IOC_STOP, 0)) { - // Unmap kernel-to-user shared memory - munmap(shared_mem, MMAP_SIZE); - while(close(fd) != 0){} +int SMUNode::stop() { + // Stop DAQ driver + if (!ioctl(fd, SMU_IOC_STOP, 0)) { + // Unmap kernel-to-user shared memory + munmap(shared_mem, MMAP_SIZE); + while (close(fd) != 0) { } + } - return 1; + return 1; } -void SMUNode::sync_signal(int, siginfo_t *info, void*) -{ - +void SMUNode::sync_signal(int, siginfo_t *info, void *) { - ioctl(fd, SMU_IOC_GET_TIME,&sync_signal_mem_pos); - sample_time.tv_nsec = sync_signal_mem_pos.tv_nsec; //macht nix - sample_time.tv_sec = sync_signal_mem_pos.tv_sec; + ioctl(fd, SMU_IOC_GET_TIME, &sync_signal_mem_pos); + sample_time.tv_nsec = sync_signal_mem_pos.tv_nsec; //macht nix + sample_time.tv_sec = sync_signal_mem_pos.tv_sec; - if (sample_time.tv_nsec > 500000000) - sample_time.tv_sec += 1; - //std::cout << "\n\npps event\n\n"; + if (sample_time.tv_nsec > 500000000) + sample_time.tv_sec += 1; } -void SMUNode::data_available_signal(int, siginfo_t *info, void*) -{ +void SMUNode::data_available_signal(int, siginfo_t *info, void *) { - mem_pos = (info->si_value.sival_int); - /* Signal uldaq_read() about new data */ - pthread_cond_signal(&cv); + mem_pos = (info->si_value.sival_int); + pthread_cond_signal(&cv); } +int SMUNode::_read(struct Sample *smps[], unsigned cnt) { + struct timespec ts; + ts.tv_sec = sample_time.tv_sec; + pthread_mutex_lock(&mutex); -int SMUNode::_read(struct Sample *smps[], unsigned cnt) -{ - struct timespec ts; - ts.tv_sec = sample_time.tv_sec; - pthread_mutex_lock(&mutex); - - pthread_cond_wait(&cv, &mutex); - size_t mem_pos_local = mem_pos; + pthread_cond_wait(&cv, &mutex); + size_t mem_pos_local = mem_pos; - smu_mcsc_t* p = (smu_mcsc_t*)shared_mem; + smu_mcsc_t *p = (smu_mcsc_t *)shared_mem; + for (unsigned j = 0; j < cnt; j++) { + struct Sample *t = smps[j]; + ts.tv_nsec = mem_pos_local * 1e6 / + (sample_rate); - for (unsigned j = 0; j < cnt; j++) { - struct Sample *t = smps[j]; - ts.tv_nsec = mem_pos_local * 1e6 / (sample_rate);//current_sample*1e9* 1/(sample_rate * 1000) - - for (unsigned i = 0; i < 8; i++) { //auslagern, Steffen fragen - int16_t data = p[mem_pos_local].ch[i]; - t->data[i].f = ((double)data); - if (dumpers[i].isActive()) - dumpers[i].writeDataBinary(1, &(t->data[i].f)); - } - - mem_pos_local++; - - t->flags = (int) SampleFlags::HAS_TS_ORIGIN | (int) SampleFlags::HAS_DATA | (int) SampleFlags::HAS_SEQUENCE; - t->ts.origin = ts; - t->sequence = sequence++; - t->length = 8; - t->signals = in.signals; + for (unsigned i = 0; i < 8; i++) { + int16_t data = p[mem_pos_local].ch[i]; + t->data[i].f = ((double)data); + if (dumpers[i].isActive()) + dumpers[i].writeDataBinary(1, &(t->data[i].f)); + } + mem_pos_local++; - } + t->flags = (int)SampleFlags::HAS_TS_ORIGIN | (int)SampleFlags::HAS_DATA | + (int)SampleFlags::HAS_SEQUENCE; + t->ts.origin = ts; + t->sequence = sequence++; + t->length = 8; + t->signals = in.signals; + } - pthread_mutex_unlock(&mutex); + pthread_mutex_unlock(&mutex); - return cnt; + return cnt; } static char n[] = "smu"; static char d[] = "SMU data acquisition"; -static NodePlugin p; +static NodePlugin + p; diff --git a/tests/integration/node-smu.sh b/tests/integration/node-smu.sh index e020295bb..161f55426 100644 --- a/tests/integration/node-smu.sh +++ b/tests/integration/node-smu.sh @@ -24,28 +24,22 @@ mkdir ./logs cat > config.json < Date: Thu, 24 Apr 2025 12:11:09 +0000 Subject: [PATCH 3/5] Add openapi specs Signed-off-by: Alexandra --- .../components/schemas/config/nodes/_smu.yaml | 7 ++ .../components/schemas/config/nodes/smu.yaml | 64 +++++++++++++++++++ tests/integration/node-smu.sh | 0 3 files changed, 71 insertions(+) create mode 100644 doc/openapi/components/schemas/config/nodes/_smu.yaml create mode 100644 doc/openapi/components/schemas/config/nodes/smu.yaml mode change 100644 => 100755 tests/integration/node-smu.sh diff --git a/doc/openapi/components/schemas/config/nodes/_smu.yaml b/doc/openapi/components/schemas/config/nodes/_smu.yaml new file mode 100644 index 000000000..67f614294 --- /dev/null +++ b/doc/openapi/components/schemas/config/nodes/_smu.yaml @@ -0,0 +1,7 @@ +# yaml-language-server: $schema=http://json-schema.org/draft-07/schema +# SPDX-FileCopyrightText: 2014-2025 Institute for Automation of Complex Power Systems, RWTH Aachen University +# SPDX-License-Identifier: Apache-2.0 +--- +allOf: +- $ref: ../node_obj.yaml +- $ref: smu.yaml diff --git a/doc/openapi/components/schemas/config/nodes/smu.yaml b/doc/openapi/components/schemas/config/nodes/smu.yaml new file mode 100644 index 000000000..933b5b19c --- /dev/null +++ b/doc/openapi/components/schemas/config/nodes/smu.yaml @@ -0,0 +1,64 @@ +# yaml-language-server: $schema=http://json-schema.org/draft-07/schema +# SPDX-FileCopyrightText: 2014-2023 Institute for Automation of Complex Power Systems, RWTH Aachen University +# SPDX-License-Identifier: Apache-2.0 +--- +allOf: +- type: object + properties: + format: + $ref: ../format_spec.yaml + + mode: + type: string + enum: + - MODE_ONESHOT + - MODE_FREERUN + - MODE_VIRTUAL + - MODE_MAX + description: | + DAQ acquisition mode. + + sync: + type: string + enum: + - SYNC_NONE + - SYNC_PPS + - SYNC_NTP + - SYNC_MAX + description: | + DAQ synchronization mode. + + fps: + type: string + enum: + - FB_10FPS + - FB_20FPS + - FB_50FPS + - FB_100FPS + - FB_200FPS + description: | + DAQ buffer frame rate (Hz / FPS). + + sample_rate: + type: string + enum: + - FS_1kSPS + - FS_2kSPS + - FS_5kSPS + - FS_10kSPS + - FS_20kSPS + - FS_25kSPS + - FS_50kSPS + - FS_100kSPS + - FS_200kSPS + description: | + DAQ sample rate (kHz / kSPS). + + dumper: + type: object + + in: + type: object + +- $ref: ../node_signals.yaml +- $ref: ../node.yaml diff --git a/tests/integration/node-smu.sh b/tests/integration/node-smu.sh old mode 100644 new mode 100755 From c3af7683028bb5d1e1b045247d5a0938f48b5468 Mon Sep 17 00:00:00 2001 From: Alexandra Date: Thu, 24 Apr 2025 14:57:00 +0000 Subject: [PATCH 4/5] convert indentation to spaces Signed-off-by: Alexandra --- etc/examples/nodes/smu.conf | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/etc/examples/nodes/smu.conf b/etc/examples/nodes/smu.conf index e0a406ad7..008edd037 100644 --- a/etc/examples/nodes/smu.conf +++ b/etc/examples/nodes/smu.conf @@ -2,30 +2,30 @@ # SPDX-License-Identifier: Apache-2.0 http = { - enabled = false + enabled = false } logging = { - # level = "warn" + # level = "warn" } nodes = { - smu = { - type = "smu" - signals = ( - { name = "ch1" type = "float"}, - { name = "ch2" type = "float"}, - { name = "signal3" type = "float"}, - { name = "signal4" type = "float"}, - { name = "signal5" type = "float"}, - { name = "signal6" type = "float"}, - { name = "signal7" type = "float"} + smu = { + type = "smu" + signals = ( + { name = "ch1", type = "float"}, + { name = "ch2", type = "float"}, + { name = "signal3", type = "float"}, + { name = "signal4", type = "float"}, + { name = "signal5", type = "float"}, + { name = "signal6", type = "float"}, + { name = "signal7", type = "float"} ) - vectorize = 1000 + vectorize = 1000 sample_rate = "FS_10kSPS" dumper = ( - { name = "ch1" path = "/tmp/ch1"}, - { name = "ch2" path = "/tmp/ch2"} + { name = "ch1", path = "/tmp/ch1"}, + { name = "ch2", path = "/tmp/ch2"} ) - } + } file = { type = "file" From ea3eb9edf458ecaa1b67409c885d448ef08fb34b Mon Sep 17 00:00:00 2001 From: Alexandra Date: Fri, 25 Apr 2025 06:51:36 +0000 Subject: [PATCH 5/5] apply clang-format Signed-off-by: Alexandra --- lib/nodes/smu.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/nodes/smu.cpp b/lib/nodes/smu.cpp index 65e8a3e7f..ca1d03ce0 100644 --- a/lib/nodes/smu.cpp +++ b/lib/nodes/smu.cpp @@ -247,8 +247,7 @@ int SMUNode::_read(struct Sample *smps[], unsigned cnt) { for (unsigned j = 0; j < cnt; j++) { struct Sample *t = smps[j]; - ts.tv_nsec = mem_pos_local * 1e6 / - (sample_rate); + ts.tv_nsec = mem_pos_local * 1e6 / (sample_rate); for (unsigned i = 0; i < 8; i++) { int16_t data = p[mem_pos_local].ch[i];