Start

C

Thread Starter

Curt Wuollet

Hi all,

I was so excited, I had to leap upon this small and fragile bit of consensus right away and start at a level it's hard to argue about. For the I/O work I have been doing, I am using the simplest possible map. Basically only setting the data types:

struct map
{
unsigned short ins[256];
unsigned short outs[256];
unsigned int ctr[128];
float algi[128];
float algo[32];
int flags;
} lmap;

Those of you who looked at the map display code will see that I have split ins and outs and added an array for counters so each array has only
one representation. ins and outs hold 4096 points each as Linux shorts are 16 bits.
128 32 bit counters as ints.
128 analog ins as IEEE ? floats;
32 analog outs as IEEE ? floats;

Proposed that atributes be added as arrays with a matching index to their corresponding member.

Issue: should we store dio as bits or ints?
My feeling is that we are trading the cost of copying a map verses doing bitwise operations. Bitwise ops in C are very fast. OTOH we wouldn't be copying maps very often. I opted for small.

Could we limit the debate to basics?

Regards

cww


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

I guess I am a little confused on the issue of "analogue in/out". Are we treading into new water here? Every analogue system I have ever dealt with expressed it's value digitally (inside the PLC anyways). Conversion to Floating point rarely happened (usually multiplied digital in by a correction factor that implied a fixed position decimal point). While maybe not as accurate, it
certainly was significantly faster than doing the floating point math.

Ins and Outs should be bitmaps as far as I am concerned. Each 'short' represents 16 points of i/o.

Counters should be expressed as 'long', not 'int'. Int on some platforms is 16 bit, not 32 bit.

Why not go with 128 points of analogue output as well. What the heck, memory is cheap nowadays! This "costs" an extra 384 bytes of overhead.

It is a good start though! I Like it.

Ron Gage - Saginaw, MI
([email protected])


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

Johan Bengtsson

I think using the bits is the best solution counting everything the code for checking if a byte is 0 or !=0 would take the same as (or perhaps longer than) checking if a bit is 0 or if the bit mask is set up before the check. (ie, make the mask part of the byte code to execute, not the bit number)

example:

switch (*op++)
{
case 0: //LD
{
register unsigned short mask=*((unsigned short *)op)++;
if (map.ins[*op++]&mask)
//...

}
}

(would be easiest if the operations actually is located in an array of unsigned short since that would require no conversion....) The code should be very efficient if the compiler is doing it's job


/Johan Bengtsson

----------------------------------------
P&L, the Academy of Automation
Box 252, S-281 23 H{ssleholm SWEDEN
Tel: +46 451 49 460, Fax: +46 451 89 833
E-mail: [email protected]
Internet: http://www.pol.se/
----------------------------------------

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

Curt Wuollet

[email protected] wrote:

> I guess I am a little confused on the issue of "analogue in/out". Are we
> treading into new water here? Every analogue system I have ever dealt with
> expressed it's value digitally (inside the PLC anyways). Conversion to Floating
> point rarely happened (usually multiplied digital in by a correction factor that
> implied a fixed position decimal point). While maybe not as accurate, it
> certainly was significantly faster than doing the floating point math.

We are dealing with a platform that has dedicated floating point hardware now. I kinda like the idea of seeing real scaled quantities when I look for values in the map and doing math and comparisons that way. But, if that's the practice
we can do it that way. An int would hold the counts from any D/A or A/D I've seen. Ignore the scale factors if you want to work with raw counts. Scales would be init'ed by I/O to accomodate hardware that can change on the fly.

> Ins and Outs should be bitmaps as far as I am concerned. Each 'short'
> represents 16 points of i/o.
>
> Counters should be expressed as 'long', not 'int'. Int on some platforms is 16
> bit, not 32 bit.

OK

> Why not go with 128 points of analogue output as well. What the heck, memory is
> cheap nowadays! This "costs" an extra 384 bytes of overhead.

OK

> It is a good start though! I Like it.
>
> Curt Wuollet <[email protected]> on 05/02/2000 08:36:24 PM
>
> Please respond to [email protected]
>
> To: [email protected]
> cc: (bcc: Ron Gage/US/GM/GMC)
> Subject: LinuxPLC: Start
>
> Hi all,
>
> I was so excited, I had to leap upon this small and fragile bit of
> consensus right away and start at a level it's hard to argue about.
> For the I/O work I have been doing, I am using the simplest possible
> map. Basically only setting the data types:

**** For reference, on x86 Linux
char = 8 bits
short = 16
int = 32
long = 32
float = 32
double = 64

struct map
{
unsigned short ins[256];
unsigned short outs[256];
unsigned long ctr[128];
int algi[128];
float ai_scale[128];
int algo[128];
float ao_scale{128]
unsigned int flags;
} lmap ;

Scale factors in the map, not application specific.
Questions: Are analogs signed ? What about 64 bit machines (alpha,IA64)?

cww


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

Johan Bengtsson

I may not understand your question about sizes.
There is a cost using a too big size: memory
increased emory usage may decrease speed due to fewer cache hits There is sometimes a cost using unaligned adresses: speed, since some architectures may have to read two times from the memory (if it is possible at all).

After thinking one step further I realized the code below may not even work on all platforms :-( (it does work on intel platforms, but even on intel it will probably be faster if the program array is of type unsigned short however)


/Johan Bengttson

----------------------------------------
P&L, the Academy of Automation
Box 252, S-281 23 H{ssleholm SWEDEN
Tel: +46 451 49 460, Fax: +46 451 89 833
E-mail: [email protected]
Internet: http://www.pol.se/
----------------------------------------

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

Simon Martin

long and int are identical only on some processors/OSes. For example 8086, DOS, int = 16 bits, long = 32.

It is more portable to call a long a long, an int an int and keep them separate

Debian GNU User
Simon Martin
Project Manager
Isys
mailto: [email protected]

Chaos reigns within.
Reflect, repent, and reboot.
Order shall return.

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

Gilles Allard

Hi Curt (and other on the list)
It seems to me that analogs should be treated as an object (ie a structure)

An analog input should have a few characteristics:
- the raw data (coming from the A/D converter)
- the range (or scaling factor)
- options (bipolar, 20% offset (ie 4-20mA), filter)
- filter time-constant
- the out-of-range signal (ie below 4mA or over 20mA)
- the scaled value

An analog output should have a few characteristics:
- the raw data (to be transmitted to the field)
- the scaled value
- the range
- options (ie 4-20mA or bipolar)

Analog should have a different handling (compared to discretes). If you only handle raw data (ie the data to be transmitted to the I/O module, it means that user programs will have to handle the chores of conversions (from 4-20mA to scaled value or from raw to filtered value).If you stay with the concept that a map item is a raw field
datum, then someday we will have to add a layer (ie reduce performance) and that layer will have to be shared.

Jiri Baum wrote:
>Then we get the points we want:
>
> plc_pt x1,y2,z3;
>
> x1=plc_pt_by_name("X001");
> y2=plc_pt_by_name("Y002");
> z3=plc_pt_by_name("Z003");

Can "plc_pt" be a structure (or a union)?

Gilles


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

Curt Wuollet

I ask a question about data types and get correct answers about portability and in core alignment. It was a trick question and answerable by inspection of (probably) <types.h> So, what do
the <> mean.?

My point is:

long = int isn't portable.

Yes, but under the covers, it builds the same code. And array indexing becomes pointer math. And simple, clear, readable code optimizes to
the same instructions as dense, obscure, code. And where it doesn't, we have Johan ;^). And if you get 10 people carried away with unions
or worrying about alignment, 3 of them won't outguess the compiler. If we all are to work on the same body of code, cranky old hackers will
outnumber computer scientists and people won't hack code they don't grok right away. And you'll never know why. Half the folks who want to
contribute don't even have a Linux box set up yet, but want to learn on a project that is relevent and meaningful and approachable to them.
I can work with Ron's code, barely ;^) and I _do_ care about efficiency, Johan, and I can dump the assembler and count cycles. And that makes, what, 5 of us?

And I have yet to see anyone modify another persons code. And yes, I am guilty as the next guy. I _will_ make my code accessable to the
majority of coders, and, I will throw mine away and work with yours if it is better or you are farther along and I can read it. And I will admit
if it confuses the hell out of me, because if I have problems, there may be one or two readers even dumber than I am. I am not so much disturbed by the lack of code as the fact that we haven't found a way to work together and attract more coders. If we get enough coders, working together, and I get left in the dust, that's fine as long as it works. I can amuse myself and burn all the time I have available with hardware and drivers. Until then I suggest we try to pull people in with code they can grok. And it wouldn't hurt to work on the same program.

Regards,

cww

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

Curt Wuollet

> > > For the I/O work I have been doing, I am using the simplest possible
> > > map. Basically only setting the data types:
> >
> > **** For reference, on x86 Linux
> > char = 8 bits
> > short = 16
> > int = 32
> > long = 32
> > float = 32
> > double = 64
> >
> > struct map
> > {
> > unsigned short ins[256];
> > unsigned short outs[256];
> > unsigned long ctr[128];
> > int algi[128];
> > float ai_scale[128];
> > int algo[128];
> > float ao_scale{128]
> > unsigned int flags;
> > } lmap ;
> >
> > Scale factors in the map, not application specific.
> > Questions: Are analogs signed ? What about 64 bit machines (alpha,IA64)?

> Hi Curt (and other on the list)
> It seems to me that analogs should be treated as an object (ie a structure)

I agree that we need to keep that information and not cooked into the application. I'm not sure if we want to keep static data in the map or if it properly belongs to setup/configuration, the _scale arrays are a place holder till we talk about it.. hang in there, we'll get there.

> An analog input should have a few characteristics:
> - the raw data (coming from the A/D converter)
> - the range (or scaling factor)
> - options (bipolar, 20% offset (ie 4-20mA), filter)
> - filter time-constant
> - the out-of-range signal (ie below 4mA or over 20mA)
> - the scaled value
>
> An analog output should have a few characteristics:
> - the raw data (to be transmitted to the field)
> - the scaled value
> - the range
> - options (ie 4-20mA or bipolar)

Yes and there will be other idiosyncrasies for individual devices.

> Analog should have a different handling (compared to discretes). If you only handle
> raw data (ie the data to be transmitted to the I/O module, it means that user programs
> will have to handle the chores of conversions (from 4-20mA to scaled value or from
> raw to filtered value).If you stay with the concept that a map item is a raw field
> datum, then someday we will have to add a layer (ie reduce performance) and that layer
> will have to be shared.

As mentioned, I would prefer that the driver deal with that and what's in the map would be the form directly usuable for formulas, comparisons,
etc. The driver _has_ to be aware of all that anyway, why duplicate? We'll address each item in turn.


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

Harald Albrecht

Curt Wuollet <[email protected]> wrote:
> I ask a question about data types and get correct answers about
> portability and in core alignment. It was a trick question and
> answerable by inspection of (probably) <types.h> So, what do
> the <> mean.?

Is that a second trick question? ;-)

> My point is:
> long = int isn't portable.

Just think of Alpha cpu's, where longs are 64 bits wide and ints are just 32 bits. It's really funny to see quite some code going down the pipe because of passing pointers as ints around and thus killing the most significant 32 bits. That's the reason why Linux/AXP maps the first 4 gig of logical address space as not available and only begins allocating real RAM at logical addresses
larger than 2**32.

My 2 cents (remember, I'm from Euro land, so this is currently a rather cheap comment): introduce a new typedef, like plc_packedbits and use something like a config.h to define it
accordingly to the system or fall back to the default of int in case the system is not known. On glibc2 systems, <sys/bitypes.h> comes to my mind, which defines things like int32_t etc. On larger systems, use long, where appropriate.

Harry


--
Harald Albrecht
Chair of Process Control Engineering
Aachen University of Technology
Turmstrasse 46, D-52064 Aachen, Germany
Tel.: +49 241 80-7703, Fax: +49 241 8888-238
email: [email protected]-aachen.de

_______________________________________________
LinuxPLC mailing list
[email protected]
http://linuxplc.org/mailman/listinfo/linuxplc
 
> Jiri Baum wrote:
> >Then we get the points we want:
> >
> > plc_pt x1,y2,z3;
> >
> > x1=plc_pt_by_name("X001");
> > y2=plc_pt_by_name("Y002");
> > z3=plc_pt_by_name("Z003");

Gilles Allard:
> Can "plc_pt" be a structure (or a union)?

It is a structure. From memory, its public definition is:

struct {
char valid;
char private[7];
} plc_pt

In other words, it's an opaque handle.

Its private definition is, well, private. Again, from memory:

struct {
short int magic;
short int ofs;
int mask;
} plc_pt_private


I have to check this into the CVS, but I was hoping to get enough of it implemented first that it'd make sense. The public definition is already in the CVS, anyway:

http://www.linuxplc.org/cgi-bin/viewcvs.cgi/~checkout~/smm/smm.h


Jiri
--
Jiri Baum <[email protected]>
Windows is not popular. Windows is *widespread*. Linux is popular.

_______________________________________________
LinuxPLC mailing list
[email protected]
http://linuxplc.org/mailman/listinfo/linuxplc
 
Curt Wuollet:
> > My point is:
> > long = int isn't portable.

Harald Albrecht:
...
> My 2 cents (remember, I'm from Euro land, so this is currently a rather
> cheap comment): introduce a new typedef, like plc_packedbits and use
> something like a config.h to define it accordingly to the system or fall
> back to the default of int in case the system is not known.

My suggestion would be to use the names i32 and u32 where you care about the length of the integer.

While we are on linux/i386, these can be typedefed to int and unsigned int. When someone gets around to compiling the thing for an Alpha, they can fix the typedefs appropriately then.

(Hmm, I see I've sort-of automatically done that while writing smm.h without even thinking about it. Then I find myself slipping between the two
notations, which is bad.)

Jiri
--
Jiri Baum <[email protected]>
Windows is not popular. Windows is *widespread*. Linux is popular.

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

Johan Bengtsson

If I have got all this correct the following is true:
char = always 8 bits
short = always 16 bits
long = always 32 bits (at least almost always <grin>)
int = one of 8 16 or 32 bits, or perhaps bigger in the future, it is supposed to be the size of a native register in the processor
any pointer type is supposed to be the size of the native pointer in the processor, for intel processors this have been quite a trick because there have been two sizes at the same time (near and far pointers, being 16 and 32 bits respectively), this is history now however.

That basically means (for portable code):
Never assume an int have any certain size
Never assume a pointer have any certain size
what the heck are the int type then ever used for? Well in some cases you want to use the native size becase that one is supposed the be one of the fastest sizes handled by the processor, and yes the type char might be slower. You may even want to make the variables bigger on a bigger processor - correctly written this means a recompile and voila you handle numbers with the now bigger size correctly and efficient.


/Johan Bengtsson


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