I now understand my problem slightly better and rather than making a new thread I'll just update this one.
So using hci_open_dev
is erroneous as it opens a socket to the local BT adapter only. It does not help me establish a connection to a remote device.
To summarise - I have a built in BT adapter in my laptop and I've bought a little USB BT adapter which I've plugged into the same laptop. Now I want to run two programs on this one machine that can communicate. To do this they need to use different adapters.
The second argument to bind
is a struct sockaddr*
, which I simply cast my previous struct sockaddr_rc*
to. The bdaddr_t
field of a listening socket's struct sockaddr
specifies which BT adapter to use, allowing me to do this:
struct sockaddr_rc loc_addr = { 0 }, rem_addr = { 0 };
// address of the built in BT adapter on my machine
const char* adapter = "60:F2:62:1B:9C:74";
// converting it to a bdaddr_t*
bdaddr_t* adapterbdadd = strtoba(adapter);
// allocate socket
int s = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
// bind socket to port 1
loc_addr.rc_family = AF_BLUETOOTH;
loc_addr.rc_bdaddr = *adapterbdadd;
loc_addr.rc_channel = (uint8_t) 1;
bind(s, (struct sockaddr *)&loc_addr, sizeof(loc_addr));
// set the socket to listening mode
listen(s, 1);
// accept one connection
client = accept(s, (struct sockaddr *)&rem_addr, &opt);
// convert the bdaddr to a char* (just assume buf is defined elsewhere)
ba2str( &rem_addr.rc_bdaddr, buf );
fprintf(stderr, "accepted connection from %s\n", buf);
// free socket resources
close(client);
close(s);
For an outgoing connection, however, I am not sure how to specify which adapter to use. The code looks roughly like this:
struct sockaddr_rc addr = { 0 };
// This is the same address that should be used by the listening program above
char dest[18] = "60:F2:62:1B:9C:74";
// allocate a socket
int s = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
// set the connection parameters. Want to connect to the listening program
// and connect through port 1. If I change both programs to use port 0 I
// get an Invalid Argument error from this program.
addr.rc_family = AF_BLUETOOTH;
addr.rc_channel = (uint8_t) 1;
str2ba( dest, &addr.rc_bdaddr );
// connect to listening program
int status = connect(s, (struct sockaddr *)&addr, sizeof(addr));
// This program never reaches beyond this point
if( status == 0 ) {
printf("successfully connected\n");
} else {
perror("error connecting");
}
close(s);
As seen above I can only specify which device to connect to, which device to use. When I first start up the listening program followed by the client, the connection is never established. The output from running hciconfig
looks like this:
hci1: Type: Primary Bus: USB
BD Address: 60:F2:62:1B:9C:74 ACL MTU: 1021:4 SCO MTU: 96:6
UP RUNNING
RX bytes:16967 acl:0 sco:0 events:2751 errors:0
TX bytes:678007 acl:0 sco:0 commands:2749 errors:0
hci0: Type: Primary Bus: USB
BD Address: 5C:F3:70:9D:BC:07 ACL MTU: 1021:8 SCO MTU: 64:1
UP RUNNING
RX bytes:1016 acl:0 sco:0 events:57 errors:0
TX bytes:3679 acl:0 sco:0 commands:57 errors:0
I am not BT expert but I don't see anything here to alarm me. Does anyone else? If anyone can point me towards why these two programs can not speak to each other I would be extremely grateful.
I am developing some Bluetooth (BT) (normal Bluetooth, not Bluetooth Low Energy) software on my laptop and in order to test them on one machine, I bought a second BT adapter (Asus USB-BT400). After I plugged it in I could immediately see it using hciconfig
.
I tried to adjust my programs to use the proper adapters but it did not work and I am not sure why. I am quite new to BT programming so I might have misunderstood something. To get program A to use the adapter with address addr1
I ran
int dev_id = hci_devid("60:F2:62:1B:9C:74");
int err = hci_open_dev(dev_id);
if(err < 0) {
printf("error opening adapter device\n");
}
where "60:F2:62:1B:9C:74"
is addr1
. The companion program did the same but used the other adapters address.
When I run the two programs the errors are not printed (meaning the adapters were chosen successfully?) but the programs do nothing. After a while the client program prints Uh Oh! The Host is Down
. If anyone can explain what I am doing wrong when choosing the adapters I'd be very grateful. I also tried running the server on one laptop and the client on another, but nothing happened there either. In that case, I did not explicitly choose the BT adapter as I expected it to default to the only one available. I have not considered that the example code might be wrong but if anyone sees any errors, please point them out.
The complete code can be seen below. I am trying to run a simple example with an RFCOMM connection between a server and a client. The example was borrowed from the book Bluetooth essentials for programmers by Albert S. Huang and Larry Rudolph, after which I've tried to modify it.
Server program
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/rfcomm.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
int main(int argc, char **argv)
{
struct sockaddr_rc loc_addr = { 0 }, rem_addr = { 0 };
char buf[1024] = { 0 };
int s, client, bytes_read;
socklen_t opt = sizeof(rem_addr);
int dev_id = hci_devid("60:F2:62:1B:9C:74");
int err = hci_open_dev(dev_id);
if(err < 0) {
printf("error opening laptop device\n");
}
// allocate socket
s = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
// bind socket to port 1 of the first available
// local bluetooth adapter
loc_addr.rc_family = AF_BLUETOOTH;
loc_addr.rc_bdaddr = *BDADDR_ANY;
loc_addr.rc_channel = (uint8_t) 1;
bind(s, (struct sockaddr *)&loc_addr, sizeof(loc_addr));
// put socket into listening mode
listen(s, 1);
// accept one connection
client = accept(s, (struct sockaddr *)&rem_addr, &opt);
ba2str( &rem_addr.rc_bdaddr, buf );
fprintf(stderr, "accepted connection from %s\n", buf);
memset(buf, 0, sizeof(buf));
// read data from the client
bytes_read = read(client, buf, sizeof(buf));
if( bytes_read > 0 ) {
printf("received [%s]\n", buf);
}
// close connection
close(client);
close(s);
return 0;
}
Client program
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/rfcomm.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
int main(int argc, char **argv)
{
struct sockaddr_rc addr = { 0 };
int s, status;
char dest[18] = "60:F2:62:1B:9C:74";
int dev_id = hci_devid("5C:F3:70:9D:BC:07");
int err = hci_open_dev(dev_id);
if(err < 0) {
printf("error opening adapter device\n");
}
// allocate a socket
s = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
// set the connection parameters (who to connect to)
addr.rc_family = AF_BLUETOOTH;
addr.rc_channel = (uint8_t) 1;
str2ba( dest, &addr.rc_bdaddr );
// connect to server
status = connect(s, (struct sockaddr *)&addr, sizeof(addr));
// send a message
if( status == 0 ) {
status = write(s, "hello!", 6);
}
if( status < 0 ) perror("uh oh");
close(s);
return 0;
}
Okay so I got some help in Zephyr's slack channel from users @hje and @sjanc. There were a few things that I had to change. First of all, my usages of strtoba
were changed to str2ba
. strtoba
did some wierd swapping.
Secondly, even the client program can specify which BT adapter to use via bind
, similarly to how the server program does it. In my case, I start the server first, after which the client will be assigned whichever adapter is free. I don't explicitly need to state which.
Lastly, but definitely most important, it turns out that you have to instruct Linux to make the BT adapters discoverable. I did this by running hciconfig hci0 piscan
and hciconfig hci1 piscan
.
Complete programs in the end:
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/rfcomm.h>
int main(int argc, char **argv)
{
struct sockaddr_rc addr = { 0 }, laddr = {0};
int s, status;
char dest[18] = "60:F2:62:1B:9C:74";
// allocate a socket
s = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
// set the connection parameters (who to connect to)
addr.rc_family = AF_BLUETOOTH;
addr.rc_channel = (uint8_t) 1;
str2ba( dest, &addr.rc_bdaddr );
// connect to server
status = connect(s, (struct sockaddr *)&addr, sizeof(addr));
// send a message
if( status == 0 ) {
printf("successfully connected\n");
}
close(s);
return 0;
}
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/rfcomm.h>
int main(int argc, char **argv)
{
struct sockaddr_rc loc_addr = { 0 }, rem_addr = { 0 };
char buf[1024] = { 0 };
int s, client, bytes_read;
socklen_t opt = sizeof(rem_addr);
// I want to use the built in BT adapter
const char* adapter = "60:F2:62:1B:9C:74";
// allocate socket
s = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
// bind socket to port 1 of the first available
// local bluetooth adapter
loc_addr.rc_family = AF_BLUETOOTH;
str2ba(adapter, &loc_addr.rc_bdaddr);
loc_addr.rc_channel = (uint8_t) 1;
bind(s, (struct sockaddr *)&loc_addr, sizeof(loc_addr));
// put socket into listening mode
listen(s, 1);
// accept one connection
client = accept(s, (struct sockaddr *)&rem_addr, &opt);
ba2str( &rem_addr.rc_bdaddr, buf );
fprintf(stderr, "accepted connection from %s\n", buf);
memset(buf, 0, sizeof(buf));
// close connection
close(client);
close(s);
return 0;
}