csocketsbluetoothlego-mindstormslego-mindstorms-ev3

Bluetooth on the EV3


Before I get started. Yes, I could use leJOS, ev3dev, or some others, but I'd like to do it this way because that is how I learn.

I am using the CodeSourcery arm-2009q1 arm toolchain. I fetched the required libraries (bluetooth) from here: https://github.com/mindboards/ev3sources. I am uploading the programs to the brick by using this tool: https://github.com/c4ev3/ev3duder

I have also fetched the brick's shared libraries, but I can not get them to work properly and there is 0 documentation on how to write a c program for the ev3 using the shared libraries. If I could get that working I might be able to use the c_com module to handle bluetooth, but right now bluez and rfcomm in conjunction with: https://github.com/c4ev3/EV3-API for motor and sensor control seems to be my best bet.

Now, with that out of the way: I'd like to run the EV3 as a bluetooth "server" meaning that I start a program on it and the program opens a socket, binds it, listens for a connection, and then accepts a single connection. I am able to do open a socket, bind it to anything but channel 1 (I believe this might be the crux of my issue), I am able to listen. These all return 0 (OK) and everything is fine.

Then I try to accept a connection. That instantly returns -1 and sets the remote to address 00:00:00:00:00:00.

My code is pretty much the same as can be found here: https://people.csail.mit.edu/albert/bluez-intro/x502.html

Here it is:

#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/rfcomm.h>
#include <ev3.h>

int main(int argc, char **argv)
{
    InitEV3();
    struct sockaddr_rc loc_addr = { 0 }, rem_addr = { 0 };
    char buf[1024] = { 0 };
    int sock, client, bytes_read;
    socklen_t opt = sizeof(rem_addr);

    sock = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);

    loc_addr.rc_family = AF_BLUETOOTH;
    loc_addr.rc_bdaddr = *BDADDR_ANY;
    loc_addr.rc_channel = 2; // <-- Anything but 1. 1 seems to be taken
    bind(sock, (struct sockaddr *)&loc_addr, sizeof(loc_addr));

    listen(sock, 1);

    // accept one connection <-- PROGRAM FAILS HERE AS accept() returns -1
    client = accept(sock, (struct sockaddr *)&rem_addr, &opt);

    // ---- All following code is irrelevant because accept fails ----

    ba2str( &rem_addr.rc_bdaddr, buf );
    fprintf(stderr, "accepted connection from %s\n", buf);
    memset(buf, 0, sizeof(buf));

    bytes_read = read(client, buf, sizeof(buf));
    if( bytes_read > 0 )
        printf("received [%s]\n", buf);

    close(client);
    close(sock);

    FreeEV3();
    return 0;
}

I am able to get the same code working on my pi. Even communication back and forth when the ev3api-specific functions are commented out. I just can't fathom why it won't work on the EV3.


Solution

  • I figured it out. On my raspberry PI, the accept call worked as expected with no quirks. On the EV3 however, the accept call is non-blocking even if it has not been told to act like so. The solution was to place the accept call in a loop until an incoming connection was in the queue.

    while (errno == EAGAIN && ButtonIsUp(BTNEXIT) && client < 0)
        client = accept(sock, (struct sockaddr*)&rem_addr, sizeof(rem_addr));
    

    I'll upload the code to github. Contact me if you'd like to do something similar with the EV3.