Dev (#6) - API changes (#19) - Message List

API changes
 unsolved

Here are my current ideas for the the libwiimote API, addressing interface modes, thread complexity, and configuration:

  1. Drop the event queue, use a pipe instead.
  2. Provide three interfaces to that pipe (a and b are mutually exclusive)
    1. Blocking: int wiimote_get_mesg(wiimote_t *wiimote, int *mesg_count, union wiimote_mesg **mesg[]), blocks on the pipe, and fills in *mesg_count and *mesg
    2. Callback: remove the callback parameter from wiimote_connect, add a wiimote_set_callback function that, when called, sets up a thread (much like the current dispatch thread) that issues the callbacks.
    3. Polling: add a flags parameter to wiimote_connect, or a separate function that enables state tracking. State is retrieved through int wiimote_get_state(wiimote_t *wiimote, wiimote_state *state).
  3. wiimote_read and wiimote_write duplicate the pipe, and wait for their own responses from the wiimote (currently, int_listen receives the response and signals wiimote_read or wiimote_write) - this will significantly reduce the complexity of the thread model and make disconnect and cleanup easier.
  4. Add flags to wiimote_connect (e.g. continuous output, repeat identical buttons, various). Add wiimote_enable, wiimote_disable to change flags after connect.
  5. Drop the int *id from wiimote_connect, add another function to get it. Move the id parameter to the callback to the end, effectively making it optional (is this portable?). This removes all multiple wiimote considerations from apps using a single wiimote.
  6. Drop stdint types from externally visible flag parameters to ease future backward compatibility.

So the API would look something like this (not all functions listed):

/* Connection */
int wiimote_connect(bdaddr_t *bdaddr, int flags);
int wiimote_disconnect(wiimote_t *wiimote);
int wiimote_get_id(wiimote_t *wiimote);
int wiimote_enable(int flags);
int wiimote_disable(int flags);
/* Operations */
int wiimote_command(wiimote_t *, enum wiimote_command command, int flags);
int wiimote_read(wiimote_t *wiimote, int flags, uint32_t offset, uint16_t len, void *data);
int wiimote_write(wiimote_t *wiimote, int flags, uint32_t offset, uint16_t len, const void *data);
/* Blocking Interface */
int wiimote_get_mesg(wiimote_t *wiimote, int *mesg_count, union wiimote_mesg **mesg[]);
/* Callback Interface */
int wiimote_set_callback(wiimote_t *wiimote, wiimote_mesg_callback_t *callback);
/* State/Polling Interface */
int wiimote_get_state(wiimote_t *wiimote, wiimote_state *state);

Comments? Suggestions?

  • Message #79

    Also, should the wiimote_state store the last messages of each type, or do something like

    struct wiimote_state {
    int buttons;
    int acc_x;
    int acc_y;
    int acc_z;
    struct ir_src src[4];
    /* etc */
    }
    

    I like the latter - seems more intuitive.

    • Message #92

      Why not just add an argument to wiimote_get_mesg() which tells if it should block or not and use the wiimote_mesg struct as it is?

      In practice I dont think the blocking function will be used much, at least not considering that most wiimote application will run in real time.

      Another thing I was thinking about is that the wiimote is running at 100Hz. which makes it somewhat not obvious how to handle new packages in a polling situation. If the app is running with a higher framerate than that, it will poll the same message several times. If its running slower, it will miss messages. To make sense of this, each message should be tagged with a timestamp (or some unique counter) so the application can id each message and take precations.

      There is always a chance of underflow/overflow depending on the applications polling speed. I dont like the idea that some messages can be missed because the app is to slow/unlucky. Obviously running at a constant 30fps will result is lots of missed packages, but a temporary slowdown should not be a problem. So some kind of buffer is needed to fix this and using pipes seems to be a great way to handle this. Although pipes has a size limit. I just read that Linux >2.6.11 has a 64kb pipe size which is should be good enough. Earlier versions used 4096bytes apparently.

      • Message #93

        I like the block flag. Perhaps message and state interfaces would be better names for than blocking and polling.

        I think I prefer the timestamp to the id - it yields more information.

        It occurred to me that it may not be clear that a single call to wiimote_get_mesg does not retrieve all messages - it retrieves only a group of them (a group is a series of messages triggered simultaneously, i.e. by a single bluetooth packet). This goes for callback invocations as well.

  • Message #80

    I would like to have a userdata parameter for the callback. I have run into awkward situations where a void* userdata would be very nice on a couple of occasions. An API like:

    typedef void wiimote_mesg_callback_t(int mesg_count, union wiimote_mesg* mesgs[], int id, void *userdata);
    /* Callback Interface */
    int wiimote_set_callback(wiimote_t *wiimote, wiimote_mesg_callback_t *callback, void *userdata);
    

    Or perhaps id and userdata could be multiplexed. If the userdata passed to wiimote_set_callback is NULL, the system passes the id instead. Or if the id can be extracted from the wiimote_t* than passing the id separately is redundant and it could be dropped entirely.

    The reason I think this is important is that the when you are interfacing a C++ class or other complex object to the wiimote you end up having to manage a lookup table of object pointers that allow the callback to access the object. This is a pain and the void* userdata is very standard for callback APIs (GTK for example).

    Just a thought.

    -Arthur

    • Message #81

      You raise a good point about getting id's from wiimote_t's. How about just passing the wiimote_t to the callback, and adding wiimote_set_user and wiimote_get_user? It gives you a user data field, id, keeps the prototype short, and you no longer have to declare the wiimote_t global to access it from the callback.

  • Message #96

    Take a look at branches/api_overhaul - it's coming along nicely, and will probably replace the trunk within the week unless someone finds something grotesquely wrong. It's a large rewrite, though, so I'd appreciate as much feedback as possible. Still got a couple of changes to the plugin architecture, but I think that's it.

    Then on to Python support...

    • Message #100

      The branches/api_overhaul code has been merged into trunk. The aforementioned possible changes to the plugin architecture will be put off until I see how they will affect Python support. (Currently, plugins get an array of pointers to messages, although regular callbacks get an array of messages. I'd prefer the latter across the board, although it'll be a small performance hit to implement in wminput). Also, still need to add a timestamp to message arrays. Possibly to state as well - a last-update time might be useful.

      • Message #101

        Hi,

        I'm using cwiid in Python currently. The wrapper isn't complete, and it uses the old API (since I didn't know there was a newer one), but I'd be willing to port it over to the new one and send what I have to you if you're interested.

        • Message #102

          Extremely interested - I was just about to start on the SWIG wrapper. If you could, go ahead and attach what you have to PythonWrapper (so I can go ahead and start working on the C side), and update it when you have a chance. Thanks!

          Let's move the python discussion to the Python Support thread.

  • Message #24317

    Hi, I am wondering if it is possible to have an additional parameter at cwiid_wiimote_t *cwiid_open(bdaddr_t *bdaddr, int flags, long timeout);

    if maintaining backwards comp i would suggest: cwiid_wiimote_t *cwiid_open_timeout(bdaddr_t *bdaddr, int flags, long timeout);

    and that cwiid_open just calls that function with the timeout 5

    cwiid_wiimote_t *cwiid_open(bdaddr_t *bdaddr, int flags) {

    return cwiid_open_timeout(bdaddr_t *bdaddr, int flags, 5);

    }

    greets

Attachments

No attachments created.