# Directory structure (was: Modbus/tcp works on the lplc repository)

J

#### Jiri Baum

Philip Costigan:

> I just got the Modbus/TCP to lplc interface code to work.

I would have placed the code under the io directory rather than under drivers - I thought drivers was for kernel stuff. It doesn't matter much, but one of us is confused...

Curt, can we have a clarification/ruling on this?

Jiri
--
Jiri Baum <[email protected]>
What we do Every Night! Take Over the World! Step 1 - bid for SMOFcon

_______________________________________________
LinuxPLC mailing list
[email protected]
http://linuxplc.org/mailman/listinfo/linuxplc

C

#### Curt Wuollet

Hi Jiri, Philip.

We'll take code wherever he wants to put it :^).

Seriously though, It's an excellent question and bears on the UNIX tradition and the very, very, ambigous term "driver" that is only loosely qualified with the preceding "device". Ideally, by this time we would have defined just exactly how we are going to treat IO.
My working concept is this:
We are going to have IO that requires an actual "device driver" in the classical sense. Examples are the ISA and PCI cards that I am working with. These are hardware that works at least partially in kernel space and may or may not use interrupts or other features that require a KS implementation. It is strong UNIX tradition and
my opinion that these enforce only method not policy so that they become files and can be handled reasonably interchangeably with ioctl()s handling the non-hideable differences. This dogma has made things easier for programmers for quite some time, but there are necessarily some exceptions for devices that can't map well.

We will probably have some IO that for various reasons has dedicated
hardware specific code in user space that does the same things that a
"device driver" does. This defies definition for the moment, but I'll
pull it together in a moment

We have IO that is manipulated strictly through existing Linux means
and services. This is the various serial and ethernet attached IO and
virtual IO into PLC's and other devices. I haven't looked at the code
yet, but I imagine that it uses sockets or other longstanding UNIX
facilities.

On the other hand we have an interface into the SMM. I am not expert
on this, and it is flux but it doesn't look like a file last time I
looked :^) (nor should it)

What comes between is what will determine where Philip's code and my
code and other IO code ends up.

I think the process that reads the IO and loads the SMM should be written to a high level api so that we are not morphing it and continually redefining it.(within reason). It should not be concerned with init, setup, and other specifics. In othere words we should maintain abstraction as far towards the IO as we can. Below that
interface we will quite probably need another layer of device specific code to handle the idiosyncracies and go between this interface and
the various drivers. This layer will handle protocols and init, setup and individual cases. Right now, this is not formalized and each IO
type interfaces directly with the SMM functions. This layer will be quite different for the classes above but with care could be three
programs to handle the classes with lots of details or many small classes (individual). What I'd like to avoid is twenty ways to talk to serial IO or Ethernet IO. I'd also like to avoid altering twenty drivers each time the SMM code changes. This is my thought so far but we really really need to think and debate and find the best way to handle the many to one relationship.

So, Philip's code probably will be classed as something other than a driver eventually. We need to figure this out because I don't think the way we are doing this, both Philip and I, is gonna work for 20 drivers or 50 drivers. and it's just about time to do it.

How do we define things so we don't have to rev 50 drivers all the time?
How do we make these diverse IO types look the same to the memory manager/IO proc.

can we limit this so we have one go between for "device drivers" and one for user space and service "drivers".

Let's go ahead and class them all as drivers for now. It may not be technically correct but people know where to look.

I am very flexible on this and all of the above is simply my working concept.

More on this later

regards

cww

_______________________________________________
LinuxPLC mailing list
[email protected]
http://linuxplc.org/mailman/listinfo/linuxplc

J

#### Jiri Baum

Curt Wuollet:
> My working concept is this:

> We are going to have IO that requires an actual "device driver" in the
> classical sense.
...
> We will probably have some IO that for various reasons has dedicated
> hardware specific code in user space
...
> We have IO that is manipulated strictly through existing Linux means and
> services.
...

> On the other hand we have an interface into the SMM. I am not expert on
> this, and it is flux but it doesn't look like a file last time I looked
> :^) (nor should it)

Actually, the API is fairly stable; there are some auxiliary functions being added, and some of the back-end is changing, but the core of the API
is still the same. The last big change I remember was when multi-bit points came in, but they'd been planned since the beginning so none of the one-bit code needs to be changed.

It's all backwards-compatible (except bugs get fixed).

> It think the process that reads the IO and loads the SMM should be
> written to a high level api so that we are not morphing it and
> continually redefining it.(within reason). It should not be concerned
> with init, setup, and other specifics. In othere words we should maintain
> abstraction as far towards the IO as we can.

For now, that's pretty much the SMM API. Once there are 3-5 io processes, we should probably look at them and abstract common idioms into an "io lib" (or a general lib, if they are general-use things). But for now there only really needs to be one process between the SMM and the kernel/hardware.

> Below that interface we will quite probably need another layer of device
> specific code to handle the idiosyncracies and go between this interface
> and the various drivers. This layer will handle protocols and init, setup
> and individual cases. Right now, this is not formalized and each IO type
> interfaces directly with the SMM functions.

I'm not sure what exactly you'd want in this layer.

Where a group of devices are accessed in a similar way, they could all be handled using one I/O process (for example, one IO module could handle any number of 8255-based cards).

OTOH, I don't see the advantage of placing disparate I/O types in one process. It'll just have to be more complicated, eventually duplicating much that the SMM already provides. (Different-speed devices should each update the SMM at its own speed, etc.)

> I'd also like to avoid altering twenty drivers each time the SMM code
> changes.

The SMM API shouldn't be changing. After all, every time the SMM changes there'll be the logic engines and the mmi modules and end-user programs
that use it, not just the io modules.

For other changes, only a recompile is needed. "make clean" at the top level should do it (I recently put it in).

> This is my thought so far but we really really need to think and debate
> and find the best way to handle the many to one relationship.
...
> How do we define things so we don't have to rev 50 drivers all the time?

The SMM API should be changing very very rarely, so it won't be such a big problem.

In some ways I'm more worried about shoe-horning together IO types that don't go well together. Even serial I/O can have massively different timing depending on what's on the other end - and we don't (necessarily) want to hold up the fast I/O until the slow I/O responds.

Remember, there may be 20 or 50 io modules in the lPLC, but any particular installation will probably only run 1 or 2 of them. The code for the other 19 or 49 doesn't need to be in memory, even if a lot of it is similar.

If an installation *does* need many io modules, then abstracting common idioms into a shared library will relieve the memory burden while keeping the mutual protection that separate processes offer.

Finally, there's the debugging problem: no one developer will have all 50 different devices to play with. By separating code for different devices into different processes, interference between them should be minimized. Debugging strange interactions between routines for different devices will be a nightmare --- so we should separate them as much as we can.

> Let's go ahead and class them all as drivers for now. It may not be
> technically correct but people know where to look.

My working concept was that
- kernel-space is "drivers", and
- user-space is "io modules".

In this way, IO modules stand between kernel-space drivers and the SMM. Some IO modules access lPLC-specific drivers, others access generic services (eg /dev/ttyS0), some may even just do an ioperm(2) and access the hardware directly.

Whether an IO module can handle just a single brand-foo card or a multitude of cards that makes the Mos Eisley cantina look tame, in some ways it's still the same thing: the last time the SMM sees a point on its way to the real world.

,-------------.
,--- | io module 1 | ----- /dev/ttyS0 <=> device
,---------. / -------------'
| | -' ,-------------.
| SMM | ------- | io module 2 | ----- kernel 8255 driver <=> card
| | -. -------------'
---------' \ ,-------------.
--- | io module 3 | <=> i/o registers (directly)
-------------'

The io module processes all use the smm library; some or all may also use an io-module library, once we have enough experience with io modules to
know what such a library should contain.

Jiri
--
Jiri Baum <[email protected]>
What we do Every Night! Take Over the World! Step 1 - bid for SMOFcon

_______________________________________________
LinuxPLC mailing list
[email protected]
http://linuxplc.org/mailman/listinfo/linuxplc

C

#### Curt Wuollet

Jiri Baum wrote:
>
> Curt Wuollet:
> > My working concept is this:
>
> > We are going to have IO that requires an actual "device driver" in the
> > classical sense.
> ...
> > We will probably have some IO that for various reasons has dedicated
> > hardware specific code in user space
> ...
> > We have IO that is manipulated strictly through existing Linux means and
> > services.
> ...
>
> > On the other hand we have an interface into the SMM. I am not expert on
> > this, and it is flux but it doesn't look like a file last time I looked
> > :^) (nor should it)
>
> Actually, the API is fairly stable; there are some auxiliary functions
> being added, and some of the back-end is changing, but the core of the API
> is still the same. The last big change I remember was when multi-bit points
> came in, but they'd been planned since the beginning so none of the one-bit
> code needs to be changed.
>
> It's all backwards-compatible (except bugs get fixed).
>
> > It think the process that reads the IO and loads the SMM should be
> > written to a high level api so that we are not morphing it and
> > continually redefining it.(within reason). It should not be concerned
> > with init, setup, and other specifics. In othere words we should maintain
> > abstraction as far towards the IO as we can.
>
> For now, that's pretty much the SMM API. Once there are 3-5 io processes,
> we should probably look at them and abstract common idioms into an "io lib"
> (or a general lib, if they are general-use things). But for now there only
> really needs to be one process between the SMM and the kernel/hardware.
>
> > Below that interface we will quite probably need another layer of device
> > specific code to handle the idiosyncracies and go between this interface
> > and the various drivers. This layer will handle protocols and init, setup
> > and individual cases. Right now, this is not formalized and each IO type
> > interfaces directly with the SMM functions.
>
> I'm not sure what exactly you'd want in this layer.

Everything that is lplc specific so that the drivers don't have to be. And more or less depending on how "high level" the driver is. What I'm trying to work through is where protocols go when we have fb attached IO, in contrast with the cards which are register reads and writes. And
in the case of serial and network attached IO where does any additional bit to register, register to register, message parsing, etc. stuff go.

Right now all that is done on an individual basis for each type of IO. This is workable I suppose, but it requires a lot of knowlege to add an IO driver. I've been wondering and trying to think of a common interface to adapt IO to. Right now this is the SMM itself and it's function call
interface. But if someone wants to add a fursluginer73 interface they have to know almost as much as you about the SMM and the reliability of the machine will depend on how good they are. We are not going to get all the IO interfaces we want if we make it that hard to do. I know you
don't see the problem much because it's not a problem for you :^).

What I'm kinda looking for is a plan on how we are going to handle this and to do some thinking up front to see if there is a better way than
individual complex IO procs for each device.

We went from a simple model to a complex model. The simple model was that we read and write from registers. That is a universal paradigm in the
PLC biz. Lots of folks understand that. We went to a complex function call interface because we needed that functionality. C programmers from the
rest of the computing world are comfortable with that but, most of the comm software in the automation world works with a register interface.
One of the ways we could make this easier to support for vendors, for example is to provide a virtual register interface. The particulars of
how to deal with that would only need to be written once, and porting drivers or protocol implementations would be much easier. I'm not
suggesting that as a cure all, but it's something to think about.

> Where a group of devices are accessed in a similar way, they could all be
> handled using one I/O process (for example, one IO module could handle any
> number of 8255-based cards).

Yes that would be good if possible.

> OTOH, I don't see the advantage of placing disparate I/O types in one
> process. It'll just have to be more complicated, eventually duplicating
> much that the SMM already provides. (Different-speed devices should each
> update the SMM at its own speed, etc.)

Not disagreeing with that either.

> > I'd also like to avoid altering twenty drivers each time the SMM code
> > changes.
>
> The SMM API shouldn't be changing. After all, every time the SMM changes
> there'll be the logic engines and the mmi modules and end-user programs
> that use it, not just the io modules.
>
> For other changes, only a recompile is needed. "make clean" at the top
> level should do it (I recently put it in).
>
> > This is my thought so far but we really really need to think and debate
> > and find the best way to handle the many to one relationship.
> ...
> > How do we define things so we don't have to rev 50 drivers all the time?
>
> The SMM API should be changing very very rarely, so it won't be such a big
> problem.
>
> In some ways I'm more worried about shoe-horning together IO types that
> don't go well together. Even serial I/O can have massively different timing
> depending on what's on the other end - and we don't (necessarily) want to
> hold up the fast I/O until the slow I/O responds.

Agreed, but "every man for himself" wrecks any semblance of determinism. I'm _not_ saying that way is bad, just that we should probably brainstorm a a little and look at alternatives. Possibly some way to sync the slow to some multiple of the fast, or support IO classes or something.

> Remember, there may be 20 or 50 io modules in the lPLC, but any particular
> installation will probably only run 1 or 2 of them. The code for the other
> 19 or 49 doesn't need to be in memory, even if a lot of it is similar.
>
> If an installation *does* need many io modules, then abstracting common
> idioms into a shared library will relieve the memory burden while keeping
> the mutual protection that separate processes offer.
>
> Finally, there's the debugging problem: no one developer will have all 50
> different devices to play with. By separating code for different devices
> into different processes, interference between them should be minimized.
> Debugging strange interactions between routines for different devices will
> be a nightmare --- so we should separate them as much as we can.
>
> > Let's go ahead and class them all as drivers for now. It may not be
> > technically correct but people know where to look.
>
> My working concept was that
> - kernel-space is "drivers", and
> - user-space is "io modules".
Great, anything that makes sense.
>
> In this way, IO modules stand between kernel-space drivers and the SMM.
> Some IO modules access lPLC-specific drivers, others access generic
> services (eg /dev/ttyS0), some may even just do an ioperm(2) and access the
> hardware directly.
>
> Whether an IO module can handle just a single brand-foo card or a multitude
> of cards that makes the Mos Eisley cantina look tame, in some ways it's
> still the same thing: the last time the SMM sees a point on its way to the
> real world.
> ,-------------.
> ,--- | io module 1 | ----- /dev/ttyS0 <=> device
> ,---------. / -------------'
> | | -' ,-------------.
> | SMM | ------- | io module 2 | ----- kernel 8255 driver <=> card
> | | -. -------------'
> ---------' \ ,-------------.
> --- | io module 3 | <=> i/o registers (directly)
> -------------'
>
> The io module processes all use the smm library; some or all may also use
> an io-module library, once we have enough experience with io modules to
> know what such a library should contain.

Since a great deal of making this thing truly useful is supporting everything under the sun, I see making it easy to add IO types as mission critical ( oops, fell into ITspeak, sorry ) Who knows? perhaps using organizations can do some of the work for us ;^). And yes, I'm playing the devil's advocate but, not without reason. That's what OSS is about isn't it?

cww

_______________________________________________
LinuxPLC mailing list
[email protected]
http://linuxplc.org/mailman/listinfo/linuxplc

J

#### Jiri Baum

Curt Wuollet:
> Right now all that is done on an individual basis for each type of IO.
> This is workable I suppose, but it requires a lot of knowlege to add an
> IO driver. I've been wondering and trying to think of a common interface
> to adapt IO to. Right now this is the SMM itself and it's function call
> interface.

OK.

> But if someone wants to add a fursluginer73 interface they have to know
> almost as much as you about the SMM and the reliability of the machine
> will depend on how good they are. We are not going to get all the IO
> interfaces we want if we make it that hard to do.

We should work on abstracting common idioms into libraries, here. The configuration interface, for instance, is fairly low-level. Then again, even in your 8255 code there's device-specific handling in that part (checking for invalid IN and OUT combinations).

> I know you don't see the problem much because it's not a problem for you
> :^).

True.

> We went from a simple model to a complex model. The simple model was that
> we read and write from registers. That is a universal paradigm in the PLC
> biz. Lots of folks understand that. We went to a complex function call
> interface because we needed that functionality. C programmers from the
> rest of the computing world are comfortable with that but, most of the
> comm software in the automation world works with a register interface.

Hmm, I can give you a pointer into the private map, but I'm not sure what you're going to do with it:

Another possibility would be to invent new syntax. We could have a script that transforms:
foo := 1;
into
plc_set(foo, 1);

A third possibility would be to go to C++, which would allow us to redefine the assignment operator:
foo = 1;

> One of the ways we could make this easier to support for vendors, for
> example is to provide a virtual register interface.

That can be done. Either by some trick (above), or by simply coding a function that copies registers to private map, calls plc_update() and
copies private map to registers.

> > Where a group of devices are accessed in a similar way, they could all
> > be handled using one I/O process (for example, one IO module could
> > handle any number of 8255-based cards).

> Yes that would be good if possible.

I think your dio48 code could be adapted for that - up to 9 or 10 chips would be easy, beyond that some of the parsing and string handling would have to be done differently.

> > In some ways I'm more worried about shoe-horning together IO types that
> > don't go well together. Even serial I/O can have massively different
> > timing depending on what's on the other end - and we don't
> > (necessarily) want to hold up the fast I/O until the slow I/O responds.

> Agreed, but "every man for himself" wrecks any semblance of determinism.
> I'm _not_ saying that way is bad, just that we should probably brainstorm
> a a little and look at alternatives. Possibly some way to sync the slow
> to some multiple of the fast, or support IO classes or something.

Mario and I were discussing a synchronisation mechanism, but the conversation sort of got stuck - I think that's my fault, sorry Mario! (The e-mail is still sitting in my inbox waiting to be answered.)

Basically, the idea was to allow generic synchronisation between all kinds of modules (not just I/O), using a Petri-net-like structure. A lot of flexibility within relatively simple semantics.

> > > Let's go ahead and class them all as drivers for now. It may not be
> > > technically correct but people know where to look.

> > My working concept was that
> > - kernel-space is "drivers", and
> > - user-space is "io modules".

> Great, anything that makes sense.

> Since a great deal of making this thing truly useful is supporting
> everything under the sun, I see making it easy to add IO types as mission
> critical ( oops, fell into ITspeak, sorry )

True. Often, I expect, it'll be a question of taking an existing, similar driver and changing it, but we should definitely make it as easy as
possible. But no easier - that's the hard part.

Jiri
--
Jiri Baum <[email protected]>
What we do Every Night! Take Over the World! Step 1 - bid for SMOFcon

_______________________________________________
LinuxPLC mailing list
[email protected]
http://linuxplc.org/mailman/listinfo/linuxplc

C

#### Curt Wuollet

Jiri Baum wrote:
>
> Curt Wuollet:
> > Right now all that is done on an individual basis for each type of IO.
> > This is workable I suppose, but it requires a lot of knowlege to add an
> > IO driver. I've been wondering and trying to think of a common interface
> > to adapt IO to. Right now this is the SMM itself and it's function call
> > interface.
>
> OK.
>
> > But if someone wants to add a fursluginer73 interface they have to know
> > almost as much as you about the SMM and the reliability of the machine
> > will depend on how good they are. We are not going to get all the IO
> > interfaces we want if we make it that hard to do.
>
> We should work on abstracting common idioms into libraries, here. The
> configuration interface, for instance, is fairly low-level. Then again,
> even in your 8255 code there's device-specific handling in that part
> (checking for invalid IN and OUT combinations).
>
> > I know you don't see the problem much because it's not a problem for you
> > :^).
>
> True.
>
> > We went from a simple model to a complex model. The simple model was that
> > we read and write from registers. That is a universal paradigm in the PLC
> > biz. Lots of folks understand that. We went to a complex function call
> > interface because we needed that functionality. C programmers from the
> > rest of the computing world are comfortable with that but, most of the
> > comm software in the automation world works with a register interface.
>
> Hmm, I can give you a pointer into the private map, but I'm not sure what
> you're going to do with it:
>
> Another possibility would be to invent new syntax. We could have a script
> that transforms:
> foo := 1;
> into
> plc_set(foo, 1);
>
> A third possibility would be to go to C++, which would allow us to redefine
> the assignment operator:
> foo = 1;
>
> > One of the ways we could make this easier to support for vendors, for
> > example is to provide a virtual register interface.
>
> That can be done. Either by some trick (above), or by simply coding a
> function that copies registers to private map, calls plc_update() and
> copies private map to registers.

Just blue sky, but I was thinking that a common IO proc could provide those abstractions in a uniform way so that "drivers" (the broad term)
wouldn't have to be lplc specific. Below this level would be individual processes. I'm still stuck on what to do with protocols. Many require some sort of engine unto themselves. I need to look at how it's layered in industry practice. If that doesn't suck too much it would make porting
straightforward. Most of the device support is probably to some secret Microsoft stuff like OPC or ?

> > > Where a group of devices are accessed in a similar way, they could all
> > > be handled using one I/O process (for example, one IO module could
> > > handle any number of 8255-based cards).
>
> > Yes that would be good if possible.
>
> I think your dio48 code could be adapted for that - up to 9 or 10 chips
> would be easy, beyond that some of the parsing and string handling would
> have to be done differently.

I would hope we could be more elegant than my hackings.

> > > In some ways I'm more worried about shoe-horning together IO types that
> > > don't go well together. Even serial I/O can have massively different
> > > timing depending on what's on the other end - and we don't
> > > (necessarily) want to hold up the fast I/O until the slow I/O responds.
>
> > Agreed, but "every man for himself" wrecks any semblance of determinism.
> > I'm _not_ saying that way is bad, just that we should probably brainstorm
> > a a little and look at alternatives. Possibly some way to sync the slow
> > to some multiple of the fast, or support IO classes or something.
>
> Mario and I were discussing a synchronisation mechanism, but the
> conversation sort of got stuck - I think that's my fault, sorry Mario!
> (The e-mail is still sitting in my inbox waiting to be answered.)
>
> Basically, the idea was to allow generic synchronisation between all kinds
> of modules (not just I/O), using a Petri-net-like structure. A lot of
> flexibility within relatively simple semantics.

OK, bravely admitting my ignorance for the common good, what's a Petri-net?

> > > > Let's go ahead and class them all as drivers for now. It may not be
> > > > technically correct but people know where to look.
>
> > > My working concept was that
> > > - kernel-space is "drivers", and
> > > - user-space is "io modules".
>
> > Great, anything that makes sense.
>
>
>
> > Since a great deal of making this thing truly useful is supporting
> > everything under the sun, I see making it easy to add IO types as mission
> > critical ( oops, fell into ITspeak, sorry )
>
> True. Often, I expect, it'll be a question of taking an existing, similar
> driver and changing it, but we should definitely make it as easy as
> possible. But no easier - that's the hard part.

It's so hard to encourage support and so easy to discourage it, it may take an Einstien.....

Regards

cww

_______________________________________________
LinuxPLC mailing list
[email protected]
http://linuxplc.org/mailman/listinfo/linuxplc