Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature/bat-45 #2

Open
wants to merge 32 commits into
base: develop
Choose a base branch
from
3,211 changes: 3,211 additions & 0 deletions .cproject

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,15 @@ libosslcrypto.*
libtestlib.*
libclangfuzzer.*
libdnp3mocks.*
yaml-cpp.*

#test suites
testopenpal
testopendnp3
testasiodnp3
testosslcrypto
testsecauth
testoutstation

#demos
master-demo
Expand Down Expand Up @@ -144,3 +146,11 @@ coverage.info
cpp/demos/cover.info
cpp/demos/cover_html/

# eclipse generated files
RemoteSystemsTempFiles
.metadata
.settings
.autotools

# apps
/outstation
12 changes: 12 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[submodule "thirdparty/asio"]
path = thirdparty/asio
url = ../asio/
branch = develop
[submodule "thirdparty/rapidjson"]
path = thirdparty/rapidjson
url = ../rapidjson
branch = develop
[submodule "thirdparty/yaml-cpp"]
path = thirdparty/yaml-cpp
url = ../yaml-cpp
branch = develop
33 changes: 33 additions & 0 deletions .project
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>dnp3</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.cdt.autotools.core.genmakebuilderV2</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
<triggers>clean,full,incremental,</triggers>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
<triggers>full,incremental,</triggers>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.cdt.core.cnature</nature>
<nature>org.eclipse.cdt.core.ccnature</nature>
<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
<nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
<nature>org.eclipse.cdt.autotools.core.autotoolsNatureV2</nature>
</natures>
</projectDescription>
46 changes: 35 additions & 11 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ set(OPENDNP3_MICRO_VERSION 0)
set(OPENDNP3_VERSION ${OPENDNP3_MAJOR_VERSION}.${OPENDNP3_MINOR_VERSION}.${OPENDNP3_MICRO_VERSION})

# various optional libraries and projects
option(OUTSTATION "Build outstation application" OFF)
option(DEMO "Build demo applications" OFF)
option(TEST "Build tests" OFF)
option(FULL "Build all optional projects (secauth, demos, tests)" OFF)
Expand All @@ -18,6 +19,7 @@ option(STATICLIBS "Builds static versions of all installed libraries" OFF)
option(COVERAGE "Builds the libraries with coverage info for gcov" OFF)

if(FULL)
set(OUTSTATION ON)
set(DEMO ON)
set(TEST ON)
set(SECAUTH ON)
Expand All @@ -43,6 +45,23 @@ if(SECAUTH OR DNP3_TLS)

endif()

if(OUTSTATION OR TEST)
include_directories(./thirdparty/rapidjson/include)
include_directories(./thirdparty/yaml-cpp/include)

add_subdirectory(./thirdparty/yaml-cpp)

set(Boost_USE_STATIC_LIBS OFF)
set(Boost_USE_MULTITHREADED ON)
set(Boost_USE_STATIC_RUNTIME OFF)
find_package(Boost 1.54.0 COMPONENTS system thread program_options)

if(Boost_FOUND)
include_directories(${Boost_INCLUDE_DIRS})
endif()

endif()

if(WIN32)

set_property(GLOBAL PROPERTY USE_FOLDERS ON) #allows the creation of solution folders
Expand Down Expand Up @@ -93,17 +112,8 @@ endif()

set(CMAKE_REQUIRED_FLAGS ${CMAKE_CXX_FLAGS})

if (ASIO_HOME)
message("ASIO_HOME defined in cache: ${ASIO_HOME}")
include_directories(${ASIO_HOME})
else()
if(DEFINED ENV{ASIO_HOME})
message("ASIO_HOME defined in environment: $ENV{ASIO_HOME}")
include_directories($ENV{ASIO_HOME})
else()
message("ASIO_HOME was not defined. ASIO expected to be on include path")
endif()
endif()
# include path for asio submodule
include_directories(./thirdparty/asio/asio/include)

# include paths for all the local libraries
include_directories(./cpp/libs/src)
Expand Down Expand Up @@ -184,6 +194,15 @@ endif()
set(INSTALL_ARGS FILES_MATCHING PATTERN "*.h" PATTERN ".deps" EXCLUDE PATTERN ".libs" EXCLUDE)
install(DIRECTORY ./cpp/libs/include/ DESTINATION include ${INSTALL_ARGS})

if(OUTSTATION)

# ----- outstation executable -----
add_executable(outstation ./cpp/outstation/OutstationApp.cpp)
target_link_libraries (outstation LINK_PUBLIC yaml-cpp asiodnp3 ${PTHREAD} ${Boost_LIBRARIES})
#set_target_properties(outstation PROPERTIES FOLDER demos)

endif()

if(DEMO)

# ----- master demo executable -----
Expand Down Expand Up @@ -279,6 +298,11 @@ if(TEST)
set_target_properties(testosslcrypto PROPERTIES FOLDER tests)

endif()

# ----- outstation app tests -----
file(GLOB_RECURSE outstation_TESTSRC ./cpp/tests/outstation/src/*.cpp ./cpp/tests/outstation/src/*.h)
add_executable (testoutstation ${outstation_TESTSRC})
target_link_libraries (testoutstation yaml-cpp)

endif()

24 changes: 22 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,25 @@ Overview

Opendnp3 is a portable, scalable, and rigorously tested implementation
of the DNP3 (www.dnp.org) protocol stack written in C++11. The library
is designed for high-performance applications like many concurrent TCP
sessions or huge device simulations. It also embeds very nicely on Linux.
can handle the largest front end processor loads, but can also be
ported to run on various microcontrollers.

Langauge bindings are available. Consult the documentation.

Ubuntu 14.04 Dependencies
=========================
```sudo apt-get install cmake libasio-dev libboost-all-dev
```

Build Steps
===========
```bash
git submodule update --init
cmake -DDEMO=on -DTEST=on -DOUTSTATION=on .
make -j5

# from simultaneous shells
./outstation
./master-demo (press 'o' to send analog output 16)
nc localhost 3384
```
75 changes: 40 additions & 35 deletions cpp/examples/master/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,11 @@ int main(int argc, char* argv[])
// Create a new master on a previously declared port, with a
// name, log level, command acceptor, and config info. This
// returns a thread-safe interface used for sending commands.
auto pMaster = pChannel->AddMaster(
"master", // id for logging
PrintingSOEHandler::Instance(), // callback for data processing
asiodnp3::DefaultMasterApplication::Instance(), // master application instance
stackConfig // stack configuration
);

auto pMaster = pChannel->AddMaster("master", // id for logging
PrintingSOEHandler::Instance(), // callback for data processing
asiodnp3::DefaultMasterApplication::Instance(), // master application instance
stackConfig // stack configuration
);

// do an integrity poll (Class 3/2/1/0) once per minute
auto integrityScan = pMaster->AddClassScan(ClassField::AllClasses(), TimeDuration::Minutes(1));
Expand All @@ -104,53 +102,60 @@ int main(int argc, char* argv[])

char cmd;
std::cin >> cmd;
switch(cmd)
switch (cmd)
{
case('a') :
case ('a'):
pMaster->ScanRange(GroupVariationID(1, 2), 0, 3);
break;
case('d') :
pMaster->PerformFunction("disable unsol", FunctionCode::DISABLE_UNSOLICITED,
{ Header::AllObjects(60, 2), Header::AllObjects(60, 3), Header::AllObjects(60, 4) }
);
case ('d'):
pMaster->PerformFunction("disable unsol", FunctionCode::DISABLE_UNSOLICITED, { Header::AllObjects(60, 2), Header::AllObjects(60, 3),
Header::AllObjects(60, 4)
});
break;
case('r') :
{
auto print = [](const RestartOperationResult& result)
case ('r'):
{
if(result.summary == TaskCompletion::SUCCESS)
{
std::cout << "Success, Time: " << result.restartTime.GetMilliseconds() << std::endl;
}
else
{
std::cout << "Failure: " << TaskCompletionToString(result.summary) << std::endl;
}
};
pMaster->Restart(RestartType::COLD, print);
break;
}
case('x'):
auto print = [](const RestartOperationResult & result)
{
if(result.summary == TaskCompletion::SUCCESS)
{
std::cout << "Success, Time: " << result.restartTime.GetMilliseconds() << std::endl;
}
else
{
std::cout << "Failure: " << TaskCompletionToString(result.summary) << std::endl;
}
};
pMaster->Restart(RestartType::COLD, print);
break;
}
case ('x'):
// C++ destructor on DNP3Manager cleans everything up for you
return 0;
case('i'):
case ('i'):
integrityScan.Demand();
break;
case('e'):
case ('e'):
exceptionScan.Demand();
break;
case('c'):
case ('c'):
{
ControlRelayOutputBlock crob(ControlCode::LATCH_ON);
pMaster->SelectAndOperate(crob, 0, PrintingCommandCallback::Get());
break;
}
case ('o'):
{
ControlRelayOutputBlock crob(ControlCode::LATCH_ON);
pMaster->SelectAndOperate(crob, 0, PrintingCommandCallback::Get());
// This is an example of synchronously doing a control operation
AnalogOutputInt16 analogOutInt16(4242);
pMaster->SelectAndOperate(analogOutInt16, 0, PrintingCommandCallback::Get());
break;
}
default:
std::cout << "Unknown action: " << cmd << std::endl;
break;
}
}
while(true);
while (true);

return 0;
}
Expand Down
66 changes: 66 additions & 0 deletions cpp/outstation/AsyncCommand.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/**
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

using namespace opendnp3;

class AsyncCommand {
public:
AsyncCommand(const ControlRelayOutputBlock* crob, const char* id, uint16_t idx) :
id_(id), idx_(idx), crob_(crob), aoInt16_(), aoInt32_(), aoFloat32_(), aoDouble64_() {
}
AsyncCommand(const AnalogOutputInt16* aoInt16, const char* id, uint16_t idx) :
id_(id), idx_(idx), crob_(), aoInt16_(aoInt16), aoInt32_(), aoFloat32_(), aoDouble64_() {
}
AsyncCommand(const AnalogOutputInt32* aoInt32, const char* id, uint16_t idx) :
id_(id), idx_(idx), crob_(), aoInt16_(), aoInt32_(aoInt32), aoFloat32_(), aoDouble64_() {
}
AsyncCommand(const AnalogOutputFloat32* aoFloat32, const char* id, uint16_t idx) :
id_(id), idx_(idx), crob_(), aoInt16_(), aoInt32_(), aoFloat32_(aoFloat32), aoDouble64_() {
}
AsyncCommand(const AnalogOutputDouble64* aoDouble64, const char* id, uint16_t idx) :
id_(id), idx_(idx), crob_(), aoInt16_(), aoInt32_(), aoFloat32_(), aoDouble64_(aoDouble64) {
}

const char* Id() {
return id_;
}

uint16_t Idx() {
return idx_;
}
const ControlRelayOutputBlock* CROB() {
return crob_;
}
const AnalogOutputInt16* AOInt16() {
return aoInt16_;
}
const AnalogOutputInt32* AOInt32() {
return aoInt32_;
}
const AnalogOutputFloat32* AOFloat32() {
return aoFloat32_;
}
const AnalogOutputDouble64* AODouble64() {
return aoDouble64_;
}

private:
const char* id_;
uint16_t idx_;
const ControlRelayOutputBlock* crob_;
const AnalogOutputInt16* aoInt16_;
const AnalogOutputInt32* aoInt32_;
const AnalogOutputFloat32* aoFloat32_;
const AnalogOutputDouble64* aoDouble64_;
};
Loading