Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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")
Expand Down
7 changes: 7 additions & 0 deletions doc/openapi/components/schemas/config/nodes/_smu.yaml
Original file line number Diff line number Diff line change
@@ -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
64 changes: 64 additions & 0 deletions doc/openapi/components/schemas/config/nodes/smu.yaml
Original file line number Diff line number Diff line change
@@ -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
69 changes: 69 additions & 0 deletions etc/examples/nodes/smu.conf
Original file line number Diff line number Diff line change
@@ -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
}
)
}
)
166 changes: 166 additions & 0 deletions include/villas/nodes/smu.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
/* Node-type for SMU data acquisition.
*
* Author: Manuel Pitz <manuel.pitz@eonerc.rwth-aachen.de>
* SPDX-FileCopyrightText: 2014-2023 Institute for Automation of Complex Power Systems, RWTH Aachen University
* SPDX-License-Identifier: Apache-2.0
*/

#pragma once

#include <jansson.h>
#include <villas/dumper.hpp>
#include <villas/node.hpp>
#include <villas/queue_signalled.h>

extern "C" {

#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
}

#define SMU_NCH 8

namespace villas {
namespace node {

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
{
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;

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
{
int16_t ch[SMU_NCH];
} __attribute__((__packed__)) smu_mcsc_t;

typedef struct // SMU multi-channel sample real
{
float ch[SMU_NCH];
} __attribute__((__packed__)) smu_mcsr_t;

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;
} __attribute__((__packed__)) timespec64_t;

// 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<size_t> 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 */
4 changes: 4 additions & 0 deletions lib/nodes/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
Loading