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.

9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ testopendnp3
testasiodnp3
testosslcrypto
testsecauth
testoutstation

#demos
master-demo
Expand Down Expand Up @@ -144,3 +145,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>
45 changes: 34 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,20 @@ if(SECAUTH OR DNP3_TLS)

endif()

if(OUTSTATION)
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)

if(Boost_FOUND)
include_directories(${Boost_INCLUDE_DIRS})
#add_executable(progname file1.cxx file2.cxx)
#target_link_libraries(progname ${Boost_LIBRARIES})
endif()
include_directories(./thirdparty/rapidjson/include)
endif()

if(WIN32)

set_property(GLOBAL PROPERTY USE_FOLDERS ON) #allows the creation of solution folders
Expand Down Expand Up @@ -93,17 +109,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 +191,18 @@ 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 asiodnp3 ${PTHREAD} ${Boost_LIBRARIES})
# target_link_libraries (outstation LINK_PUBLIC asiodnp3 ${PTHREAD})
# target_link_libraries(outstation ${Boost_LIBRARIES})

# set_target_properties(outstation PROPERTIES FOLDER demos)

endif()

if(DEMO)

# ----- master demo executable -----
Expand Down Expand Up @@ -279,6 +298,10 @@ 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})

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: 36 additions & 39 deletions cpp/examples/master/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@ using namespace asiopal;
using namespace asiodnp3;
using namespace opendnp3;

int main(int argc, char* argv[])
{
int main(int argc, char* argv[]) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are a bunch of these code-style changes here, are they legit? Does the parent project have a style guide?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is a code formatting command here, although it touches a bunch of files already in the repository too. I'll run it on the shared code so at least that part will be formatted correctly.
https://github.com/automatak/dnp3-guide/blob/master/mkdoc/docs/contributing/tasks.md


// Specify what log levels to use. NORMAL is warning and above
// You can add all the comms logging by uncommenting below
Expand Down Expand Up @@ -74,13 +73,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 @@ -91,8 +88,7 @@ int main(int argc, char* argv[])
// Enable the master. This will start communications.
pMaster->Enable();

do
{
do {
std::cout << "Enter a command" << std::endl;
std::cout << "x - exits program" << std::endl;
std::cout << "a - performs and ad-hoc range scan" << std::endl;
Expand All @@ -104,53 +100,54 @@ int main(int argc, char* argv[])

char cmd;
std::cin >> cmd;
switch(cmd)
{
case('a') :
switch (cmd) {
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') :
{
case ('r'): {
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;
}
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'):
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'):
{
ControlRelayOutputBlock crob(ControlCode::LATCH_ON);
pMaster->SelectAndOperate(crob, 0, PrintingCommandCallback::Get());
break;
}
case ('c'): {
ControlRelayOutputBlock crob(ControlCode::LATCH_ON);
pMaster->SelectAndOperate(crob, 0, PrintingCommandCallback::Get());
break;
}
case ('o'): {
// 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
61 changes: 61 additions & 0 deletions cpp/outstation/AsyncCommand.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/**
* 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, uint16_t idx) :
idx_(idx), crob_(crob), aoInt16_(), aoInt32_(), aoFloat32_(), aoDouble64_() {
}
AsyncCommand(const AnalogOutputInt16* aoInt16, uint16_t idx) :
idx_(idx), crob_(), aoInt16_(aoInt16), aoInt32_(), aoFloat32_(), aoDouble64_() {
}
AsyncCommand(const AnalogOutputInt32* aoInt32, uint16_t idx) :
idx_(idx), crob_(), aoInt16_(), aoInt32_(aoInt32), aoFloat32_(), aoDouble64_() {
}
AsyncCommand(const AnalogOutputFloat32* aoFloat32, uint16_t idx) :
idx_(idx), crob_(), aoInt16_(), aoInt32_(), aoFloat32_(aoFloat32), aoDouble64_() {
}
AsyncCommand(const AnalogOutputDouble64* aoDouble64, uint16_t idx) :
idx_(idx), crob_(), aoInt16_(), aoInt32_(), aoFloat32_(), aoDouble64_(aoDouble64) {
}

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:
uint16_t idx_;
const ControlRelayOutputBlock* crob_;
const AnalogOutputInt16* aoInt16_;
const AnalogOutputInt32* aoInt32_;
const AnalogOutputFloat32* aoFloat32_;
const AnalogOutputDouble64* aoDouble64_;
};
Loading