s7netplus: Can't migrate to lattest version. Need an explanation.
Hello guys, untill now we had 0.1.8 version implemented in the project. And it worked fairly fine. It is time to make another application and we came accross with some challenges. Early versions allowed to read multiple DB as per example code below.
ReadMethod()
{
DB1 db1 = new DB1();
plc.ReadClass(db1, 1); // reading DB1
value0 = db1.varReal1;
value1 = db1.varInt1;
value2 = db1.varReal2;
value3 = db1.varInt2;
value4 = db1.varReal3;
value5 = db1.varInt3;
value6 = db1.varReal4;
value7 = db1.varInt4;
value8 = db1.varReal5;
value9 = db1.varInt5;
value10 = db1.varReal6;
//DB2 db2 = new DB2();
//plc.ReadClass(db2, 2); // reading DB2
//db2_value1 = db2.Gear_0; // Real
//db2_value2 = db2.Gear_1; // Dint
//db2_value3 = db2.Gear_2; // Int
//db2_value4 = db2.Gear_3; // Bool
//db2_value5 = db2.Gear_4; // Bool
//db2_value6 = db2.Gear_5; // Bool
//db2_value7 = db2.Gear_6; // Bool
//db2_value8 = db2.Gear_7; // Bool
//db2_value9 = db2.Gear_8; // Bool
//db2_value10 = db2.Gear_9; // Bool
//db2_value11 = db2.Gear_10; // Bool
}
Now, it seems not a workable way to read multiple data blocks. Or? Could someone help us to migrate to lattest version? Basically the question is about a way of reading multiple data blocks.
Thanks in advance!
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Comments: 39 (22 by maintainers)
Good morning @all
maybe I can provide a little testprogram which uses lib-version 0.8.1 and a timer to read and write a) multiple variables using a item list and to read b) a class within another DB inside the plc. The plc is a S7-1515-2 PN which is in slot 1. It is running since nearly 6:30 o´clock this morning without any exceptions. Parallel to this little program my main logging application is also running and reads far more values from this plc but with lib-version 0.7.xx
The test program is a console application.
Btw I am using https://github.com/StephenCleary/AsyncEx for async locking of S7NetPlus. Works like a charm, and very easy to use with using/IDisposable.
OK, so there’s 2 things that made me reconsider concurrent requests (which would also handle concurrency in general):
As for the first point, it’s pretty obvious, it would make usage of the library easier if it could handle concurrency internally. The second point is a different story. The past few days I’ve worked on implementing concurrent requests for Sally7. Today I performed my first tests and exclusive vs concurrent requests made only a minor difference, concurrent requests were something like 3% faster. However, that was in a lab environment, i.e. the PLC and PC were probably (I was testing remotely, so I’m not sure) separated by one or two switches only. Also, the PLC only had a single datablock available, with a single variable. I couldn’t change any of that, so I just put the same variable in a read request multiple times (and also tried with the single variable only).
So then I thought, let’s test this at a customer site, with a server room, large network etc. I was reading a single
short[10]array and there the concurrent reads were over twice as fast! Probably this also was a faster PLC, because the total time was reduced as well, but still this is a huge improvement.Long story short, I figured how to do concurrent requests with Sally7, which works pretty well. I still have to cleanup the code and verify some things, but from initial testing it’s looking really good. Now the thing is that the API surface of Sally7 is waaay smaller than S7NetPlus. Also, Sally7 only has an async api (because you know, network communication is inherently async), which is well suited for handling concurrency (because you can await available slots, freeing up threads that would otherwise be block by a sync operation). All in all I’m not sure if there’s any better way than implementing all of this async in S7NetPlus as well, with perhaps a wrapper that exposes the sync methods using
.GetAwaiter().GetResult(), but at least that’s still an option.I’m not sure yet when (or honestly, if, I’m still very time-constrained) I can add this to S7NetPlus, but at least if I want to take a stab at it the plan’s already laid out.
Do you have only this single timer instance? Or do you create this per DB you’re reading or something similar?
I think this could provide some insight, but I’ll try to explain it really short. Let’s assume you’re reading data from the PLC and reading takes 1 second (I know it’s a lot faster, but the scale is not important for the example). Now let’s say you have two threads that need to read data. If you start reading DB1 at T0 the connection can only be used to wait for the response for DB1, which takes 1 second. If anywhere within that second the read for DB2 starts, you’re creating concurrent access to the PLC class. When that happens there will be two threads contending to receive responses for their requests, which the library doesn’t handle in it’s current form. A synchronization primitive can be used to keep the read for DB2 waiting, until it has been given the clear when the DB1 read completes. There are many approaches to solving this and it’s hard to decide for someone else what would be a good fit in their project, especially when you can’t see the project.
On the other hand, if you only use a single timer (
System.Timers.Timer, because this doesn’t apply to all other timers) to read/write data you should normally not have to deal with concurrency, becauseSystem.Timers.Timersynchronizes it’s execution.Yes, with 250ms interval that’s indeed hard to say… You could perhaps apply logging to get more exact figures.
There are changes, but my best guess is that the failures are handled differently, so maybe there always were issues that went unnoticed because they had different impact. I can’t say, but I’m very interested in how this turns out.
I have no reason to doubt you. It’s strange that it works every time, that’s definitely more than a coincidence. However assuming it’s an issue with concurrency then switching the libraries might affect first execution of the application with regards to caching and optimization, I don’t think we can get any better than this educated guess… (Or perhaps we can when we figure out what’s going on).
I’d be willing to provide help (free of charge) in a way that suits your employer, for instance using remote assistance software like TeamViewer or by means of an NDA to prevent me from ‘stealing’ your code.
I’m also interested in what happens when you perform the same actions in a simple command line application if you just do reads and a
Thread.Sleep(250)to mimic the behavior of your UI. Let me know if you can replicate this in a sample that you can share though.I guess all people need to do here is to ask for help and provide information when requested to be helped. We are missing a proper sample so that people can take a look at that, it’s something I want to add when I have time…
@mycroes,
it is 4.5.2 (btw, 0.8.1 is also targetting 4.5.2 by default)
WPF App (.Net Framework)
Yes I am. It’s System Timer.
I created a class library and connected it to solution. This class library has a class where I make a connection to plc.
This is quite big application, so my answer -yes. Yet while troubleshooting others are disabled.
An event subscribed to a timer, then it is being broadcasted to a method which is located in VM (used mvvm pattern). At this method values of fields are being assigned to VM properties. Further go bindings and so on.
0.1.8 has errorcode, I used that. 0.8.1 doesn’t have that. So right now is nothing.
seems the time between first “living number” read/change and the last “living number” read/change is about 3 sec. it may say it has constant interval before break.
I am plc programmer, have some knowledge about XAML, C#, MVVM pattern. Consider me as a beginner.