Creating an interface to variables

C

Chris Carlen

Hi:

I have an embedded system, platform: TI TMS320F2812 32-bit integer DSP.

A module (.c file) contains external (to the funcs in that module)
variables which are used to affect the operation of the program (other
modules). These variables are only read by other parts of the program,
but are to be set by a user interface which consists of an RS-232
terminal command line interface. The command parser for this interface
responds to commands to get or set the variables.

In the interest of good programming practice I desired to have the
parser know as little as possible about the variables. It doesn't set
or read them directly, but through an interface. The parser contains a
table of pointers to variable attribute structures. Each pointer is
associated with a packed string id for the variable. When a match is
made, it passes the pointer (and perhaps a set value) to the variable
attribute struct to the get or set accessor function for the variable.

Here is the interface to the variables. Note, that it only needs to be
general up to the point of handling the machine's native int16 and int32
access sizes.

If you have any better ideas or criticisms, please let me know. I am
not fully happy with the use of void * . I tried to use a union in two
different ways, but not successfully.

Thanks:

--------------------------------------------------------------------
// use-vars.h
// header for module with variables to be interfaced:

// a var may be signed or unsigned (u)int16 or (u)int32
extern uint16 Var1;
extern int32 Var2;
--------------------------------------------------------------------
// vars.h
// header for module which implements interface:

#include "use-vars.h"

#define VAR_RW_OK 0
#define VAR_RW_ERR_RANGE -1
#define VAR_RW_ERR_TYPE -2

/* This defines which type is used at the interface level to pass values
to/from variable read/write access functions, and to define the bounds.
This must be the largest type for which any variable might need to be
accessed: */

typedef int32 VarRW_t;

struct VarAttribs {
void *vptr; // pointer to variable -- tried union unsuccessfully
int vsize; // sizeof() variable
VarRW_t vmin; // lower bound
VarRW_t vmax; // upper bound
};

typedef struct VarAttribs VarAttribs_t;

int var_set(VarAttribs_t *, VarRW_t);
VarRW_t var_get(VarAttribs_t *);

extern VarAttribs_t Var1_attr;
extern VarAttribs_t Var2_attr;
--------------------------------------------------------------------
// vars.c

#include "use-vars.h"
#include "vars.h"

// Here we define the variable attributes:
VarAttribs_t Var1_attr = {&Var1, sizeof(Var1), 1, 10};
VarAttribs_t Var1_attr = {&Var2, sizeof(Var2), -50000, 50000};

// Functions for accessing variables (only set shown):

int var_set(VarAttribs_t *vi, VarRW_t val)
{
if ( val < vi->vmin || val > vi->vmax ) return(VAR_RW_ERR_RANGE);
else {
if ( vi->vsize == sizeof(int16) )
*(int16 *)vi->vptr = (int16) val;
else if ( vi->vsize == sizeof(int32) )
*(int32 *)vi->vptr = (int32) val;
else return (VAR_RW_ERR_TYPE);
}
return(VAR_RW_OK);
}
----------------------------------------------------------------------
// parse.c
// module which accesses the variables

#include "vars.h"

/* if a command is parsed which provides the value v to set the
variable identified "Var1", and the table lookup has returned a
pointer to the Var1_attr structure, then: */

if ( var_set(&Var1_attr, v) != VAR_RW_OK )
deal_with_badness();
// else continue...





--
Good day!

________________________________________
Christopher R. Carlen
Principal Laser&Electronics Technologist
Sandia National Laboratories CA USA
(e-mail address removed)
NOTE, delete texts: "RemoveThis" and
"BOGUS" from email address to reply.
 
J

John Devereux

Chris Carlen said:
Hi:

I have an embedded system, platform: TI TMS320F2812 32-bit integer DSP.

A module (.c file) contains external (to the funcs in that module)
variables which are used to affect the operation of the program (other
modules). These variables are only read by other parts of the
program, but are to be set by a user interface which consists of an
RS-232 terminal command line interface. The command parser for this
interface responds to commands to get or set the variables.

In the interest of good programming practice I desired to have the
parser know as little as possible about the variables. It doesn't set
or read them directly, but through an interface. The parser contains
a table of pointers to variable attribute structures. Each pointer is
associated with a packed string id for the variable. When a match is
made, it passes the pointer (and perhaps a set value) to the variable
attribute struct to the get or set accessor function for the variable.

Here is the interface to the variables. Note, that it only needs to
be general up to the point of handling the machine's native int16 and
int32 access sizes.

If you have any better ideas or criticisms, please let me know. I am
not fully happy with the use of void * . I tried to use a union in
two different ways, but not successfully.

Thanks:

--------------------------------------------------------------------
// use-vars.h
// header for module with variables to be interfaced:

// a var may be signed or unsigned (u)int16 or (u)int32
extern uint16 Var1;
extern int32 Var2;
--------------------------------------------------------------------
// vars.h
// header for module which implements interface:

#include "use-vars.h"

#define VAR_RW_OK 0
#define VAR_RW_ERR_RANGE -1
#define VAR_RW_ERR_TYPE -2

/* This defines which type is used at the interface level to pass
values to/from variable read/write access functions, and to define the
bounds. This must be the largest type for which any variable might
need to be accessed: */

typedef int32 VarRW_t;

struct VarAttribs {
void *vptr; // pointer to variable -- tried union unsuccessfully
int vsize; // sizeof() variable
VarRW_t vmin; // lower bound
VarRW_t vmax; // upper bound
};

typedef struct VarAttribs VarAttribs_t;

int var_set(VarAttribs_t *, VarRW_t);
VarRW_t var_get(VarAttribs_t *);

extern VarAttribs_t Var1_attr;
extern VarAttribs_t Var2_attr;
--------------------------------------------------------------------
// vars.c

#include "use-vars.h"
#include "vars.h"

// Here we define the variable attributes:
VarAttribs_t Var1_attr = {&Var1, sizeof(Var1), 1, 10};
VarAttribs_t Var1_attr = {&Var2, sizeof(Var2), -50000, 50000};

// Functions for accessing variables (only set shown):

int var_set(VarAttribs_t *vi, VarRW_t val)
{
if ( val < vi->vmin || val > vi->vmax ) return(VAR_RW_ERR_RANGE);
else {
if ( vi->vsize == sizeof(int16) )
*(int16 *)vi->vptr = (int16) val;
else if ( vi->vsize == sizeof(int32) )
*(int32 *)vi->vptr = (int32) val;
else return (VAR_RW_ERR_TYPE);
}
return(VAR_RW_OK);
}

[...]

I think you need more than the size to distinguish between different
types of variables. Even with just the types you have it looks dodgy
(signed vs. unsigned), although you might get away with it on your
platform. And I think you will likely need other types in the future
that can't be distinguished using the sizeof.

I too have found this to be a thorny problem and would also be
interested in other approaches. I usually end up using an enumeration
to label the type in the "attributes" structure.

typedef enum
{
BOOL, TRIPLE, QUAD, QUINT, STRING, INT, LONG, TIME8, LINK,
COMMAND, CONFIRM_COMMAND
} SETTING_TYPE;

Then do a switch by setting type.

Over the years I seem to have embellished this stuff, to the point
where I now have a text file (a "resource" file) containing all the
variable definitions, defaults, descriptive text and menu
structure. This gets processed by an awk script to programmatically
generate various C header files.
 
C

Chris Carlen

John said:
I think you need more than the size to distinguish between different
types of variables. Even with just the types you have it looks dodgy
(signed vs. unsigned), although you might get away with it on your
platform. And I think you will likely need other types in the future
that can't be distinguished using the sizeof.

I too have found this to be a thorny problem and would also be
interested in other approaches. I usually end up using an enumeration
to label the type in the "attributes" structure.

typedef enum
{
BOOL, TRIPLE, QUAD, QUINT, STRING, INT, LONG, TIME8, LINK,
COMMAND, CONFIRM_COMMAND
} SETTING_TYPE;

Then do a switch by setting type.


Yeah, I seem to be moving in this direction, having thought about it
further.

Thanks for the input!


--
Good day!

________________________________________
Christopher R. Carlen
Principal Laser&Electronics Technologist
Sandia National Laboratories CA USA
(e-mail address removed)
NOTE, delete texts: "RemoveThis" and
"BOGUS" from email address to reply.
 
C

Clifford Heath

Chris said:
Yeah, I seem to be moving in this direction, having thought about it
further.

Maybe look at how SNMP descriptors work, as this is basically the same problem.
 
A

Alex Colvin

I too have found this to be a thorny problem and would also be
Maybe look at how SNMP descriptors work, as this is basically the same problem.

for quick & dirty, you could associate a scanf/printf string with each
variable.
 
B

Barry Schwarz

Hi:

I have an embedded system, platform: TI TMS320F2812 32-bit integer DSP.

A module (.c file) contains external (to the funcs in that module)
variables which are used to affect the operation of the program (other
modules). These variables are only read by other parts of the program,
but are to be set by a user interface which consists of an RS-232
terminal command line interface. The command parser for this interface
responds to commands to get or set the variables.

In the interest of good programming practice I desired to have the
parser know as little as possible about the variables. It doesn't set
or read them directly, but through an interface. The parser contains a
table of pointers to variable attribute structures. Each pointer is
associated with a packed string id for the variable. When a match is
made, it passes the pointer (and perhaps a set value) to the variable
attribute struct to the get or set accessor function for the variable.

Here is the interface to the variables. Note, that it only needs to be
general up to the point of handling the machine's native int16 and int32
access sizes.

If you have any better ideas or criticisms, please let me know. I am
not fully happy with the use of void * . I tried to use a union in two
different ways, but not successfully.

Thanks:

--------------------------------------------------------------------
// use-vars.h
// header for module with variables to be interfaced:

// a var may be signed or unsigned (u)int16 or (u)int32
extern uint16 Var1;
extern int32 Var2;
--------------------------------------------------------------------
// vars.h
// header for module which implements interface:

#include "use-vars.h"

#define VAR_RW_OK 0
#define VAR_RW_ERR_RANGE -1
#define VAR_RW_ERR_TYPE -2

/* This defines which type is used at the interface level to pass values
to/from variable read/write access functions, and to define the bounds.
This must be the largest type for which any variable might need to be
accessed: */

typedef int32 VarRW_t;

struct VarAttribs {
void *vptr; // pointer to variable -- tried union unsuccessfully

It would be interesting to see what problems you had here. A union of
the four pointer types should be pretty straight forward.
int vsize; // sizeof() variable
VarRW_t vmin; // lower bound
VarRW_t vmax; // upper bound
};

Since you say your variables could be signed or unsigned, it is
possible the vmax may not be able to hold the desired value when vptr
points to a uint32.
typedef struct VarAttribs VarAttribs_t;

int var_set(VarAttribs_t *, VarRW_t);
VarRW_t var_get(VarAttribs_t *);

Similarly, the may be numerous valid uint32 values this function
cannot return. Since you don't show var_get, I wonder how you intend
it to indicate failure. Unless your variables have limited range, any
value returned would be valid int32 value. (One method would be to
pass the address of the address of the target variable to receive the
value as a second argument and have the return value be a status
indicator like it is in var_set. The function could then update the
target variable directly with the value from the source variable.)
extern VarAttribs_t Var1_attr;
extern VarAttribs_t Var2_attr;
--------------------------------------------------------------------
// vars.c

#include "use-vars.h"
#include "vars.h"

vars.h includes use-vars.h explicitly so you don't need to include it
here. It is not a problem now since use-vars.h only declares a few
external objects but you could run into problems as your project
develops. You may want to add include guards to both headers.
// Here we define the variable attributes:
VarAttribs_t Var1_attr = {&Var1, sizeof(Var1), 1, 10};
VarAttribs_t Var1_attr = {&Var2, sizeof(Var2), -50000, 50000};

// Functions for accessing variables (only set shown):

int var_set(VarAttribs_t *vi, VarRW_t val)

Again, how to deal with uint32 values greater than the max int32
value.
{
if ( val < vi->vmin || val > vi->vmax ) return(VAR_RW_ERR_RANGE);
else {
if ( vi->vsize == sizeof(int16) )
*(int16 *)vi->vptr = (int16) val;

How do you know it is an int16 and not a uint16? You really need a
method to identify the type properly (such as an enum member of
VarAttribs_t).
else if ( vi->vsize == sizeof(int32) )
*(int32 *)vi->vptr = (int32) val;
else return (VAR_RW_ERR_TYPE);
}
return(VAR_RW_OK);
}
----------------------------------------------------------------------
// parse.c
// module which accesses the variables

#include "vars.h"

/* if a command is parsed which provides the value v to set the
variable identified "Var1", and the table lookup has returned a
pointer to the Var1_attr structure, then: */

if ( var_set(&Var1_attr, v) != VAR_RW_OK )
deal_with_badness();
// else continue...


Remove del for email
 
D

David Thompson

On Tue, 21 Aug 2007 14:00:55 -0700, Chris Carlen


It would be interesting to see what problems you had here. A union of
the four pointer types should be pretty straight forward.
To declare, yes, but ...
.... initializing it like this would work for at most one type;
otherwise you need C99 designated initializers:
VarAttribs_t Var1_attr = { {.uint16ptr = &Var1}, -3, 42};

<snip other good points>
- formerly david.thompson1 || achar(64) || worldnet.att.net
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top