apache / plc4x

PLC4X The Industrial IoT adapter
https://plc4x.apache.org/
Apache License 2.0
1.26k stars 400 forks source link

[Feature-Request][S7] Reading long Int Array (Optimizer) #605

Open ottlukas opened 1 year ago

ottlukas commented 1 year ago

Dear Chris,

I need to report an another bug. As you know I am trying to read a very complex Data Bloc from a S7-1200, in the future I will try with a 1500. A picture of one of this block in in the attached picture. I found a problem which actually is similar to the String problem I reported in PLC4X-240, in reading long array of Int. The software running in the PLC as a component which actually samples an analog value a store the data in long Array of Integer or Real. An example is:


PLC_CellValue_2[400]='%DB2:928.0:INT[400]'

or


PLC_SpeedNotSafety[400]='%DB2:6542.0:REAL[400]'

Reading such a long array of values is not possible because the request on the wire is for a too huge payload (probably this is the same problem we had with the string). I have attached the wireshark capture for you.

I did the comparison with the 0.6.0 version of the library and the array is correctly read. On the wire I see 3 read of 110 Integer and a last one of 70 which are my 400 Integer. As for this reading I have captured the wireshark.

just to complete the big picture my final target is to read a big DB. In this complex scenario there a similar problem that I think is a data request size problem too. If I try to read a list of variables like this one:


PLC_ReportColpoDateLast='%DB2:0.0:DATE_AND_TIME'
PLC_@timestamp='%DB2:12.0:DATE_AND_TIME'
PLC_ReportColpoDateLastID='%DB2:24.0:DINT'
PLC_ReportColpoDateID='%DB2:28.0:DINT'
PLC_RichiestaCurva='%DB2:32.0:INT'
PLC_TrasferimentoCurva='%DB2:34.0:BOOL'
PLC_ArchiveReport='%DB2:36.0:BOOL'
PLC_DeleteReport='%DB2:36.1:BOOL'
PLC_Report='%DB2:36.2:BOOL'
PLC_Enable='%DB2:36.3:BOOL'
PLC_SetCelloffset='%DB2:36.4:BOOL'
PLC_ResCelloffset='%DB2:36.5:BOOL'
PLC_IDX='%DB2:38.0:INT'
PLC_KW='%DB2:40.0:BOOL'
PLC_TemCen='%DB2:42.0:REAL'
PLC_TemBiella='%DB2:46.0:REAL'
PLC_TemBroDx='%DB2:50.0:REAL'
PLC_TemBroSx='%DB2:54.0:REAL'
PLC_PreCen='%DB2:58.0:REAL'
PLC_PreFreno='%DB2:62.0:REAL'
PLC_PreCil='%DB2:66.0:REAL'
PLC_EncPosAct='%DB2:70.0:REAL'
PLC_EncPosActSafety='%DB2:74.0:REAL'
PLC_EncSpeedSafety='%DB2:78.0:REAL'
PLC_EncSpeed='%DB2:82.0:REAL'
PLC_CellValue[5]='%DB2:86.0:INT[5]'
PLC_CellValueOffset[5]='%DB2:96.0:INT[5]'
PLC_N_TotPezzi='%DB2:106.0:DINT'
PLC_N_TotColpi='%DB2:110.0:DINT'
PLC_KW_Max='%DB2:114.0:INT'
PLC_CellValueMax[5]='%DB2:116.0:INT[5]'
PLC_CellValue_1[2]='%DB2:126.0:INT[2]'
PLC_CellValue_2[400]='%DB2:928.0:INT[100]'

The error I find on the wire is the same. Pleas note that in the list of variables there are no array of 400 samples but, I suppose, that the sum of all the request fire the same bug about the request of more than 240 byte length. I have attached a wireshark capture of this scenario too.

Hope this analysis could help to find an universal solution for this problem.

Regards, Stefano

P.S. As usual I am using the HellpPlc4x code and the latest compiled version of the 0.8.0 library.

Imported from Jira PLC4X-241. Original Jira may contain additional context. Reported by: fox_pluto.

dremsol commented 1 year ago

Confirming this bug is still present in v0.10.0

chrisdutz commented 1 year ago

From the REAL[400] I can see that this one tag would consume more space than fits in one S7 packet for most PLC models. I did implement the query optimizer to automatically split the request into multiple ones, however I haven't implemented a real query rewriting. So if you had for example tried reading 400 individual REAL fields (Or a number of smaller arrays ... where each fits into one packet) the driver would have split it up into multiple requests. However this "rewrite" logic we always wanted to handle in a generic way to use in all drivers, but the volunteers that prommised to do so never did.

dremsol commented 1 year ago

Actually I tried with an array of WORD[400]. Splitting the readRequestBuilder into 4 arrays of WORD[100] works perfectly fine.

PlcReadRequest.Builder builder = plcConnection.readRequestBuilder();
builder.addItem("value-alarm1", "%DB1:0:WORD[100]");
builder.addItem("value-alarm2", "%DB1:64:WORD[100]");
builder.addItem("value-alarm3", "%DB1:128:WORD[100]");

So I'm doing manually what the spi.optimizer.SingleTagOptimizer should do automatically. If I understand correctly this needs to be implemented on the S7 driver level just as has been done for the modbus driver?

chrisdutz commented 1 year ago

Well I don't think you'll like the SingleTagOptimizer as that sort of is the opposite of an optimizer. It takes a multi-item request and makes single item requests out of that and then merges the results back together. Even if it's the fool-proof thing to do, it's by far the least optimal one.

In your above case, when using an S7-1200 the result will probably be 4 requests as the max PDU size allows a payload of something around 240 bytes. If you were using an s7-1500 or 400 you might even get all items in one request as their PDU sizes is bigger.

Problem is ... If we wrote an optimizer for only S7, then we'll run into the same problem elsewhere and we'd be writing the same thing over and over again ... if you feel willing to work on this, I would be happy to assist you. However right now I don't have the capacity to work on this.

dremsol commented 1 year ago

So ideally, we would have an optimizer which works for all drivers, devices and their respective PDU sizes. Indeed, that is quite a bit of work. Although I'm interested in working on the project, I'm not sure if I'm capable of pulling it off. It requires to study the codebase in detail and bump my Java skills. Would be great if there is some information about how the project is structured.