Subject: glove interface standard

From: [email-masked] (John D Beutel)
Date: Thu, 31 Oct 91 23:32:52 EST

I hope there are at least a few people still interested in this.

I'd like the standard to do as much as it possibly can.
I suggest we make the glove interface standard complex and smart.
Normally I would prefer something simple and elegant, but since
we don't have diffinitive specs on the glove and we don't really
know what we'll figure out how to make it do next, we shouldn't
make a standard that will become obsolete in a few months.

The key is to abstract the glove functionality, so what the
glove does (and what the program expects it to do) is not
linked to a particular method.  Different machines and
different schemes will use different methods, which will
yield different capabilities, but if the standard can put
those capabilities in abstract terms then the program can
ask for what it needs and the interface can worry about how
to do it.

See how you like this for abstraction (any additions?):

        sample rate (Hz)
        x, y, z resolution
        each finger, w/ resolution
        response time (from physical sample to availability of data)
        synch glove to computer (or not)
        buttons, pad, and lo-res joystick data
        call a user function when data arrives (or not)

It's not easy to know how the abstraction should be done.
For example, should the X, Y, and Z values be handled
seperately or together?  Seperately makes more complexity,
but e.g. if someone invents a way of getting better Z resolution
than X & Y resolution then seperate would be better.

It's not just a question of the absolute capabilities of the interface
(software or hardware)---there are tradeoffs.  For example, what if we
find a way to turn off the fingers and get a faster sample rate?  If
the app just wants a 3D coordinate, then this is a good tradeoff.  If
the app needs the fingers too, then it isn't.  This futuristic
interface could do either faster sampling or finger data, but not
both.  So, it can't simply report its sampling rate or finger
resolution because it depends.

That's why I think a negotiation with the interface would be a great
way to do it (as someone already suggested).  Of course, it can't be
too complicated, or who'd want to use it?  One function call would be
best.  The application could give the interface its requirements for
each abstraction:

        minimum acceptable value
        maximum acceptable value
        prefered value
        priority

The interface resolves conflicts the best it can, making tradeoffs
in order of priority, and returns what it can do.
(E.g., you prefered a sample rate of 30 Hz but the best I can do is 17 Hz.
It's within your acceptable range, so here it is.)

If the application doesn't care about an abstraction (e.g.,
doesn't care what the X, Y, Z resolution is) it can say so
(e.g., specify -1 as its value requirements).  Likewise,
if the app doesn't need an abstraction at all (e.g., doesn't
want any lo-res data) then it can say so (e.g., specify 0 as
its priority).  The interface sorts the abstraction requirements
in order of priority, and then attempts to grant each its
prefered value.  If that becomes impossible, then it tries
to get it within the acceptable value range.  If that is still
impossible, then the interface could either do its best,
or sort the requirements in a different order than their priority
and try again.

The prefered value of a high priority may make impossible the
acceptable value of a lower priority, but if the lower priority
is satisfied first then the higher priority may still be able
to be within the acceptable range.  For 7 abstractions,
the 7! possible orders of priority are about 3000.
For 9 abstractions, the 9! orders go up to the impractical
area of 350,000.  So, doing all possible orders of
priority may be impossible, but it may be easy to swap a few of the
ones that the standard knows will make a difference.

Whether or not the interface implementation is smart enuf to do this
doesn't really matter.  If the interface doesn't try different orders,
or if it does but it still can't satisfy the application's request,
then it just returns what it can do.  The skill of the tradeoffs
that the interface makes---and its raw capability---will increase
with time, but at least right now if the interface can't do it,
it can say so thru the standard, and the app can decide for itself
whether it's good enuf or not.

If the interface can't satisfy the app's request, the app can always
make another request with looser constraints.  I doubt that app's
will do this very often---that's the idea of specifying an acceptable
range and priority; let the interface do all the work trying to
get it right.  In most cases, the app makes one call to the interface,
and the it does the best that it can, (initializes the glove?),
and returns what it's going to do (e.g., the finger data will range
from 0 to 3).  The app uses the return values (instead of constants)
to interpret the data.  So, if you wire your glove's fingers directly
to an IO port to get faster sampling and better resolution,
the interface you write returns that its finger data will range
from 0 to 255, and the application that only needs 0 to 3 will work
just as well with your better data.

Passing the abstraction requests via dynamic means (i.e., "tags")
also sounds like a good idea (someone else suggested earlier).
That way, if other abstractions are added later (e.g., a glove with
two X,Y,Z coordinates) then programs could request these new abstractions
from old interfaces and still compile.  If we put the standard names
in a datastructure, then the compiler won't work with the
older .h interface files, or the function call's arguments
will be wrong.  If we use "tags", then the interface can ignore the
things it doesn't know, or act intelligently by telling the app that
it can't do those things.  The app can decide for itself whether it
really needs that extra X,Y,Z coordinate or not.  Some apps may
really need it, and won't be written to be downwardly compatable.
Other apps may not need it---it may be strictly an option or a fringe.
For those apps, it would be a shame to not be able to use them
with older interfaces or simpler hardware just because the names
were hardcoded and the compiler won't compile the new names.

Using tags will make the interface a little more complicated, but
not significantly so, especially considering that the support
functions only need to be written once.  I wouldn't mind writing
them for the ST, and they'd be practically the same on any computer.
Here's an example of what the code might look like:

-------------------------- in stdglove.h -------------------------
struct negotiate_glove {
        char    *name;          /* the tag, standardized */
        long    minimum,        /* acceptable range, std bit length */
                preference,     /* prefered value */
                maximum;        /* acceptable range */
        int     priority;
        long    offer;          /* return value of what interface can do */
                                /* 0 == not available */
        /* double the number of elements here to allow for signed ranges? */
        /* e.g., -127..128 instead of just 255? */
}

--------------------------- in app.c ------------------------------

struct  negotiate_glove gn[6] = {
        {"rate", 1, 14, 30,     1, 0},
        {"sync", 1, 1, 1,       2, 0},
        {"xyz", 10, 255, 1000,  3, 0},
        {"finger1", -1, -1, -1, 4, 0},
        {"lores", 0, 0, 0,      0, 0},  /* actually, maybe for those */
                                        /* things we don't want it would */
                                        /* be easier to just not ask for */
                                        /* them. */
        {"end"}
}

main()
{
        init_glove( gn);

        if( get_offer( gn, "rate") != 14)
                fprintf( stderr, "warning: optimum sample rate unavailable");

        /* etc... */
}

We could include an option to init_glove so that if it
can't satisfy the app's request within the given acceptable values,
then it prints a nice error message and aborts,
so the app doesn't even have to worry about checking
the return values if it doesn't want to.

The tags do make the interface more complicated, but
not significantly so.  They will slow the initialization
a little, but it's not noticable.  They will slow the
retrieval of the sample data a little, but only a few
microseconds (unless someone can come up with a clever
macro for this?  I haven't thought much about it.)
Milliseconds are significant, but what's a few microseconds
at 30 Hz?

Please think about whether a complex standard like this
would be good for this glove environment, and express your opinion.

--
J. David Beutel  11011011  [email-masked]  "I am, therefore I am."