RFCOMM channel to Lego NXT

Discussion in 'Programmer Misc' started by outpaddling, Dec 9, 2007.

  1. outpaddling

    outpaddling Guest

    Dear Mac programming heroes:

    I'm developing a cross-platform C API for communicating with the Lego
    NXT via USB and Bluetooth. The code is mostly functional on FreeBSD,
    Linux, and OS X, with the exception of Bluetooth on OS X, which is
    vastly different from the other two platforms' socket-based

    I wrote a simple program to figure out the IOBluetooth framework, and
    using just the online developer docs was able to complete almost
    everything I need. I *thought* I was one line of code away from done
    when I discovered that OS X has no support for synchronous reads on an
    RFCOMM connection. (Argh.) I.e., there is no read analog to
    IOBluetoothRFCOMMChannelWrite(). OK, fine. Asynchronous I/O will
    probably become part of my API down the road anyway.

    From what I was able to dig up on the docs and on the WEB, it seems I
    need to set up a CFRunLoop in my program in order to make my callback
    function work, but I haven't found any hints as to what type of input
    source is required or how to set it up.

    Everything works up to the point of sending a command to the NXT, and
    I wrote a callback based on examples in the IOBluetooth framework
    docs. The IOBluetoothRFCOMMChannelWrite() call indicates success, but
    I can't yet read the response, presumably because my CFRunLoop is not
    set up properly.

    My code and the output are below. If someone can suggest a simple way
    to set up the CFRunLoop, I'd really appreciate it. I'm hoping to
    avoid buying yet another computer book I'll probably never look at


    #include <stdio.h>
    #include <CoreFoundation/CFArray.h>
    #include <CoreFoundation/CFNumber.h>
    #include <IOBluetooth/IOBluetoothUserLib.h>


    void listener(IOBluetoothRFCOMMChannelRef rfcommChannel, void
    *data, UInt16 l
    ength, void *refCon);

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

    BluetoothDeviceAddress btAddr =
    BluetoothDeviceName btName;
    IOBluetoothRFCOMMChannelRef rfcommChannel;
    IOBluetoothDeviceRef btDevice;
    CFStringRef name;
    char raw_name[100],
    int new_data;
    /* Create a BluetoothDeviceAddress for use in setting up a
    connection */
    btDevice = IOBluetoothDeviceCreateWithAddress(&btAddr);
    printf("btDevice = %p\n",btDevice);

    /* Quick test of address */
    ( IOBluetoothDeviceRemoteNameRequest(btDevice,NULL,NULL,btName) !=
    kIOReturnSuccess )
    fprintf(stderr,"IOBluetoothDeviceRemoteNameRequest() failed.
    return 1;
    name = IOBluetoothDeviceGetName(btDevice);
    printf("CFString name = %p\n",name);
    if ( CFStringGetCString(name,raw_name,
    100,kCFStringEncodingISOLatin1) )
    printf("Device name = %s\n",raw_name);
    fprintf(stderr,"CFStringGetCString() failed.\n");

    /* Open an RFCOMM channel to the NXT. The underlying baseband
    connection is automatically opened if needed. The process
    isn't finished until a listener callback function is
    since synchronous reads are not supported. */
    ( IOBluetoothDeviceOpenRFCOMMChannel(btDevice,NXT_RFCOMM_CHANNEL_ID,
    &rfcommChannel) != kIOReturnSuccess )
    fprintf(stderr,"IOBluetoothDeviceOpenRFCOMMChannel() failed.
    return 1;
    printf("Successfully opened RFCOMM channel!\n");

    /* Check Max Transmission unit, just for kicks. */
    printf("MTU = %d

    /* Send a get-battery-level command and check response */
    if ( IOBluetoothRFCOMMChannelRegisterIncomingDataListener(
    rfcommChannel,listener,&new_data) == 0 )
    /* Get battery level */
    cmd[0] = 0x00;
    cmd[1] = 0x0B;
    new_data = 0; /* Make use of the refCon arg by setting a
    flag. */
    if ( IOBluetoothRFCOMMChannelWrite(rfcommChannel,cmd,2,0) ==
    0 )
    printf("Successfully sent command!\n");

    /* Now read back response. This will require using the
    callback function, since there is no synchronous read
    function. */

    // Use CFMessagePort?
    fprintf(stderr,"IOBluetoothRFCOMMChannelWrite() failed.


    if ( IOBluetoothRFCOMMChannelCloseChannel(rfcommChannel) != 0 )
    fprintf(stderr,"IOBluetoothRFCOMMChannelCloseChannel() failed.
    return 0;

    void listener(IOBluetoothRFCOMMChannelRef rfcommChannel, void
    UInt16 length, void *refCon)

    int c,
    *new_data = refCon;

    puts("Got data!");
    for (c=0; c<length; ++c)
    printf("%02X ",((char *)data)[c]);
    *new_data = 1;


    btDevice = 0x305740
    CFString name = 0x308790
    Device name = NXT
    Successfully opened RFCOMM channel!
    MTU = 126
    Successfully sent command!
    outpaddling, Dec 9, 2007
    1. Advertisements

  2. outpaddling

    outpaddling Guest

    Thanks for the suggestion. I looked at the examples, but
    unfortunately, they don't seem to demonstrate what I need to do.

    I tried just calling CFRunLoopRun() with the default env, but the
    handler doesn't fire. Some other docs I found suggested that I need
    to add a source using CFRunLoopAddSource(), but I haven't been able to
    figure out how as yet.

    Thanks anyway,

    outpaddling, Dec 18, 2007
    1. Advertisements

  3. outpaddling

    outpaddling Guest

    I actually already got this far, and found in the Xcode docs:

    Creates a CFRunLoopSource object for a CFMessagePort object.

    CFRunLoopSourceRef CFMessagePortCreateRunLoopSource (
    CFAllocatorRef allocator,
    CFMessagePortRef ms,
    CFIndex order

    Problem is, I don't know where to get the CFMessagePortRef from. I
    browsed the framework docs, and found some possibilities, each with
    additional parameters that I didn't know where to get. At this point
    I just had to chuckle. The time required to explore every possible
    branch of this trail grows geometrically with each additional layer,
    and I'm not even certain that CFMEssagePort is the right path to
    follow. It's clear that I would need to know a lot about Carbon/Cocoa
    programming, including several core frameworks, in order to solve this
    one on my own, and I just don't have the time, so I have to hope I can
    find an analogous code example. It would have been so simple if Apple
    would have just let us do synchronous reads. Oh well...

    Thanks for the ideas,

    outpaddling, Dec 20, 2007
    1. Advertisements

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 (here). After that, you can post your question and our members will help you out.