Setting up Half Duplex Operation

127 views
Skip to first unread message

ben...@benegon.com

unread,
Jul 11, 2010, 12:34:55 PM7/11/10
to open...@googlegroups.com
Hi,
I am really excited to see an open source DNP implementation. For a
test program I was a looking to make a loop to read counter values
from a device. I saw the SlaveDemo and its close to what I want but I
need to use half-duplex RS485 not tcp. I also need to integrate it
with a GUI so I was wondering if I could call the StackManager to act
rather than yield to its Run() command.

-Dave

Adam Crain

unread,
Jul 11, 2010, 1:17:10 PM7/11/10
to open...@googlegroups.com
Hi Dave,

The StackManager can start up both slaves and masters. The DemoSlave isn't a bad place to start, but the interfaces are slightly different for an outstation/master.

Instead of calling AddTCPServer(..), add a serial port using AddSerial(..). That's where you'll configure baud, rate, etc. There's no direct control for 485, as there is no standard way of doing this. I assume your hardware is fixed on 485 or you have another way of configuring this.

Now that you have a named port, you call AddMaster(..). The parameter MasterStackConfig controls how the master will behave. Check out the documentation for this in the code or on our Hudson server:

https://dev.greenenergycorp.com:8888/hudson/job/DNP3_Docs/doxygen/?

If you call Start() function instead of Run(), the stack will run in a background thread so that you can go about setting up your UI, etc and retain control of your parent thread. Via the configuration you can set it up to periodically poll for your counters. Does your device support class polling? If so, that's probably the best way to go on a 1/2 duplex link.

The TestSet also shows how to configure a master, but there's a lot more going on there then the demo Slave. It would probably be beneficial to have an demo master as well.

regards,
Adam

winmail.dat

Adam Crain

unread,
Jul 11, 2010, 1:22:50 PM7/11/10
to open-dnp3
I forgot to mention, that you might want to try using the TestSet to
communicate with your outstation first. The XML configuration is well
documented and you'll get a good idea of how the master behaves in
response to different configurations. There's a docx in the TestSet
folder or it will install in the windows program group if you use the
windows installer.

-Adam

Sam Hendley

unread,
Jul 11, 2010, 1:31:25 PM7/11/10
to open...@googlegroups.com
EDIT: Adam beat me to it but someone else may find this useful so I'm posting it anyways.

Hi Dave, glad to see our project peaked your interest. DNP can be used with either full or half duplex regardless of physical layer because the communication can be totally controlled by the master. The key is making sure that the device (slave) doesn't default to sending unsolicited data to the master. Most devices don't default to sending unsolicted data but some relays and meters may be configured to start up like that, if you see CRC error messages in the logs that may be a telltale of unsolicted data sent by the device. Using half duplex RS485 shouldn't be a problem (in fact we have done it many times) but it does depend on how you configure the serial port. On some of the platforms we have developed on it was necessary to make some system calls on the serial port object to enable the RS485 support; on others it was configured by dip switch and jumpers. You'll need to figure out how your system operates, if you need to get access to the underlying serial port object ASIO provides functions to get at the native file objects, we could point you in the right direction.

You can use the testset application we provide to talk to the device by editing the XML to use the serial port. The sample  configuration has an entry for serial connections but it is disabled by default.

Alter the first line; replacing PhysicalLayer="tcpclient" with PhysicalLayer="serial" and change the Device="COM1" to point to your RS485 serial port (should be something like /dev/ttyAM0 on Linux). That should allow you talk to a device using DNP over an RS485 connection, thats probably the fastest way to verify the dnp connection.

Adam covered the basics of using the StackManager in a GUI, one thing to note is that the data coming out of the stack on the IDataObserver interface will be on a different thread than the GUI thread so some care must be taken to marshal the data onto the GUI thread.

Good Luck!

Sam

ben...@benegon.com

unread,
Jul 11, 2010, 1:45:04 PM7/11/10
to open...@googlegroups.com, Sam Hendley
My experience with a commercial stack was that its half duplex support
was lacking in that the stack's built in link integrity polling would
transmit while I was receiving data. Since the stack handled the
transmit queue, the only way to handle this was to disable link
integrity polling
In your stack, how do I make sure that transmits don't occur until
after receives are complete?

Adam Crain

unread,
Jul 11, 2010, 2:08:09 PM7/11/10
to open...@googlegroups.com
Link integrity polling is a seldom used feature, this being one of the reasons why. We choose not to implement it because the functionality it provides is largely redundant with other features. Our link layer responds to them, but doesn't actively send link status requests.

The master will stay 100% quiescent with respect to the physical layer until an app layer respond times out. You shouldn't have any trouble using it with half duplex. We've run half duplex serial links with it in the past.

-Adam


-----Original Message-----
From: open...@googlegroups.com on behalf of ben...@benegon.com

Sent: Sun 7/11/2010 1:47 PM
To: open...@googlegroups.com; Sam Hendley
Subject: Re: [open-dnp3] Re: Setting up Half Duplex Operation

My experience with a commercial stack was that its half duplex support
was lacking in that the stack's built in link integrity polling would
transmit while I was receiving data. Since the stack handled the
transmit queue, the only way to handle this was to disable link
integrity polling
In your stack, how do I make sure that transmits don't occur until
after receives are complete?

winmail.dat

ben...@benegon.com

unread,
Jul 12, 2010, 9:09:45 AM7/12/10
to open...@googlegroups.com
The class poll interval is not cutting it for me. I need to compose a
specific READ to get counter values, and I will also need to WRITE
some counters and set analog deadbands.

Is there a "proper" way to do this with the AsyncMaster or do I have
to add a function to AsyncMaster to do it?

-Dave

Adam Crain

unread,
Jul 12, 2010, 9:11:57 AM7/12/10
to open...@googlegroups.com
Hi Dave,

1) The master doesn't currently support custom scans. We'd love for you to do this and contribute it back to the project.

2) I don't know of a way to write counters in DNP3. Does your device map an analog output to a counter value?

3) The master currently doesn't setting analog deadbands. Ditto from 1).


Both 1) and 3) would be fairly straightforward to implement.

-Adam


-----Original Message-----
From: open...@googlegroups.com on behalf of ben...@benegon.com

Sent: Mon 7/12/2010 9:11 AM
To: open...@googlegroups.com
Subject: RE: [open-dnp3] Setting up Half Duplex Operation

The class poll interval is not cutting it for me. I need to compose a
specific READ to get counter values, and I will also need to WRITE
some counters and set analog deadbands.

Is there a "proper" way to do this with the AsyncMaster or do I have
to add a function to AsyncMaster to do it?

-Dave

winmail.dat

ben...@benegon.com

unread,
Jul 12, 2010, 9:42:54 AM7/12/10
to open...@googlegroups.com
Quoting Adam Crain <adam....@greenenergycorp.com>:

> Hi Dave,
>


> 1) The master doesn't currently support custom scans. We'd love for
> you to do this and contribute it back to the project.

OK. I don't really know your architecture but it seems like I would

-Have the user compose a custom APDU
-Hand that APDU and task handler to the AsyncMaster
-AsyncMaster hands those of to a SendAPDU() of its current state
-AMS_Idle is the only AMS_Base descendant to have a working SendAPDU

>
> 2) I don't know of a way to write counters in DNP3. Does your device
> map an analog output to a counter value?

This is specific to a certain product. Welcome to the real world of DNP.

>
> 3) The master currently doesn't setting analog deadbands. Ditto from 1).
>

I'll just use a custom APDU for that now.

Adam Crain

unread,
Jul 12, 2010, 10:04:23 AM7/12/10
to open...@googlegroups.com
Hi Dave,

1) the architecture encapsulates the APDU, attempting to minimize the number of externally exposed classes, especially complicated ones that introduce dependencies. The preferred/cleanest way to do this would be to extend the scans available to master in MasterConfig to be more generic to meet your application's needs. I.E. making the scans available take specific group/var and ranges.

You could add a more generic function to pass in an APDU + verification function but I would rather see the configurable scans as it most reusable to everyone. It's Apache 2.0, however, so do as you please!

2) Yes, DNP3 has lots of non-standard extensions, we'll consider non-standard additions to the mainline on a case-by-case basis. Out of curiosity, then, your slave then accept APDU's with Function == WRITE and object headers with counters types Group 20, Var X? What vendor/model? What masters that you have worked with support writing counters?

thanks,
Adam


-----Original Message-----
From: open...@googlegroups.com on behalf of ben...@benegon.com
Sent: Mon 7/12/2010 9:43 AM
To: open...@googlegroups.com
Subject: RE: [open-dnp3] Setting up Half Duplex Operation

Quoting Adam Crain <adam....@greenenergycorp.com>:

> Hi Dave,
>


> 1) The master doesn't currently support custom scans. We'd love for
> you to do this and contribute it back to the project.

OK. I don't really know your architecture but it seems like I would

-Have the user compose a custom APDU
-Hand that APDU and task handler to the AsyncMaster
-AsyncMaster hands those of to a SendAPDU() of its current state
-AMS_Idle is the only AMS_Base descendant to have a working SendAPDU

>


> 2) I don't know of a way to write counters in DNP3. Does your device
> map an analog output to a counter value?

This is specific to a certain product. Welcome to the real world of DNP.

>


> 3) The master currently doesn't setting analog deadbands. Ditto from 1).
>

I'll just use a custom APDU for that now.

>

winmail.dat

ben...@benegon.com

unread,
Jul 12, 2010, 3:13:52 PM7/12/10
to open...@googlegroups.com, Adam Crain
Adam,
I took another look at this and I think I am on the wrong track.
Even with the modifications to the Master, there is still a generic
ICommandAcceptor interface. However, what I am doing is very specific
to a single application. The Master abstraction is really getting in
the way because the only I have to communicate with it is through the
ICommandAcceptor. I really do not want to bubble a few specific
commands through all these layers of code. I also don't understand why
I need to talk to an interface in APL to do DNP stuff.
I like the APDU for composing commands and would just like to send
them to the destination slave address. I like the asynchronous part
but would be willing to write the code synchronously as well.

-Do I still need an AsyncStackManager to do this?
-Is there some test code that does this?

Thanks,
Dave

Adam Crain

unread,
Jul 12, 2010, 4:37:23 PM7/12/10
to ben...@benegon.com, open...@googlegroups.com

Dave,

I'll try to clarify why it's implemented this way. We have a modbus codebase as well, and those interfaces/abstractions in APL (Async Protocol Library) were meant to serve as a superset of what you needed to represent the interfaces for index-based protocols like DNP3, modbus, telegyr, ICCP, etc.

In general, you may find our docs on our CI serer helpful:

https://dev.greenenergycorp.com:8888/hudson/job/DNP3_Docs/doxygen/?

The ICommandAcceptor is the only *dynamic*  means of communication, but there's a whole config structure that could be modified to tell the master how to behave. This was written this way so that re-usability would be favored over custom tasks. That said, it's clearly getting in your way at the moment.

You could write your own master, and tie in directly to the application layer, but you'd be doing just as much work if not more work than modifying the current master's task handling and telling it what to do via new configuration information. You could add descriptors for how to do counter writes, deadbands setpoints, and custom polls to this file:

http://github.com/greenenergycorp/dnp3/blob/master/DNP3/MasterConfig.h

And then react to those configurations in AsyncMaster.

If you really wanted to write another master, you can start by looking at the interactions between these classes:

http://github.com/greenenergycorp/dnp3/blob/master/DNP3/AsyncStack.h
http://github.com/greenenergycorp/dnp3/blob/master/DNP3/AsyncLinkLayerRouter.h
http://github.com/greenenergycorp/dnp3/blob/master/APL/PhysicalLayerManager.h

If you can get your brain wrapper around how these three classes work together, you could write your own master and send APDU's directly. However, it will still have to be based on an async model where the event flow is driven by calls to boost::io_service::run().  This takes a bit of getting used to... but it's the way that we can get our frontend to talk to hundreds of endpoints without lots of nasty context switching.

If you want to understand how the master/outstation interacts with the application layer, have a look at the interfaces defined in:

http://github.com/greenenergycorp/dnp3/blob/master/DNP3/AsyncAppInterfaces.h

and the tests defined in:

http://github.com/greenenergycorp/dnp3/blob/master/DNP3Test/TestAsyncAppLayer.cpp

-Adam




-----Original Message-----
From: ben...@benegon.com [mailto:ben...@benegon.com]
Sent: Mon 7/12/2010 3:18 PM
To: open...@googlegroups.com; Adam Crain
Subject: RE: [open-dnp3] Setting up Half Duplex Operation

Adam,
   I took another look at this and I think I am on the wrong track. 
Even with the modifications to the Master, there is still a generic 
ICommandAcceptor interface. However, what I am doing is very specific 
to a single application. The Master abstraction is really getting in 
the way because the only I have to communicate with it is through the 
ICommandAcceptor. I really do not want to bubble a few specific 
commands through all these layers of code. I also don't understand why 
I need to talk to an interface in APL to do DNP stuff.
   I like the APDU for composing commands and would just like to send 
them to the destination slave address. I like the asynchronous part 
but would be willing to write the code synchronously as well.

-Do I still need an AsyncStackManager to do this?
-Is there some test code that does this?

Thanks,
Dave


ben...@benegon.com

unread,
Jul 14, 2010, 12:18:32 PM7/14/10
to open...@googlegroups.com
Quoting Adam Crain <adam....@greenenergycorp.com>:

> The ICommandAcceptor is the only *dynamic* means of communication,
> but there's a whole config structure that could be modified to tell
> the master how to behave. This was written this way so that
> re-usability would be favored over custom tasks. That said, it's
> clearly getting in your way at the moment.

I have to say I ended up not using your library. Having used DNP
from a high level with another toolkit, it was easier for me to
understand the link, transport, and application protocol and hack
something out for my purposes. The data marshalling back and forth is
about 200-300 lines of code. The frustrating thing is I know you do
this already but it was not easy to use ONLY that part of the code.
I think your library could be a great starting point for a reference
implementation or maybe a big box SCADA system. However, I think for
developer use it needs improvement for the following areas:

-Embedded systems: There are many programmers with years of embedded
experience who are used to C and assembler. In many cases they are
being asked to write software that runs on top of an OS. They will run
screaming from boost.asio, ruby, java, and the jungle of CamelCased
design patterns that dominate your code. The only reason I didn't do
the same was because I'm not far out of a good computer science
school. If you don't provide a simple, synchronous C-like C++
interface you will be shutting out many senior engineers from this
product.

-Smaller data concentrators: Mostly similar to embedded systems. Don't
really need to manage thousands of connections; at most 5-6 dozen.

-Test Harness tools: Most test harness tools will let you do things
like Write Counters straight out of the box. That's because the give
you very fine grained control over composing DNP requests. NEVER force
the user to hack specific functions into generic interfaces; generic
interfaces promote reusability, but reusability should be optional,
not required.

I would like to see functions for stateful composition of packets and
marshalling data; leave it up to the programmer to send that data over
a fd. That way I can use your library to make product specific custom
tools.
Perhaps you modularize your top layers as well so I don't need to
use your IO framework to use them. I could just feed the data packets
to those layers and they could call me back.

Thanks,
-Dave

Sam Hendley

unread,
Jul 15, 2010, 11:05:18 AM7/15/10
to open...@googlegroups.com
On Wed, Jul 14, 2010 at 12:18 PM, <ben...@benegon.com> wrote:
Quoting Adam Crain <adam....@greenenergycorp.com>:

The ICommandAcceptor is the only *dynamic*  means of communication,  but there's a whole config structure that could be modified to tell  the master how to behave. This was written this way so that  re-usability would be favored over custom tasks. That said, it's  clearly getting in your way at the moment.

 I have to say I ended up not using your library. Having used DNP from a high level with another toolkit, it was easier for me to understand the link, transport, and application protocol and hack something out for my purposes.

Dave-
We're sorry to hear that you didn't end up using our project. We have been developing this project primarily as a library for DNP communication for projects that just need the data, don't really care that its DNP. What I think you are looking for is a framework for building custom DNP masters. While this is certainly possible using using our project, it hasn't been our focus and the highest level APIs reflect that. The primary API's we have exposed are the right level of abstraction for 90% of applications that need to communicate with DNP devices; commands in, data out. That is what has made it so easy to wrap for use in other applications and languages. 

As Adam described in his last email it is more than possible to use the stack directly without using the AsyncMaster, but we haven't provided the examples and sample code to demonstrate writing custom masters. We also know that our master is not fully feature complete, it is not possible to configure it to do all types of behaviors or scans one might need in some situations but it has been sufficient for our purposes up until now. We are hoping that the community can help us determine where to direct our efforts and what features we may need.
 
The data marshalling back and forth is about 200-300 lines of code. The frustrating thing is I know you do this already but it was not easy to use ONLY that part of the code. 
 I think your library could be a great starting point for a reference implementation or maybe a big box SCADA system. However, I think for developer use it needs improvement for the following areas:

-Embedded systems: There are many programmers with years of embedded experience who are used to C and assembler. In many cases they are being asked to write software that runs on top of an OS. They will run screaming from boost.asio, ruby, java, and the jungle of CamelCased design patterns that dominate your code. The only reason I didn't do the same was because I'm not far out of a good computer science school. If you don't provide a simple, synchronous C-like C++ interface you will be shutting out many senior engineers from this product.

This project was never intended to be a used on embedded micro-controller systems, instead we have tried to produce a modern, maintainable and scalable solution to be used on standard hardware/OS's. We are going to update the description pages to make this more clear. However, I can see where you are coming from here, this code is very different from the majority of protocol stack implementations used in the industry. We developed this with a small team and tried to take advantage of world class libraries and tools rather than reinvent the wheel where we could. Boost ASIO is an incredible library that provides blazingly fast IO and lets us scale up to thousands of connections on very limited systems. The asynchronous reactor pattern allowed us to develop an entirely event driven stack that makes if fast and incredibly simple to test. Some people may be scared off by the design patterns and asynchronous nature of the code base and thats unfortunate but we have seen the alternatives and we believe the trade-offs are well worth it. We also made use of many of the boost libraries like bind and memory pointers and they have made the code base infinitely more understandable and pleasurable to work with.

-Smaller data concentrators: Mostly similar to embedded systems. Don't really need to manage thousands of connections; at most 5-6 dozen.
-Test Harness tools: Most test harness tools will let you do things like Write Counters straight out of the box. That's because the give you very fine grained control over composing DNP requests. NEVER force the user to hack specific functions into generic interfaces; generic interfaces promote reusability, but reusability should be optional, not required.
 
We would love to have more functionality in the testset but again, we are not making a testset 'product'. It is primarily a tool for verifying connections and diagnosing communication errors and an example application using the Async master. We've been talking to some SCADA engineers and trying to compile a list of "standard scans" which we could add to the master config in the future, we'd welcome your input.
 
I would like to see functions for stateful composition of packets and marshalling data; leave it up to the programmer to send that data over a fd. That way I can use your library to make product specific custom tools.
 Perhaps you modularize your top layers as well so I don't need to use your IO framework to use them. I could just feed the data packets to those layers and they could call me back.

As Adam described, it is possible to use the stack without the ASIO IO physical layers. You could even write a few shim classes and use the stack in a more synchronous fashion if necessary. It requires a bit of book keeping and a few extra threads, but is possible. In general I would say it would be more valuable to get your head around the async behavior, once you grok it alot of problems actually become much easier to solve.

Thanks for looking at this project, your perspective has made us look at the design in a slightly different light and we've seen a few things we'd like to change in the future. 

Sam
Reply all
Reply to author
Forward
0 new messages