Splitting requests using a schema shouldn't really be necessary though, as
you still need to define the individual tags within the PLC4X Read request.

So you could define each read request as one tag, each tag wouldn't be more
than the 125 limit. Then within the optimizer it would build larger
requests made up of these read requests. This way there's no chance of
splitting individual tags into more than 1 request, but you get the benefit
of merging requests into one larger one.

An example below, this would then be grouped in the optimizer logic into 3
read requests, the first request would contain values 1 and 2, the second
just value 3 and the third only value 4.

PlcReadRequest.Builder builder = plcConnection.readRequestBuilder();
builder.addItem("value-1", "400001");
builder.addItem("value-2", "400002");
builder.addItem("value-3", "400010[10]");
builder.addItem("value-4", "400020[120]");
PlcReadRequest readRequest = builder.build();


On Mon, Jan 16, 2023 at 9:21 AM Niels Basjes <[email protected]> wrote:

> Hi,
>
> Yes this is exactly my idea as well.
> Splitting a request for >125 registers into multiple requests cannot be
> done in a generic reliable way.
> If you know the schema (i.e. meaning of the registers) then you can combine
> requests with multiple logical values into blocks of modbus registers that
> stay within the 125 register limit.
>
> Which implies the need for a (generic) way of defining logical values and
> the modbus registers from which they can be read (with all kinds of
> constraints about reading them).
> I would call this a modbus schema definition which can then be used to
> calculate the actual read/write operations.
>
> The effect would be that for every type of device a schema definition is to
> be created from which a client can be created/generated.
>
> Niels
>
>
>
>
>
> On Mon, Jan 16, 2023 at 8:50 AM Ben Hutcheson <[email protected]>
> wrote:
>
> > Hi Niels,
> >
> > As Łukasz pointed out, there are a thousand different combinations of how
> > Modbus requests can be arranged. I'm not sure there's a generic schema
> that
> > can be used to define it though.
> >
> > You talked originally about splitting large reads (>125 registers) up
> into
> > smaller registers. This logic would live in a class that implements the
> > BaseOptimizer. This is then defined within the ModbusTCPDriver class, we
> > are just using the SingleTagOptimizer for Modbus at the moment.
> >
> > If I were to implement this I would probably firstly try and combine tags
> > that are adjacent into one request until we either encounter a break in
> the
> > requested area or approach the limit of ~125 registers. This way it is
> > guaranteed that requests for individual requests are not broken into
> > smaller requests.
> >
> > Kind Regards
> >
> > Ben
> >
> >
> >
> >
> >
> > On Sun, Jan 15, 2023 at 6:58 PM Niels Basjes <[email protected]> wrote:
> >
> > > Hi Łukasz,
> > >
> > > At this point I tend towards the need for a tool that allows one to
> > define
> > > the schema of a modbus device with all available values and code to
> > convert
> > > them into usable stuff (like in java an actual String or Double).
> > > So far it seems this needs indeed flags indicating which values can and
> > > must be read combined (like the sync block in SunSpec).
> > > Then based on this a request for a set of functional values is
> converted
> > > into a set of modbus requests that follow these defined rules.
> > >
> > > Rules about an after connection delay and maximum requests per second
> > seem
> > > like something that should be at the modbus level (i.e. part of plc4x).
> > >
> > > Is there an existing project that does something like this?
> > >
> > > Niels
> > >
> > > On Sun, Jan 15, 2023 at 5:22 PM Łukasz Dywicki <[email protected]>
> > > wrote:
> > >
> > > > I am really glad you are moving it forward and fighting it!
> > > >
> > > > It is fairly difficult to get modbus code aligned and working
> > > > automatically because different devices behave differently with even
> > > > most basic requests.
> > > > I remember that one of electric meters I had to work with did support
> > > > read multiple registers but did not support going over "empty"
> indexes.
> > > > By empty  I mean these which were not declared in the documentation,
> > > > even if it was still below 125 limit.
> > > >
> > > > Effectively I could draw three primary options to cover:
> > > > - read continuous (just keep expanding requests up to the limit)
> > > > - read blocks (group indexes into blocks up to limit, if they are
> > > > continuous)
> > > > - read single (read multiple registers is not supported)
> > > >
> > > > Some devices, especially older PLCs may also require extra delay
> after
> > > > data retrieval, so you have to wait between finishing one request and
> > > > starting another. Some inverters and official dongles made by fairly
> > > > large Chinese manufacturer, which brand I won't mention here, as well
> > as
> > > > primitive tcp/rtu bridges, may require "after connection delay" in
> > order
> > > > to establish rtu connection they use to serve tcp session.
> > > >
> > > > All this makes modbus option list rather long, compared to abilities
> it
> > > > gives!
> > > >
> > > > Cheers,
> > > > Łukasz
> > > >
> > > >
> > > > On 15.01.2023 17:05, Niels Basjes wrote:
> > > > > Hi,
> > > > >
> > > > > No, I'm reading many logical values where the needed registers
> > combined
> > > > > exceed the 125 mark.
> > > > > Assume my application needs a set of values and asks for such a
> block
> > > of
> > > > > registers.
> > > > > Then the modbus library that gets the request for 200 registers can
> > no
> > > > > longer reliably split it into multiple parts that yield the correct
> > > > value.
> > > > >
> > > > > What I understand of your S7 example (I do not know this device)
> > seems
> > > > like
> > > > > a device that offers a single value that exceeds the limits of
> modbus
> > > and
> > > > > thus I expect they made it so you can fetch it step by step.
> > > > >
> > > > > I'll see if I can do a wireshark dump for you.
> > > > >
> > > > > What should I make the issue say? I currently do not see this as a
> > bug
> > > or
> > > > > problem with plc4x.
> > > > >
> > > > > Niels
> > > > >
> > > > > On Sun, Jan 15, 2023 at 4:46 PM Christofer Dutz <
> > > > [email protected]>
> > > > > wrote:
> > > > >
> > > > >> Hi Niels,
> > > > >>
> > > > >> I think this might be related to what happens when reading Strings
> > in
> > > S7
> > > > >> without providing a length.
> > > > >> In this case each string is 255 charaters long and it already
> > exceeds
> > > > the
> > > > >> size-limit of 200 or so of a S7 1200.
> > > > >>
> > > > >> In S7 we use some code to split up multiple tags into multiple
> > > requests,
> > > > >> but rewriting the query to support automatic splitting of one
> single
> > > tag
> > > > >> into multiple requests is quite a bit more difficult.
> > > > >>
> > > > >> I thought you were reading multiple tags that in sum exceeded the
> > 125
> > > > >> registers and for that case simply something similar to the S7
> query
> > > > >> updater should also work for other protocols.
> > > > >>
> > > > >> Do I understand you correctly, that in your case you want to read
> > one
> > > > tag,
> > > > >> that is bigger?
> > > > >>
> > > > >> Chris
> > > > >>
> > > > >> From: Niels Basjes <[email protected]>
> > > > >> Date: Sunday, 15. January 2023 at 16:38
> > > > >> To: [email protected] <[email protected]>
> > > > >> Subject: [Modbus] Handling 'too large' blocks of registers
> > > > >> Hi,
> > > > >>
> > > > >> A few weeks ago some code of mine was merged to limit the number
> of
> > > > >> registers that can be requested in a single ModbusTag because
> asking
> > > for
> > > > >> more than 125 registers in a single request will always fail
> > (because
> > > of
> > > > >> the way modbus works).
> > > > >> https://github.com/apache/plc4x/pull/721
> > > > >>
> > > > >> One of the comments was asking if it can be automated in a generic
> > way
> > > > to
> > > > >> split a "too large" request into multiple smaller requests.
> > > > >> So If I ask for a block of 200 registers then plc4x would simply
> > split
> > > > it
> > > > >> into multiple requests (like 125 and 75 for example, or 100 and
> 100)
> > > and
> > > > >> afterwards merge the resulting registers of the two requests back
> > > into a
> > > > >> single block of 200 registers for the upstream application to
> > analyze.
> > > > >>
> > > > >> I said I would look into this and this is what I found while doing
> > > some
> > > > >> experimenting with my real solar converter.
> > > > >> This device uses the SunSpec standard for defining meaning to
> modbus
> > > > >> registers.
> > > > >>
> > > > >> My current conclusion at this point is that it is impossible to
> > handle
> > > > this
> > > > >> at the modbus level and I'm looking for you guys to challenge me
> in
> > > > this.
> > > > >>
> > > > >> Why do I say this?
> > > > >> One of the logical values you can retrieve is the name of the
> > > > Manufacturer
> > > > >> and the Model of the device that are both stored as UTF-8 in a set
> > of
> > > 16
> > > > >> registers (i.e. usually 32 characters).
> > > > >>
> https://github.com/sunspec/models/blob/master/json/model_1.json#L27
> > > > >>
> https://github.com/sunspec/models/blob/master/json/model_1.json#L36
> > > > >>
> > > > >> I found that if I try to fetch only a part of this logical value I
> > get
> > > > >> either an error (INVALID_ADDRESS) or bad data.
> > > > >> When I fetch the entire value I get the 16 registers which hold
> the
> > > > correct
> > > > >> data.
> > > > >>
> > > > >> Output of my test program that fetches the Model of the device
> > (which
> > > > is in
> > > > >> my case "SB3.6-1AV-41" ).
> > > > >> ModbusTag[4x40021:UINT[16]]:  0x5342 0x332E 0x362D 0x3141 0x562D
> > > 0x3431
> > > > >> 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000
> > 0x0000
> > > > >> ModbusTag[4x40021:UINT[15]]: INVALID_ADDRESS
> > > > >> ModbusTag[4x40022:UINT[15]]:  0xFFFF 0xFFFF 0xFFFF 0xFFFF 0xFFFF
> > > 0xFFFF
> > > > >> 0xFFFF 0xFFFF 0xFFFF 0xFFFF 0xFFFF 0xFFFF 0xFFFF 0xFFFF 0xFFFF
> > > > >>
> > > > >> So if I retrieve the correct block I get it.
> > > > >> If I try to get 1 register less than I should I get an error.
> > > > >> If I try to get the registers starting from the 2nd register I get
> > > only
> > > > >> 0xFFFF (important: NO error and a PlcResponseCode.OK !!)
> > > > >>
> > > > >> I expect there to be many other modbus devices that have similar
> > > effects
> > > > >> when the logical value requires multiple registers.
> > > > >>
> > > > >> So for now I come to the conclusion that fetching only part of the
> > > > >> registers that make up a logical variable in general will not work
> > and
> > > > (in
> > > > >> some cases) cannot be detected to have failed.
> > > > >>
> > > > >> At this point my assessment is that the only way to handle this is
> > by
> > > > >> actually knowing the meaning of the block of registers (i.e. which
> > > must
> > > > be
> > > > >> read together in a single read) and work from there.
> > > > >>
> > > > >> Note that the current SunSpec definition also has the concept of a
> > > > 'sync'
> > > > >> group of points (logical values that consist of 1 or more
> registers)
> > > > which
> > > > >> are grouped in the specification with the intent of "indicating
> > > > >> that the points in the group must be read and written atomically",
> > > which
> > > > >> effectively means you cannot read them individually from the
> modbus
> > > > >> standpoint.
> > > > >>
> > > > >> Looking for your feedback on this.
> > > > >> Do you know of existing software to generically handle this ?
> > > > >>
> > > > >> --
> > > > >> Best regards / Met vriendelijke groeten,
> > > > >>
> > > > >> Niels Basjes
> > > > >>
> > > > >
> > > > >
> > > >
> > >
> > >
> > > --
> > > Best regards / Met vriendelijke groeten,
> > >
> > > Niels Basjes
> > >
> >
>
>
> --
> Best regards / Met vriendelijke groeten,
>
> Niels Basjes
>

Reply via email to