1
0
Fork 0
mirror of https://git.rwth-aachen.de/acs/public/villas/node/ synced 2025-03-09 00:00:00 +01:00

Minor cleanup

- Move lambde `fill_asdu` to dedicated function SlaveNode::fillASDU.
- Remove "-slave" suffix from node name so it does not mess up logging
  and help message.
- Expose queue sizes settings in config
This commit is contained in:
Philipp Jungkamp 2022-06-23 15:32:29 +00:00
parent 44203fa77c
commit 3e787eeb85
3 changed files with 53 additions and 46 deletions

View file

@ -1,7 +1,7 @@
nodes = {
iec104 = {
type = "iec60870-5-104-slave"
type = "iec60870-5-104"
# network address and port of the server
# 0.0.0.0 listens on all interfaces
@ -9,6 +9,9 @@ nodes = {
port = 2404
# common address of this IEC104 slave
ca = 41025
# queue sizes for this node
low_priority_queue = 100
high_priority_queue = 100
out = {
# map signals to information object addresses and asdu data types

View file

@ -139,8 +139,8 @@ protected:
std::string local_address = "0.0.0.0";
int local_port = 2404;
int common_address = 1;
int low_priority_queue_size = 100;
int high_priority_queue_size = 100;
int low_priority_queue = 100;
int high_priority_queue = 100;
// config (use lib60870 defaults if std::nullopt)
std::optional<int> apci_t0 = std::nullopt;
@ -178,6 +178,8 @@ protected:
bool onInterrogation(IMasterConnection connection, CS101_ASDU asdu, uint8_t _of_inter) const noexcept;
bool onASDU(IMasterConnection connection, CS101_ASDU asdu) const noexcept;
unsigned fillASDU(CS101_ASDU &asdu, Sample const *sample, ASDUData::Type type) const noexcept(false);
virtual
int _write(struct Sample * smps[], unsigned cnt) override;

View file

@ -289,7 +289,7 @@ void SlaveNode::createSlave() noexcept
this->destroySlave();
// create the slave object
server.slave = CS104_Slave_create(server.low_priority_queue_size,server.high_priority_queue_size);
server.slave = CS104_Slave_create(server.low_priority_queue,server.high_priority_queue);
CS104_Slave_setServerMode(server.slave, CS104_MODE_CONNECTION_IS_REDUNDANCY_GROUP);
// configure the slave according to config
@ -312,7 +312,7 @@ void SlaveNode::createSlave() noexcept
return self->onClockSync(connection,asdu,new_time);
}, this);
CS104_Slave_setInterrogationHandler(server.slave, [] (void *tcp_node, IMasterConnection connection, CS101_ASDU asdu, uint8_t qoi) {
CS104_Slave_setInterrogationHandler(server.slave, [] (void *tcp_node, IMasterConnection connection, CS101_ASDU asdu, QualifierOfInterrogation qoi) {
auto self = static_cast<SlaveNode const *> (tcp_node);
return self->onInterrogation(connection,asdu,qoi);
}, this);
@ -411,7 +411,7 @@ bool SlaveNode::onClockSync(IMasterConnection connection, CS101_ASDU asdu, CP56T
return true;
}
bool SlaveNode::onInterrogation(IMasterConnection connection, CS101_ASDU asdu, uint8_t qoi) const noexcept
bool SlaveNode::onInterrogation(IMasterConnection connection, CS101_ASDU asdu, QualifierOfInterrogation qoi) const noexcept
{
auto &mapping = this->output.mapping;
auto &last_values = this->output.last_values;
@ -474,41 +474,41 @@ bool SlaveNode::onASDU(IMasterConnection connection, CS101_ASDU asdu) const noex
return true;
}
unsigned SlaveNode::fillASDU(CS101_ASDU &asdu, Sample const *sample, ASDUData::Type type) const noexcept(false) {
int asdu_elements = 0;
auto &mapping = this->output.mapping;
for (unsigned signal = 0; signal < MIN(sample->length, mapping.size()); signal++) {
if (mapping[signal].type() != type) continue;
auto timestamp = (sample->flags & (int) SampleFlags::HAS_TS_ORIGIN)
? std::optional{ sample->ts.origin }
: std::nullopt;
if (mapping[signal].hasTimestamp() && !timestamp.has_value())
throw RuntimeError("Received sample without timestamp for ASDU type with mandatory timestamp");
if (mapping[signal].signalType() != sample_format(sample,signal))
throw RuntimeError("Expected signal type {}, but received {}",
signalTypeToString(mapping[signal].signalType()),
signalTypeToString(sample_format(sample,signal))
);
mapping[signal].addSampleToASDU(asdu, ASDUData::Sample {
sample->data[signal],
IEC60870_QUALITY_GOOD,
timestamp
});
asdu_elements++;
}
assert(CS101_ASDU_getNumberOfElements(asdu) == asdu_elements);
return asdu_elements;
};
int SlaveNode::_write(Sample *samples[], unsigned sample_count)
{
auto fill_asdu = [this] (CS101_ASDU &asdu, Sample const *sample, ASDUData::Type type) {
int asdu_elements = 0;
auto &mapping = this->output.mapping;
for (unsigned signal = 0; signal < MIN(sample->length, mapping.size()); signal++) {
if (mapping[signal].type() != type) continue;
auto timestamp = (sample->flags & (int) SampleFlags::HAS_TS_ORIGIN)
? std::optional{ sample->ts.origin }
: std::nullopt;
if (mapping[signal].hasTimestamp() && !timestamp.has_value())
throw RuntimeError("Received sample without timestamp for ASDU type with mandatory timestamp");
if (mapping[signal].signalType() != sample_format(sample,signal))
throw RuntimeError("Expected signal type {}, but received {}",
signalTypeToString(mapping[signal].signalType()),
signalTypeToString(sample_format(sample,signal))
);
mapping[signal].addSampleToASDU(asdu, ASDUData::Sample {
sample->data[signal],
IEC60870_QUALITY_GOOD,
timestamp
});
asdu_elements++;
}
assert(CS101_ASDU_getNumberOfElements(asdu) == asdu_elements);
return asdu_elements;
};
for (unsigned sample_index = 0; sample_index < sample_count; sample_index++) {
Sample const *sample = samples[sample_index];
@ -532,7 +532,7 @@ int SlaveNode::_write(Sample *samples[], unsigned sample_count)
);
// if data was added to asdu, enqueue it
if (fill_asdu(asdu, sample, asdu_type) != 0)
if (this->fillASDU(asdu, sample, asdu_type) != 0)
CS104_Slave_enqueueASDU(this->server.slave, asdu);
CS101_ASDU_destroy(asdu);
@ -564,13 +564,15 @@ int SlaveNode::parse(json_t *json, const uuid_t sn_uuid)
json_t *out_json = nullptr;
char const *address = nullptr;
if(json_unpack_ex(json, &err, 0, "{ s?: o, s?: s, s?: i, s?: i }",
if(json_unpack_ex(json, &err, 0, "{ s?: o, s?: s, s?: i, s?: i, s?: i, s?: i }",
"out", &out_json,
"address", &address,
"port", &this->server.local_port,
"ca", &this->server.common_address
"ca", &this->server.common_address,
"low_priority_queue", &this->server.low_priority_queue,
"high_priority_queue", &this->server.high_priority_queue
))
throw ConfigError(json, err, "node-config-node-iec60870-5-104-slave");
throw ConfigError(json, err, "node-config-node-iec60870-5-104");
if (address)
this->server.local_address = address;
@ -581,7 +583,7 @@ int SlaveNode::parse(json_t *json, const uuid_t sn_uuid)
if(json_unpack_ex(out_json, &err, 0, "{ s: o }",
"signals", &signals_json
))
throw ConfigError(out_json, err, "node-config-node-iec60870-5-104-slave");
throw ConfigError(out_json, err, "node-config-node-iec60870-5-104");
}
auto parse_asdu_data = [&err] (json_t *signal_json) -> ASDUData {
@ -595,7 +597,7 @@ int SlaveNode::parse(json_t *json, const uuid_t sn_uuid)
"asdu_type_id", &asdu_type_id,
"ioa", &ioa
))
throw ConfigError(signal_json, err, "node-config-node-iec60870-5-104-slave");
throw ConfigError(signal_json, err, "node-config-node-iec60870-5-104");
if (ioa == 0)
throw RuntimeError("Found invalid ioa {} in config", ioa);
@ -679,6 +681,6 @@ int SlaveNode::stop()
// Plugin
// ------------------------------------------
static char name[] = "iec60870-5-104-slave";
static char name[] = "iec60870-5-104";
static char description[] = "Provide values as protocol slave";
static NodePlugin<SlaveNode, name, description, (int) NodeFactory::Flags::SUPPORTS_WRITE> p;