Skip to main content
Up and Coming
April 25, 2013

Basic Linux Rift library with OpenGL in C

Ok, don't get too excited. This is a very simple C port of the SDK 1.5 library. I did this mostly to satisfy my own curiosity, but if there is enough interest, I'm willing to make it a more complete project.

Right now all it will do is connect to the Rift, open up a GL window, and move an arrow around to follow the HMD tracker. Now that the new SDK is out, there are GL shaders which I'll work into the simple demo scene for the next pass.

I'm still playing around with this, but tf there is interest, I can put the code up in a private git repo so others can contribute.

Enjoy

-nsb

    73 replies

    Up and Coming
    April 25, 2013
    The linuxdemo test program has this problem:
    https://forums.virtualbox.org/viewtopic.php?f=3&t=30964

    So apparently it is not VirtualBox compatible...

    My "C minimal app" test program starts emitting this message about twice per second, as soon as it does a sleep() call (which never returns):
    sendSensorKeepAlive: Invalid argument
    This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
    nsbAuthor
    Up and Coming
    April 25, 2013
    "geekmaster" wrote:
    The linuxdemo test program has this problem:
    https://forums.virtualbox.org/viewtopic.php?f=3&t=30964

    So apparently it is not VirtualBox compatible...


    Interesting - seems to be a glut issue. I guess I could switch to something other than glut - SDL maybe? I presume you tried the fix that thread suggested:

    LIBGL_ALWAYS_INDIRECT=1 ./myGlutProgram


    "geekmaster" wrote:

    My "C minimal app" test program starts emitting this message about twice per second, as soon as it does a sleep() call (which never returns):
    sendSensorKeepAlive: Invalid argument


    Hmm...the thread is trying to send a keepalive packet to the Rift every 500ms or so. If you don't do this, the Rift stops sending data back after 5000 samples. That error seems like the HID file descriptor is getting closed or something, but I'd have to look at your code to be sure.
    Up and Coming
    April 25, 2013
    "nsb" wrote:
    Heh! Yes, it's very GL1.0 - that's what happens when you play with GL for awhile and then get sidetracked for a decade writing embedded firmware.

    I agree about pthreads - I left it in there for initial simplicity, but if this gets any traction, I'll either make a _t version of the lib or make it a configure option.

    For added portability, it could probably use this for the HID stuff: http://www.signal11.us/oss/hidapi Looks like their BSD license would be compatible.


    I was in the same boat. I skipped graphics for the whole PC 3D hardware revolution, up until a couple of years ago. :) I like GLES2/OGL4 way of doing things for applications... not so good for little tests though -- which 1.0 is great for!

    I started by looking at hidapi... now I wish I made notes about why I shied away from it. My recollection is that there were reports of more frequent problems with Windows. Looking at it again, it's at a better level of abstraction for sensor devices (bluetooth support). Hmm...

    I like what you have. Nice and simple, yet functional -- it's all there. I'm looking over bits as I type. ;) I think I'm sold. Portability can be improved in time, threads being optional. I also like that there's really only one necessary malloc -- for the Device, which could easily be changed to support application-provided memory or allocator. The world needs more embedded system programmers. :)

    And, of course, I just realized my own recent experiments were succeeding but I was erroneously identifying an error -- because libusb's "control" interface returns a positive transfer size on success rather than the "interrupt" interface which is only zero on success. So I could potentially add libusb support if desired at sometime, though hidapi might be better.

    On the graphics side of things I was unsure what to provide -- implementation is very application specific. Even for a reference implementation of stereo rendering with distortion... what version/style of OpenGL would one choose? I guess "2.0" -- shaders but still using GL matrices. Did you have thoughts on this? Really, the hardware abstraction for of the display amounts to data: the display properties.
    nsbAuthor
    Up and Coming
    April 25, 2013
    "atavener" wrote:
    I started by looking at hidapi... now I wish I made notes about why I shied away from it. My recollection is that there were reports of more frequent problems with Windows. Looking at it again, it's at a better level of abstraction for sensor devices (bluetooth support). Hmm...


    I'll mess around with it a bit more - if it looks like it'll do the trick then it might be worth incorporating for a more general solution.

    "atavener" wrote:

    I like what you have. Nice and simple, yet functional -- it's all there. I'm looking over bits as I type. ;) I think I'm sold. Portability can be improved in time, threads being optional. I also like that there's really only one necessary malloc -- for the Device, which could easily be changed to support application-provided memory or allocator. The world needs more embedded system programmers. :)


    Yeah, until recently, my smallest device had 128 bytes of RAM. Now I've migrated to an embedded Linux platform and I'm positively drowning in 128MB. It tends to make one stingy when it comes to allocation. :)

    "atavener" wrote:

    On the graphics side of things I was unsure what to provide -- implementation is very application specific. Even for a reference implementation of stereo rendering with distortion... what version/style of OpenGL would one choose? I guess "2.0" -- shaders but still using GL matrices. Did you have thoughts on this? Really, the hardware abstraction for of the display amounts to data: the display properties.


    I think that for the people who actually want a place to start on a C/C++ Linux project, starting with more up-to-date GL techniques would be best. Anyone else is likely only interested in linking the C tracker library to another language, so the rendering demo isn't so important for them. I'm all for jumping past 2004 at least :)
    Up and Coming
    April 26, 2013
    I only want tracker data and nothing else, just like the MinimalOculusDemo provides.
    I am having problems with "sendSensorKeepAlive: Invalid argument" displaying about once per second now, even when I call "waitSampleDevice(dev,-1)".

    If I call "sampleDevice(dev)", it returns FALSE (failed).


    // ==========================================================================
    // RiftTest - Reading RiftDK head tracker data with pure C
    // Show RiftDK display name and head tracker values.
    // ==========================================================================
    // Revision History, Last Change First:
    // YYYY/MM/DD Author Description
    // ========== ==================== ==========================================
    // 2013/04/22 Geekmaster First release version.

    #include "stdio.h"
    #include "OVR.h"

    Device *dev; // Oculus Rift Device

    int main(int argc, char* argv[]) {

    dev = openRift(0,0);
    if(!dev) {
    printf("Could not locate Rift\n");
    printf("Be sure you have read/write permission to the proper /dev/hidrawX device\n");
    return -1;
    }

    printf("Device Info:\n");
    printf("\tname: %s\n", dev->name);
    printf("\tlocation: %s\n", dev->location);
    printf("\tvendor: 0x%04hx\n", dev->vendorId);
    printf("\tproduct: 0x%04hx\n", dev->productId);

    // Fire up Sensor update thread
    runSensorUpdateThread(dev);

    while (1) {
    if (sampleDevice(dev)) {
    printf("A: %+f %+f %+f %+f\n", dev->A[0], dev->A[1], dev->A[2], dev->A[3] );
    printf("Q: %+f %+f %+f %+f\n", dev->Q[0], dev->Q[1], dev->Q[2], dev->Q[3] );
    } else {
    printf("sampleDevice() failed\n");
    }
    // usleep(100000);
    }

    return 0;
    }

    I do not need anything else but tracker data, so I want to strip this library down to the bare minimum that I need. I could use a little help (too many projects grabbing my attention)...
    This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
    nsbAuthor
    Up and Coming
    April 26, 2013
    "geekmaster" wrote:

    I do not need anything else but tracker data, so I want to strip this library down to the bare minimum that I need. I could use a little help (too many projects grabbing my attention)...


    Ahh, I think I know what's going on. You're calling runSensorUpdateThread() and then also calling sampleDevice() or waitSampleDevice(). runSensorUpdateThread() fires up a thread that does all the waiting and sampling for you in the background so you don't have to manually catch all the HID packets as they show up. You can, of course, do the sampling yourself and not bother with runSensorUpdateThread(), however be aware that the HID file descriptor is non-blocking, so if you call sampleDevice() rather than waitSampleDevice() it will return FALSE immediately unless there is something available to read.

    If you only call runSensorUpdateThread(), it will be busy keeping the quaternion in dev->Q in sync with the oculus orientation so that whenever you need the transformation matrix for rendering, you just extract it from dev->Q and render away. Currently accessing this way is not exactly thread-safe, but for demo purposes it should be ok until I ad a mutex and an accessor function or something.
    Up and Coming
    April 26, 2013
    I tried a lot of variations. When I call sampleDevice() it NEVER returns TRUE. When I call waitSampleDevide() it never returns. When I call I runSensorUpdateThread() all I see is these values:
    getSensorInfo: Invalid argument
    Device Info:
    name: Oculus VR, Inc. Tracker DK
    location: usb-0000:00:06.0-2/input0
    vendor: 0x2833
    product: 0x0001
    A: +0.000000 +0.000000 +0.000000 +0.000000
    Q: +0.000000 +0.000000 +0.000000 +1.000000
    A: +0.000000 +0.000000 +0.000000 +0.000000
    Q: +0.000000 +0.000000 +0.000000 +1.000000
    A: +0.000000 +0.000000 +0.000000 +0.000000
    Q: +0.000000 +0.000000 +0.000000 +1.000000
    A: +0.000000 +0.000000 +0.000000 +0.000000
    Q: +0.000000 +0.000000 +0.000000 +1.000000
    ...

    And if I put a sleep() call in the loop, then it never returns and I get this:
    A: +0.000000 +0.000000 +0.000000 +0.000000
    Q: +0.000000 +0.000000 +0.000000 +1.000000
    sendSensorKeepAlive: Invalid argument
    sendSensorKeepAlive: Invalid argument
    sendSensorKeepAlive: Invalid argument
    sendSensorKeepAlive: Invalid argument
    sendSensorKeepAlive: Invalid argument
    sendSensorKeepAlive: Invalid argument
    sendSensorKeepAlive: Invalid argument
    ...

    That error message repeats about every 500msec.

    I tried both with and without runSensorUpdateThread() too.

    And I have never seen live data no matter what I try.

    Could you perhaps provide a little CLI program that just outputs the Q and A vectors? I am obviously missing something here. TIA...
    This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
    Up and Coming
    April 26, 2013
    I changed sleep() to usleep() in previously posted code. Now sleep() returns. PEBKAC error! Doh!

    Anyway, here is the output when only runSensorUpdateThread() is used:
    lm32 libnsb_ovr_0.0.1 # ./linuxtest
    getSensorInfo: Invalid argument
    Device Info:
    name: Oculus VR, Inc. Tracker DK
    location: usb-0000:00:06.0-2/input0
    vendor: 0x2833
    product: 0x0001
    A: +0.000000 +0.000000 +0.000000 +0.000000
    Q: +0.000000 +0.000000 +0.000000 +1.000000
    A: +0.000000 +0.000000 +0.000000 +0.000000
    Q: +0.000000 +0.000000 +0.000000 +1.000000
    A: +0.000000 +0.000000 +0.000000 +0.000000
    Q: +0.000000 +0.000000 +0.000000 +1.000000
    A: +0.000000 +0.000000 +0.000000 +0.000000
    Q: +0.000000 +0.000000 +0.000000 +1.000000
    A: +0.000000 +0.000000 +0.000000 +0.000000
    Q: +0.000000 +0.000000 +0.000000 +1.000000
    sendSensorKeepAlive: Invalid argument
    A: +0.000000 +0.000000 +0.000000 +0.000000
    Q: +0.000000 +0.000000 +0.000000 +1.000000
    A: +0.000000 +0.000000 +0.000000 +0.000000
    Q: +0.000000 +0.000000 +0.000000 +1.000000
    A: +0.000000 +0.000000 +0.000000 +0.000000
    Q: +0.000000 +0.000000 +0.000000 +1.000000
    A: +0.000000 +0.000000 +0.000000 +0.000000
    Q: +0.000000 +0.000000 +0.000000 +1.000000
    A: +0.000000 +0.000000 +0.000000 +0.000000
    Q: +0.000000 +0.000000 +0.000000 +1.000000
    sendSensorKeepAlive: Invalid argument
    A: +0.000000 +0.000000 +0.000000 +0.000000
    Q: +0.000000 +0.000000 +0.000000 +1.000000
    ...

    If I use only waitSampleDevice(dev,-1) it never returns at all. Ever. Moving my Rift does not help.
    EDIT: Unplugging and plugging in my Rift USB makes it starts to return from the call (continuously) but the data is still default values shown above.

    If I use only sampleDevice(dev) it never returns TRUE. Ever. Moving my Rift does not help. A USB removal/insertion does not help.

    Is there something ELSE that I need to initialize?
    This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
    Up and Coming
    April 26, 2013
    Using only runSensorUpdateThread(dev), and IF I also disconnect and reconnect Rift USB before running the test program, then I get this instead of only the default values:
    getSensorInfo: Invalid argument
    Device Info:
    name: Oculus VR, Inc. Tracker DK
    location: usb-0000:00:06.0-2/input0
    vendor: 0x2833
    product: 0x0001
    A: +0.000000 +0.000000 +0.000000 +0.000000
    Q: +0.000000 +0.000000 +0.000000 +1.000000
    sendSensorKeepAlive: Invalid argument
    A: -0.004036 -0.005860 +0.006574 +0.001700
    Q: -0.006603 +0.000002 -0.004012 +0.999970
    A: -0.004036 -0.005860 +0.006574 +0.001700
    Q: -0.006603 +0.000002 -0.004012 +0.999970
    A: -0.004036 -0.005860 +0.006574 +0.001700
    Q: -0.006603 +0.000002 -0.004012 +0.999970
    ...

    The values change ONE TIME after the first 500ms periodic "Invalid argument" error, but then they never change again (so perhaps random data).

    So, again, is there something ELSE that I need to call?
    This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
    nsbAuthor
    Up and Coming
    April 26, 2013
    The problem appears to be something with the way the 2.6 kernel is handling sending HID reports to a device. This may be due to how things are done inside virtualBox - not sure. I installed Mint11 in a VBox VM and it is exhibiting the behavior you describe with no changes to the code that works under Ubuntu 12.10 (kernel 3.5).

    Next step would be to try it on a non-Vbox Mint 11 to see if the result is the same. I can do that but it'll take me a bit as I do have a day job :). In the meantime, here is another cut with threading removed from the library, and some console-only test apps. All are working properly at least under my configuration.