Added support for offset on DNP3

This commit is contained in:
Thiago Alves 2018-12-27 15:15:37 -02:00 committed by GitHub
parent 1d40db5358
commit 2c330b53d9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 121 additions and 18 deletions

73
webserver/core/dnp3.cfg Normal file
View File

@ -0,0 +1,73 @@
# ----------------------------------------------------------------
# Configuration file for DNP3
#-----------------------------------------------------------------
# Use this file to fill out DNP3 settings for your Open PLC
# Uncomment settings as you want them
# Link Settings
#-----------------------------------------------------------------
# local address
local_address = 10
# master address allowed
remote_address = 1
# keep alive timeout
# time (s) or MAX
# keep_alive_timeout = MAX
# Parameters
#-----------------------------------------------------------------
# enable unsolicited reporting if master allows it
# True or False
enable_unsolicited = True
# how long (seconds) the outstation will allow a operate
# to follow a select
# select_timeout = 10
# max control commands for a single APDU
# max_controls_per_request = 16
# maximum fragment size the outstation will recieve
# default is the max value
# max_rx_frag_size = 2048
# maximum fragment size the outstation will send if
# it needs to fragment. Default is the max falue
# max_tx_frag_size = 2048
# size of the event buffer
event_buffer_size = 10
# number of values the outstation will report at once
# AKA database size
database_size = 8
# First data point offset for DI - required if slave device used (the address should represent 1st data point of slave device)
offset_di = 800
# First data point offset for DO - required if slave device used (the address should represent 1st data point of slave device)
offset_do = 800
# First data point offset for AI - required if slave device used (the address should represent 1st data point of slave device)
offset_ai = 100
# First data point offset for AO - required if slave device used (the address should represent 1st data point of slave device)
offset_ao = 100
#Timeout for solicited confirms
# in MS
# sol_confirm_timeout = 5000
#Timeout for unsolicited confirms (ms)
# unsol_conrfirm_timeout = 5000
#Timeout for unsolicited retries (ms)
# unsol_retry_timeout = 5000

View File

@ -43,7 +43,11 @@
#define OPLC_CYCLE 50000000
// Initial offset parameters (yurgen1975)
int offset_di = 0;
int offset_do = 0;
int offset_ai = 0;
int offset_ao = 0;
using namespace std;
using namespace opendnp3;
@ -84,18 +88,22 @@ static inline std::string &trim(std::string &s) {
class CommandCallback: public ICommandHandler {
public:
//CROB
//CROB - changed to support offsets (yurgen1975)
virtual CommandStatus Select(const ControlRelayOutputBlock& command, uint16_t index) {
index = index + offset_di;
return CommandStatus::SUCCESS;
}
virtual CommandStatus Operate(const ControlRelayOutputBlock& command, uint16_t index, OperateType opType) {
index = index + offset_di;
auto code = command.functionCode;
CommandStatus return_val;
if(code == ControlCode::LATCH_ON || code == ControlCode::LATCH_OFF) {
return_val = CommandStatus::SUCCESS;
IEC_BOOL crob_val = (code == ControlCode::LATCH_ON);
pthread_mutex_lock(&bufferLock);
if(bool_output[index/8][index%8] != NULL) {
*bool_output[index/8][index%8] = crob_val;
@ -105,15 +113,16 @@ public:
else {
return_val = CommandStatus::NOT_SUPPORTED;
}
return return_val;
}
//Analog Out
//Analog Out - changed to support offsets (yurgen1975)
virtual CommandStatus Select(const AnalogOutputInt16& command, uint16_t index) {
index = index + offset_ao;
return CommandStatus::SUCCESS;
}
virtual CommandStatus Operate(const AnalogOutputInt16& command, uint16_t index, OperateType opType) {
index = index + offset_ao;
auto ao_val = command.value;
pthread_mutex_lock(&bufferLock);
if(index < MIN_16B_RANGE && int_output[index] != NULL) {
@ -194,27 +203,28 @@ protected:
//------------------------------------------------------------------
// Function to update DNP3 values every time they may have changed
// Updated by Yurgen1975 to support slave devices: DI/DO address 800 and AI/AO address 100
//------------------------------------------------------------------
void update_vals(std::shared_ptr<IOutstation> outstation){
UpdateBuilder builder;
// Update Discrete input (Binary input)
for(int i = 1; i < MAX_DISCRETE_INPUT; i++) {
builder.Update(Binary((bool)(*bool_input[i/8][i%8])), i);
// Update Discrete input (Binary input) - changed to support offsets (yurgen1975)
for(int i = offset_di; i < MAX_DISCRETE_INPUT; i++) {
builder.Update(Binary((bool)(*bool_input[i/8][i%8])), i-offset_di);
}
// Update Coils (Binary Output)
for(int i = 0; i < MAX_COILS; i++) {
builder.Update(BinaryOutputStatus((bool)(*bool_output[i/8][i%8])), i);
// Update Coils (Binary Output) - changed to support offsets (yurgen1975)
for(int i = offset_do; i < MAX_COILS; i++) {
builder.Update(BinaryOutputStatus((bool)(*bool_output[i/8][i%8])), i-offset_do);
}
// Update Input Registers (Analog Input)
for (int i = 0; i < MAX_INP_REGS; i++) {
builder.Update(Analog((int)(*int_input[i])), i);
// Update Input Registers (Analog Input) - changed to support offsets (yurgen1975)
for (int i = offset_ai; i < MAX_INP_REGS; i++) {
builder.Update(Analog((int)(*int_input[i])), i-offset_ai);
}
// Update Holding Registers (Analog Output)
for (int i = 0; i < MIN_16B_RANGE; i++) {
builder.Update(AnalogOutputStatus((int)(*int_output[i])), i);
// Update Holding Registers (Analog Output) - changed to support offsets (yurgen1975)
for (int i = offset_ao; i < MIN_16B_RANGE; i++) {
builder.Update(AnalogOutputStatus((int)(*int_output[i])), i-offset_ao);
}
// Update Holding registers for memory
for (int i = MIN_16B_RANGE; i < MAX_16B_RANGE; i++) {
@ -338,6 +348,25 @@ OutstationStackConfig parseDNP3Config() {
getline(iss, token, '=');
config.outstation.eventBufferConfig =
EventBufferConfig::AllTypes(atoi(token.c_str()));
// get offsets from dnp.cfg (yurgen1975)
} else if (token == "offset_di") {
getline(iss, token, '=');
offset_di = atoi(token.c_str());
} else if (token == "offset_do") {
getline(iss, token, '=');
offset_do = atoi(token.c_str());
} else if (token == "offset_ai") {
getline(iss, token, '=');
offset_ai = atoi(token.c_str());
} else if (token == "offset_ao") {
getline(iss, token, '=');
offset_ao = atoi(token.c_str());
// -------------------------------------------------------------------
} else if (token == "sol_confirm_timeout") {
getline(iss, token, '=');
config.outstation.params.solConfirmTimeout =
@ -364,6 +393,7 @@ OutstationStackConfig parseDNP3Config() {
}
}
}
return config;
}