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

Simulating a PLC #73

Open
piertoni opened this issue Aug 26, 2019 · 6 comments
Open

Simulating a PLC #73

piertoni opened this issue Aug 26, 2019 · 6 comments

Comments

@piertoni
Copy link

Hi, I would like to simulate a PLC.
In my case when I read an address, let's say 10 words starting from 0x200, I get some values back (I.E. a string containing the Producer), instead when I read 10 words from 0x201 I will get completely different values.
Which is the proper way to realize this? For what I have understood with app.route I can only define one value at a time. Is there a way to get the lenght of the request at application level?

The workaround that came to my mind was to trigger the modification of regs_word when the first register is requested, like:

    @app.route(slave_ids=[1],function_codes=[3], addresses=(0x200,1) ):
    def producer(slave_id, function_code, address):
        regs_word[0x200] = 0xaabb # first registers
        regs_word[0x201] = 0x2231 # prepares other registers
        regs_word[0x202] = 0x231a # prepares other registers
        # ...
        return regs_word[0x200]

    @app.route(slave_ids=[1],function_codes=[3], addresses=(0x201,15) ):
    def other_regs(slave_id, function_code, address):
        return regs_word[address]

Thanks

@OrangeTux
Copy link
Collaborator

OrangeTux commented Aug 27, 2019

Hello @piertoni,

Thanks for your question. From what I understand you want the value of a register to be depending on the start address of the request. Am I correct?

For what I have understood with app.route I can only define one value at a time.

It is correct that the the handlers should return only 1 value. If a client requests multiple registers than the handler is executed multiple times using a different value for each address.

But wouldn't something like this work for your?

@app.route(slave_ids=[1],function_codes=[3], addresses=list(range(0x200,0x215))):
    def producer(slave_id, function_code, address):
        if address == 0x200:
            # prepare all your other registers

            regs_word[0x200] = 0xaabb # first registers
            regs_word[0x201] = 0x2231 # prepares other registers
            regs_word[0x202] = 0x231a # prepares other registers
      
     return regs_word[0x200]

@piertoni
Copy link
Author

Hello @piertoni,

Thanks for your question. From what I understand you want the value of a register to be depending on the start address of the request. Am I correct?

Exactly, in fact I am replicating the PLC behavior and if I read 16 regs starting from 0x200 I get one string I.E. Producer name, If I read 16 regs starting from 0x201 I get another string I.E. production date. Is not really a standard modbus behavior from my point of view... but is like this 😄

For what I have understood with app.route I can only define one value at a time.

It is correct that the the handlers should return only 1 value. If a client requests multiple registers than the handler is executed multiple times using a different value for each address.

But wouldn't something like this work for your?

@app.route(slave_ids=[1],function_codes=[3], addresses=list(range(0x200,0x215))):
    def producer(slave_id, function_code, address):
        if address == 0x200:
            # prepare all your other registers

            regs_word[0x200] = 0xaabb # first registers
            regs_word[0x201] = 0x2231 # prepares other registers
            regs_word[0x202] = 0x231a # prepares other registers
      
     return regs_word[0x200]

Yes, this will work better than my code! Thanks!
It's a hack anyway but for a simulator I think is fine.
Really thanks!

@piertoni
Copy link
Author

mmm thinking better I don't know if this (in general) will work because should be something like this:

    @app.route(slave_ids=[1],function_codes=[3], addresses=list(range(0x200,0x215))):
    def producer(slave_id, function_code, address):
        if address == 0x200:
            # prepare all your other registers

            regs_word[0x200] = 0xaabb # first registers
            regs_word[0x201] = 0x2231 # prepares other registers
            regs_word[0x202] = 0x231a # prepares other registers
      
     return regs_word[address]

    @app.route(slave_ids=[1],function_codes=[3], addresses=list(range(0x201,0x216))):
    def production_date(slave_id, function_code, address):
        if address == 0x201:
            # prepare all your other registers

            regs_word[0x200] = 0x1111 # first registers
            regs_word[0x201] = 0x0000 # prepares other registers
            regs_word[0x202] = 0x123b # prepares other registers
      
     return regs_word[address]

In fact the region are overlapping... I don't think will work, what do you think?

@piertoni piertoni reopened this Aug 27, 2019
@OrangeTux
Copy link
Collaborator

It's a hack anyway but for a simulator I think is fine.

I am not sure if there is a non-hacky option. To be fair, your requirement of having registers values depend on the start address seem a little bit odd for me.

In fact the region are overlapping... I don't think will work, what do you think?

I am not exactly how this will work out, but I don't think it will work as you want it to work. At least uModbus is not intended to work that way when I created this package.

@piertoni
Copy link
Author

I am not sure if there is a non-hacky option. To be fair, your requirement of having registers values depend on the start address seem a little bit odd for me.

Yeah, I agree, that seems odd to me too... but ask Wago producers... 😄

In fact the region are overlapping... I don't think will work, what do you think?

I am not exactly how this will work out, but I don't think it will work as you want it to work. At least uModbus is not intended to work that way when I created this package.

If you think that it is possible to retrieve the length of the request just tell me where to start and eventually I can write the code.
If not I will close the issue, thank you for uModbus, is cool! 😄

@OrangeTux
Copy link
Collaborator

If you think that it is possible to retrieve the length of the request just tell me where to start and eventually I can write the code.

Assuming you run a Modbus TCP server than you could create your own request handler that extends from the umodbus.server.tcp.RequestHandler. If you than override than the umodbus.server.AbstractRequestHandler.execute_route() you have access to the info you want.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants