the plc_set() function

J

Thread Starter

Jiri Baum

Hello,

here's the first installment of ``better living through documentation''.
Please ask questions...


The plc_set() function sets a point to a particular value. Usage:

plc_set(data_point, value);

Where:
data_point is the handle to the point, and
value is an unsigned value (0-32 bits depending on the point).

As in a PLC, the value is buffered (in `private map') and doesn't appear to the outside world (or the rest of the lPLC) until plc_update() is called.

The function will only use as many bits of value as fit into the data_point, the rest will be ignored.

So, assuming we have point handles foo, bar and baz, we can write:

/* turn foo on */
plc_set(foo, 1);

/* invert bar */
plc_set(bar, ~plc_get(bar));

/*
* LD BAR
* AND BAZ
* OUT FOO
*/
plc_set(foo, plc_get(bar) & plc_get(baz));

Since we have the buffering, we can also do:

plc_set(foo, 0);
if (...)
plc_set(foo, 1);
if (...)
plc_set(foo, 1);

This won't cause any glitches, because the 0 doesn't actually appear to anything until the end of our cycle (when we call plc_update()).

If we have a handle xyzzy which is 8-bit, we can do:

/* increment (wraps around at 256) */
plc_set(xyzzy, plc_get(xyzzy)+1);

Note that this trick cannot be used with 32-bit words. With 32-bit words we have to:

/* increment with wrap-around */
if (~plc_get(plugh))
plc_set(plugh, plc_get(plugh)+1);
else
plc_set(plugh, 0);

Any other mathematical expressions as usual:

/* scaled decaying average */
plc_set(plugh, (9*plc_get(plugh) + scaling*plc_get(xyzzy) + 5)/10);


If you are writing a library, remember that the user might pass in any size handle - even zero-bit. Normally you should cope with this by keeping any important information in C variables, like this:

/* decaying average */
plugh_val = (9*plugh_val + scaling*plc_get(xyzzy) + 5)/10;
plc_set(plugh, plugh_val);
/* ... other code that uses plugh_val ... */

You could also check the size of the handle, if it absolutely doesn't make sense to pass a zero-bit handle (or 1-bit handle etc).


The data_point must be a valid point handle. If it is invalid, the program will exit with an error message (this needs fixing - there should be
provision for an error callback/return - so it may change).

It is permissible to write any point, even read-only ones. Such changes will persist until the next plc_update(), at which point they are discarded and a new value is fetched. Using this is a bad programming practice.


How it works: (lib/gmm/gmm.c lines 629-637)

This is basically a two-liner function. The first line calls a macro to check whether the data_point p is valid.

The second line changes the particular bits in the private map, by combining those bits of the map that shouldn't be changed (~pp.mask) and
the given value, shifted appropriately and masked.

That is:
word of private map =
word of private map & bits that shouldn't be changed
plus shifted value & bits that should be changed

The macro "pp" expands to "p", typecast to the private point-handle type.

Jiri
--
Jiri Baum <[email protected]>
What we do Every Night! Take Over the World!

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

Gilles Allard

<snip>
>It is permissible to write any point, even read-only ones. Such changes
>will persist until the next plc_update(), at which point they are discarded
>and a new value is fetched. Using this is a bad programming practice.
<snip>

This is a bad programming practice except during debugging where we have to include some simulation code to generate data for inputs from the field.

Gilles

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

> <snip>
> >It is permissible to write any point, even read-only ones. Such changes
> >will persist until the next plc_update(), at which point they are discarded
> >and a new value is fetched. Using this is a bad programming practice.
> <snip>

> This is a bad programming practice except during debugging where we have
> to include some simulation code to generate data for inputs from the
> field.

Actually, I'd recommend writing the simulator as a separate program which runs instead of the I/O modules... That way you don't have to modify your
control program when you switch from simulator to the real thing.

But I can see where you'd just want to hack something into your program, quickly.

Obviously, `bad programming practice' is not an absolute term. There are situations where using one will simplify the rest of the program so much
that it is warranted. But it is something to be avoided.

Jiri
--
Jiri Baum <[email protected]>
What we do Every Night! Take Over the World!

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