thiagoralves / OpenPLC_v3

OpenPLC Runtime version 3
1.02k stars 421 forks source link

Add PiPLC Hardware layer + Modbus RTS/CTS GPIO capability #230

Closed Chrismettal closed 4 months ago

Chrismettal commented 4 months ago

As discussed in the forum thread about this, I've added Modbus RTS/CTS GPIO capability to OpenPLC running on Raspberry Pi's by swapping Libmodus with a Pi specific port.

To give all hardware layers the option of setting a RTS/CTS GPIO pin, i've added a new custom_layer_options struct that gets passed into the initialization of a hardware layer, for them to apply settings that can be used in main.cpp. This was required to keep the hardware layer initialization before the modbus initialization in main.cpp's execution order. Let me know if this additional struct is not the preferred way to do this!

Along with this, I've also added a hardware layer for my in-development PiPLC project, which incorporates the CTS/RTS GPIO functionality by having a modbus transceiver on-board.

I've tested this change in the following configuration on a testing board:

Link to testing board layout

smol

I've confirmed building, Modbus TCP and Serial capability with the following OS'es:

For this, I've connected a Modbus I/O Box through serial as well as observed that the Monitoring tab, which uses Modbus TCP as far as I know work as expected.


BTW, the install instructions for Windows still guide you to install python2 in Cygwin even though we are rebased to Python3. I also needed to substitute "Lynx" for "curl" in the installer script for windows so that I can get pip to execute

https://autonomylogic.com/docs/installing-openplc-runtime-on-windows/

thiagoralves commented 4 months ago

Thank you for the awesome PR @Chrismettal ! Just one thing about the custom_layer_options struct. I think that sending it to all hardware layers is a bit too much, as only your hardware layer makes use of it, and it is made of a single variable only. How about we make it as a global variable (or a global struct if more items will be added to it in the future) defined ladder.h, that libmodbus and your hardware layer can make use of using extern ? I'm just trying to avoid changing the hardware layer API, as that could potentially break other things in the future.

Chrismettal commented 4 months ago

I specifically thought passing a struct for HW layer options through main would be cleaner than using something global so I don't contaminate the namespace. But sure, I can make them global if that fits the general codestyle more!

To you have any example in the code where I can check how exactly the code style would do this?


I also thought provisioning a struct for this would help us in future with potentially more complex hardware layers that want to set global options. I'm sure PiPLC isn't the only supported hardware that implements on-board I/O that uses the underlying OS direclty. Thinking about how KNX / I²C / 1-wire will look like in OpenPLC for PiPLC. Though I'll gladly refactor to something more along what you imagined.

thiagoralves commented 4 months ago

Yeah, I confess that OpenPLC does not have the best coding style... It was written acros multiple years of my life (10 years and counting) and carries some of that evolving personality. If I had to start over today it would've been completely different. With that being said, there are a lot of global elements declared in ladder.h, so this hardware structure could be one of them. A few examples are the I/O buffers, the boolean controls (run_modbus, run_dnp3, etc) for the interactive server - those actually should be part of a struct, but, anyway - the PLC tick time, and some other things. You can include your struct in there and then just use it wherever you find appropriate.

Chrismettal commented 4 months ago

Moved the var to be global, defined in modbus_master.cpp as this is where this setting is ultimately used, and passed through ladder.h via extern like the other global settings.

Tested in Linux Mint VM with USB-Modbus adapter as well as real PiPLC hardware with on-board Modbus transceiver on the same testing board es before.

Reverted all changes in other hardware layers.