afterdream
hi,thiagorablves

    I have understood  the running process by reading the main.cpp,knowing how to add gpio dirver.
    But I really don't know the function config_run__(tick++) and I really want kown how to map the plc IO to real hardware GPIO.
    Thanks!
Quote 0 0
thiagoralves
If all you want to do is map PLC I/O to real hardware you're looking at the wrong file. You should check the hardware_layer.cpp file. There is one different hardware_layer.cpp for each platform, and they are all inside the /core/hardware_layers folder. Basically all it need to have are 3 functions that are called by OpenPLC main loop: initializeHardware(), updateBuffersIn(), and updateBuffersOut(). An explanation of each function is available on the blank.cpp hardware layer, which should use as a base if you're trying to build your own hardware driver.
Quote 1 0
mohsh86
alright, i am finding this a bit confusing, do i need to go through other .cpp files to start understanding how this works? i have an industrial built PLC based on RPI compute module, have a couple of questions:


1. DIO's are accessible through "/sys/class/gpio" so am assuming these are the built in GPIO's, detected and available through kernel and i can read them with simple "cat" , e.g: "cat /sys/class/gpio/gpio18/value":
Q: if for example the DI pins are gpio18, gpio19, gpio20, gpio 21, does that mean: 
#define MAX_INPUT 4 & int inBufferPinMask[MAX_INPUT] = { 18, 19, 20 ,21 }; ?

2. AI is through I2C ADC chip,"MCP3424" and is accessible through "/sys/bus/i2c/devices/0-006c/iio😃evice0" :

  • Files …raw - for reading analog input values
  • Files …scale - scale of reading
  • File in_voltage_scale_available - all available scales
  • File sampling_frequency_available - all available sampling frequency

    Q1. assuming everything else is predefined for simplicity, how is it possible to refer to AI pin through file "/sys/bus/i2c/devices/0-006c/iio😃evice0/in_voltage0_raw" in the hardware layer?
    Q2. to make this more advance when it comes to scaling, how the other variables/files can be incorporated in the hardware layer? or do i just read the raw and scale it internally in OpenPLC?

    [edit]
    I've added manufacturers I/O related info PDF
Quote 0 0
thiagoralves
mohsh86 wrote:
alright, i am finding this a bit confusing, do i need to go through other .cpp files to start understanding how this works?

No. If all you want to do is write a driver for OpenPLC to control your GPIOs, then you only need to look at hardware_layer.cpp file. Just remember that if you want to make your changes permanent, it is better if you edit one of the original files inside the /webserver/core/hardware_layers/ folder. Get for example the raspberrypi.cpp file and put your modifications in there. Then, once you're done, go to the hardware tab on the webserver and reapply the Raspberry Pi driver. This will make OpenPLC reload your modified driver and then all will be good.

mohsh86 wrote:

1. DIO's are accessible through "/sys/class/gpio" so am assuming these are the built in GPIO's, detected and available through kernel and i can read them with simple "cat" , e.g: "cat /sys/class/gpio/gpio18/value":
Q: if for example the DI pins are gpio18, gpio19, gpio20, gpio 21, does that mean: 
#define MAX_INPUT 4 & int inBufferPinMask[MAX_INPUT] = { 18, 19, 20 ,21 }; ?

No. The pin numbers are according to the WiringPi library, that bases the numbers on the pin headers of the Raspberry Pi. This is not the same numbering as the one used in the Broadcom chip GPIO. Also, I don't know how your PLC is internally connected. It may be the case that these GPIOs are not even directly connected to the Broadcom chip at all. Toggling pins on the chip directly might cause unexpected behaviors and even harm your device!

It seems that the operating system of your device makes available all the GPIO over SYSFS. If you don't know what it is, here is a quote from Wikipedia: "sysfs is a pseudo file system provided by the Linux kernel that exports information about various kernel subsystems, hardware devices, and associated device drivers from the kernel's device model to user space through virtual files". This means that these virtual files (/sys/class/gpio) are directly linked to a driver that can control your GPIO. For the Linux system, they are treated as files. So your driver must also treat them as files. If you want to read them, just open the file and read it. If you want to write to them, open the file and write. I'm writing an OpenPLC driver for the UniPi Neuron PLC that also makes available the pins over SYSFS. The driver is not finished yet, but I'm attaching it here for your reference. Please ignore the SearchForIO() function as this is specific for the Neuron platform.
mohsh86 wrote:

2. AI is through I2C ADC chip,"MCP3424" and is accessible through "/sys/bus/i2c/devices/0-006c/iioDevice0" :

  • Files …raw - for reading analog input values
  • Files …scale - scale of reading
  • File in_voltage_scale_available - all available scales
  • File sampling_frequency_available - all available sampling frequency

    Q1. assuming everything else is predefined for simplicity, how is it possible to refer to AI pin through file "/sys/bus/i2c/devices/0-006c/iioDevice0/in_voltage0_raw" in the hardware layer?

Same thing as last question. Use SYSFS to access the data.
mohsh86 wrote:

Q2. to make this more advance when it comes to scaling, how the other variables/files can be incorporated in the hardware layer? or do i just read the raw and scale it internally in OpenPLC

OpenPLC registers have 16 bits, which means they are integers on the range 0...65535. You can multiply or divide the raw value of your analog input to fit in this range so you don't lose accuracy. All OpenPLC drivers do that, they provide all analog values in the full scale range of 0...65535.
Quote 0 0
mohsh86
Thanks for your quick prompt, i' haven't dug deep into the files you've sent me yet, still have few more questions if you don't mind:

1. is there any performance degradation when accessing GPIO over SYSFS? is that the optimal way to do it?
2. the vendor is providing a couple of examples of how to deal with the GPIO over c code (attached example and PDF part), would that be a better way of doing it?
3. some of the GPIO's can be configured as either DI or DO (i think they've wired the circuitry in a way that the direction of those DIO is based on other onboard GPIO (controlled in pairs in my case) that aren't terminated to the outside of the box), is there such a way to control the direction dynamically from hardware layer? or do i just add those controlling pins and set them in the code as either high or low to define the direction of the other pins?

i know this sounds to be outside of the topic, but i guess everybody will benefit from understanding how OpenPLC should be utilized.
Quote 1 0
thiagoralves
SYSFS is definitely not the most optimal way to do it, but certainly the most generic. It allows different architectures to use virtually the same code, as the I/O operations are handled by the Operating System. The most optimal solution is certainly direct register access. This pdf document you sent just describes the API developed by the manufacturer of the device. How that API handles I/O operations I don’t know. It could be using SYSFS internally or direct register access. The only way to know which one is faster is to implement both and measure.

About the GPIO direction, you could define one OpenPLC register (like %QW0 for example) to hold that information. Then each bit of that value would determine if each particular GPIO should be input or output
Quote 0 0
Zoltan
Dear thiagoralves and OpenPLC project


I have a WS-15423 8-ch Relay Expansion Board for Raspberry, and it needs the 5, 6, 13, 16, 19, 20, 21, 26 (BCM) gpios as output. https://www.waveshare.com/wiki/RPi_Relay_Board_(B)

I have tried to investigate and edit the hardware_layer.cpp (from standard Raspberry Pi settings). Is it enough to change the MAX_INPUT, MAX OUTPUT and in(out)BufferPinMask to the correct numbers?
What will be the new name of that pin in the Openplc (etc. it was %IX1.1), or I have to do something else in the program? 
I have an 1-wire thermometer on the BCM 4 also.

Thank You in advance
(and Sorry about my english and my noobism. 😉

Zoltan
Quote 0 0
thiagoralves
Yes, just change the #defines and the pinMask arrays and you should be good. The mapping is sequential, so if you put on the output array pins 2, 3, 4, they will be mapped to %QX0.0, %QX0.1, and %QX0.2 respectively. For the 1-wire thermometer, you will have to write your own C code to interface with it, and then map it to some available position, like %IW0 for example.
Quote 0 0