plc4x-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Julian Feinauer <>
Subject Re: [PLC4C] Summary of API discussion on slack
Date Tue, 12 May 2020 10:19:14 GMT
You have my +1 there : )

Am 12.05.20, 12:15 schrieb "Christofer Dutz" <>:

    Hi all,

    so I think we have the C-API in a quite nice state now and I'd like to merge the c-api
branch back to develop ... it shouldn't have any negative effect on the rest of the build.
Just wanted to ask if you are cool with me doing that.


    Am 06.05.20, 11:05 schrieb "Christofer Dutz" <>:

        Hi all,

        thanks to Otto's efforts now the C-API has it's equivalent to PlcValues ...
        Also has the API sort of matured to some state I think we no longer have to work on
the "feature/c-api" branch and would like to merge this back to develop.

        In the end it's still in the sandbox alongside a lot of unfinished stuff ... so we're
not treating it as a first-class citizen yet.

        What do you think?


        Am 04.05.20, 19:44 schrieb "Christofer Dutz" <>:

            Ok ... after several days of working in the garden a new day with updates on PLC4C

            So today I managed to finish and commit some changes that perform a full roundtrip
of connection, read, disconnect using the "simulated" driver.
            Right now that only parses the address strings and returns a random int for every
item .. this is not yet on-par with the java version of the simulated driver, but more a preview
of the API we are planning to use for PLC4C.

            All asynchronous operations: 
            - Connect
            - Read
            - Disconnect

            Are implemented using something we call "system-tasks" which I described in my
last summary.

            All seems to be working nicely and I really like the structure of the code ...
I know it will need quite a bit of cleaning up and I would be super grateful, if some C professionals
could review what I have created. Constructive feedback is essential here for the continued
work on this.


            Am 29.04.20, 19:57 schrieb "Christofer Dutz" <>:

                Aaaand another update :-)

                So today I continued adding code-flesh to the empty API body.

                I implemented two basic data-structures: List and Queue (Noticing at the end
that my queue isn't even needed).

                Starting from today the functionality for: connecting, reading, writing, etc.
is implemented by callback functions generating so-called system_tasks.

                These are data-structures consisting of 4 properties:
                - a state-machine-function callback
                - an int representing the state-machine state the task is currently in
                - a pointer to a context data-structure (The state-machine controls what's
in there)
                - a completed-flag that tells the system if a task is finished

                So now if a driver for example is asked to connect, it generates a system-task
and that's added to the task-list.

                Then as soon as the system_loop function is called, this function goes through
the list of queued system-tasks and for each calls the state-machine function if comes with
and passes in the task as an argument.

                In the end the system loop checks If after executing the state-machine-function
the task is marked as "completed" ... if it is it removes this task form the queue and continues
with the next task in the list.

                The cool thing is that this way we can even ensure the system_loop function
doesn't hog too much processing time ... so we could give the loop a maximum execution time
and as soon as that's exceeded the function returns and the following tasks will be executed
the next time the system_loop function is called. In this case I would probably change the
task-list into a ring data-structure.

                Right now my example hello world program if correctly loading the "simulated"
driver and a "dummy" transport and correctly connecting using the above mechanisms. 

                Guess tomorrow I'll be writing string-parsers again to continue working on
implementing the read/write operations on the simulated-driver.

                So far the update from today,


                Am 28.04.20, 19:38 schrieb "Christofer Dutz" <>:

                    Hi folks,

                    even if this wasn't discussed as much as the other things we discussed,
I still think it's important.

                    So I was a strong advocate of the "promised land" ... I wanted to use
promises and register callbacks for async execution.
                    Theoretically this I cool ... however I had to notice it's cool as long
as you have someone cleaning up for you.
                    In most of the languages I encountered heavy usage of this pattern there
are garbage collection mechanisms in place and then this is a great feature.

                    In C however this is not the case. Here you have to manually free previously
allocated memory and if you don't do that, you'll run out of it pretty soon.

                    My main issue was that with promises it is difficulty to explicitly clean
them up as you have no means to see which part of the program is still keeping a reference
to it. If you clean that up and the other code access it, the failure depends on your OS but
in all cases it's pretty bad.

                    So I decided to undo the promises, I just introduced a few days earlier.

                    To keep the code half-clean I decided to instead use some manual state-machine
like code.

                    Not much more to report besides the fact that I started implementing the
actual logic. Up to now all methods sort of just returned empty or default objects. Now at
least you can register drivers at the plc4c system and create connection structures, that
correctly parse plc4x connection strings and lookup matching drivers in the registry. 

                    Guess in the following days I'll have to work on how I can actually define
protocols in a way that I can have them processed in the central "loop" method without blocking
the OS.

                    Feel free to discuss here or on slack.

                    I'll continue to post summaries to what's been going on.


                    Am 23.04.20, 18:34 schrieb "Christofer Dutz" <>:


                        today we worked quite a bit on making the directory structure more
                        So what we've now done, it we left the general directory structure
unchanged, but eliminated the maven-like structure.
                        So now every module has a "CMakeList.txt" file and a "src", "include"
and "test" directory.
                        "src" is pretty much what src/main/c and src/main/resources would
have been, just mixed.
                        Same applies for "test".

                        The directory structure now matches that of a lot of other projects
and it would even allow adding a second set of build configurations to allow building PLC4C
with MyNewts "newt" build tool (But that's for the future ... no worries)

                        Today I also added a "simulated" driver which should act similar like
the one in PLC4J ... in the end it should respect the PLC4C API and be used as some dummy
driver which mainly helps with writing hello_world applications as well as testing new integration

                        Also did I extend the "system" with a function to manually create
and register drivers. 

                        Especially in limited environments like embedded systems, I think
the typical: "I just add all drivers and load what I need" doesn't work. Same as you can't
just copy a driver to the device, a dynamic search and discovery mechanism would be overkill.
We will definitely add similar loading mechanisms like in Java, but for now I'll work with
manually registering drivers to keep it simple, small and efficient.

                        So far the update for today.


                        Am 20.04.20, 16:41 schrieb "Christofer Dutz" <>:

                            Hi all,

                            currently we’re in a mode of synchronous exchange on creating
the PLC4C API on Apache slack “” (Please send an email if you need an
                            We’re doing that as specially in the beginning this simplifies
and speeds up things drastically.

                            But as we’re at Apache and here “If it didn’t happen on
the list, it didn’t happen” I’m trying to keep the list in sync with the outcome and
give you folks the chance to participate by writing up summaries.

                            So we have the great situation that Otto and Björn have quite
some experience in C and C++ and are being a huge help with getting this started.

                            So a few weeks ago I have already setup a build that’s integrated
into our normal Maven build. However you need to enable to profiles in order to do that:

                              *   with-sandbox
                              *   with-c

                            You need to run the maven build at least once as our plc4x-maven-plugin
is a maven plugin and we need to have it generate some code first (or the build will fail)

                            The actual build however is done with CMake. This allows us to
use any CMake-capable IDE to develop PLC4C (I’m using CLion, but VisualStudio seems to also
work fine).

                            Today I created a branch feature/c-api as I think I’ll sometimes
be committing unbildable stuff in order to allow collaboration (I commit something and others
fix it ;-) ).
                            So please follow this branch.

                            Regarding the directory structure, we decided to stick to a structure
that is sort of aligned with the one we have in PLC4X as this makes it easier to understand
the structure (at least from a PLC4J point of view). The structure should also not be too
strange for a c developer. What C developers might consider “an abomination” is that I
started off using a directory structure for modules which is maven-inspired.

                            The reason is that I think this allows to cleanly separate prod
from test code and code from resources (In this case code from header files) … so a C module
currently has the general structure:

                            - main
                            - c
                            - include
                            - test
                            - c
                            - include

                            The CMakeLists.txt file is sort of the equivalent to our pom.xml
… it tells CMake how to build the module. This is also where you define “dependencies”
… however in C you rather define the locations of the header-files you intend on using …
the actual using of code will happen by the linker when compiling.

                            So now come the parts where I was super happy to have some help

                              *   In the API module we have a set of header files which define
the core functions and types
                              *   However these types don’t really expose any information
on the internals of PLC4X. So even if you have a connection structure, you can’t access
any properties of this directly. If you want to access any properties, you need to use the
corresponding function. So if in the “connection” domain you have a plc4c_connection structure,
in order to access the connection_string property of that, you need to call the plc4c_connection_get_connection_string
function and pass in your connection object.
                              *   As a currently implicit naming convention we started using
a prefix “plc4c_” for everything.
                              *   We also split up the API functions into domains like “system”,
“connection”, … all the functions which then results in names like “plc4c_system_create”.
As we’re expecting the domains to grow, this way we hope to keep the sizes of the code blocks
                              *   While the interface a user would use is defined in the API
module, the implementation is then done in the SPI module (pretty much like in PLC4J)
                              *   Initially we started playing around with callbacks, much
like we’re doing in Java and as C does allow function pointers, that seemed like a good
idea. But people actually coding in C mentioned that this form of coding feels very strange
for full-blooded C developers. As we want this API to feel native for C developers, we’ll
go down this path.
                              *   As C doesn’t support a try-catch-finally style error handling,
almost every function returns a return_code enum which can be translated into error messages
by using some helper functions. So it is important to check if an operation returned OK and
to do some error handling, if this is not OK.
                              *   The API will completely not use synchronous operations.
So we won’t provide a blocking “connect” function that returns as soon as the connection
is established, as some of the systems we’re going to support are single threaded and don’t
have any mutlitasking or scheduling. Therefore we’ll have a “plc4c_system_loop()” function
which is cyclically called in order to do something.

                            So far the update … I hope I didn’t skip anything …

                            More will follow :-)


View raw message