SparkFun Forums 

Where electronics enthusiasts find answers.

All things pertaining to wireless and RF links
By siekosunfire
#16328
I just purchased a one of the WiTilt v2.5 sensors, and I was wondering if anyone on here had experience interfacing with the sensor via a program rather than a hyperterminal application. From my limited experience with Bluetooth programming, I assume that since Serial-over-Bluetooth is possible with the WiTilt sensor that the Bluetooth module on the sensor most likely uses RFCOMM sockets (as opposed to L2CAP sockets) in order to transmit the data from the sensor to another Bluetooth device.

How I'm looking at things now, I should just be able to perform a device discovery (assuming only one Bluetooth device is within range) and connect to that device and read what it transmits. While this is a far from complete program (I'd have to take into account multiple Bluetooth devices and also the WiTilt's menu interface), I feel that this is a pretty good start and am open to any suggestions or comments:
Code: Select all
/*Using the BlueZ Bluetooth stack - http://www.bluez.org/ */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
#include <sys/socket.h>

int main(int argc, char **argv)
{
   char address[18], buf[1024];
   int device, socket, num_return, status, bytes_read;
   const int length = 8, max_return = 255;
   inquiry_info *info = NULL;
   struct sockaddr_rc addr = {0};

   /*If an address was specified via the command prompt, try and locate the device with the target address*/
   if(argc > 1) {
      if((device = hci_devid(argv[1])) < 0) {
         perror("Error opening device");
         exit(1);
      }
   }

   /*If no address was specified on the command prompt, grab the first active device connected to the computer (hci0 for instance)*/
   else{
      if((device = hci_get_route(NULL)) < 0) {
         perror("Error opening device");
         exit(1);
      }
   }

   /*Open up a socket file descriptor to the device, which will be used by some BlueZ commands*/
   if((socket = hci_open_dev(device)) < 0) {
      perror("Error opening socket");
      exit(1);
   }

   /*Dynamically allocate memory for the inquiry info*/
   info = (inquiry_info *)malloc(max_return * sizeof(inquiry_info));

   /*Perform the device discovery for length * 1.28 seconds, with up to max_return devices returned, using the device id found previously*/
   if((num_return = hci_inquiry(device, length, max_return, NULL, 
      &info, IREQ_CACHE_FLUSH)) < 0) {
      perror("HCI inquiry error");
   }

   /*We'll assume only one device was found via the inquiry to keep things simple*/
   ba2str(&(info)->bdaddr, address);
   printf("Found device: %s", address);

   free(info);
   close(socket);

   /*Reinitialize with a new socket file descriptor to connect to the target Bluetooth device*/
   if((socket = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)) < 0) {
       perror("Error creating socket");
       exit(1);
   }

   /*Set the appropriate values of the structure*/
   addr.rc_family = AF_BLUETOOTH;   //Address family Bluetooth
   addr.rc_channel = (uint8_t) 1;        //RFCOMM Channel 1
   str2ba(address, &addr.rc_bdaddr); //Address of target device

   /*Try and establish a connection to the device*/
   if((status = connect(s, (struct sockaddr *)&addr, sizeof(addr))) < 0) {
      perror("Error connecting");
      exit(1);
   }

   memset(buf, 0, sizeof(buf));
   
   /*Print out anything returned*/
   while((bytes_read = read(client, buf, sizeof(buf))) > 0) {
      printf("Data: %s", bytes_read);
   }

   /*Close the socket file descriptor*/
   close(socket);
   return 0;
}
Cheers.
By siekosunfire
#16814
Just as a follow up, I was able to connect to the Bluetooth sensor directly via a C program:
Code: Select all
#include <stdio.h>
#include <unistd.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/rfcomm.h>
#include <sys/socket.h>

void Close(int);
void Connect(int, const struct sockaddr *, socklen_t);
void Send(int, const void *, size_t, int);
int SSocket(int, int, int);

int main(int argc, char **argv)
{
   if(argc < 3) {
      printf("Usage: RFCOMM_client [destination] [channel]\n");
      exit(1);
   }

   char buffer[1024] = {0};
   int socket, num_bytes;
   struct sockaddr_rc server;
   
   socket = SSocket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);

   server.rc_family = AF_BLUETOOTH;
   server.rc_channel = (uint8_t) atoi(argv[2]);
   str2ba(argv[1], &server.rc_bdaddr);

   printf("Connecting to: %s on channel: %s\n", argv[1], argv[2]);
   Connect(socket, (struct sockaddr *)&server, sizeof(server));

   printf("\tGrabbing data\n");

   for( ; ; ) {
      memset(buffer, 0, sizeof(buffer));
      num_bytes = read(socket, buffer, sizeof(buffer));

      if(num_bytes > 0) {
         printf("Received:\n%s", buffer);
      }
   }

   Close(socket);
   return 0;
}

void Close(int cl_fd)
{
   if(close(cl_fd) < 0) {
      perror("Close error");
      exit(1);
   }
}

void Connect(int con_fd, const struct sockaddr *con_sa, socklen_t con_salen)
{
  if(connect(con_fd, con_sa, con_salen) < 0) {
     perror("Connect error");
     exit(1);
  }
}

void Send(int send_fd, const void *send_ptr, size_t send_nbytes, int send_flags)
{
  if(send(send_fd, send_ptr, send_nbytes, send_flags) != (ssize_t)send_nbytes) {
     perror("Send error");
     exit(1);
  }
}

int SSocket(int sock_family, int sock_type, int sock_protocol)
{
   int s;

   if((s = socket(sock_family, sock_type, sock_protocol)) < 0) {
      perror("Socket error");
      exit(1);
   }

   return s;
}
Basically it'll establish a socket (not unlike Internet sockets) and attempt to connect to the WiTilt sensor at the designated channel and address. From there, I just had it loop infinitely and pressed the reset button on the sensor to have it output the menu into the terminal window. Adding support for user input (to start the accelerometer, calibrate, etc.) and grab the corresponding data is trivial at this point.

While not necessarily a huge issue, I did modify my /etc/bluetooth/pin file and replaced the standard '1234' pin with 'default'. However, since this directly establishes a connection to the Bluetooth sensor, I don't think a passkey is needed.
By cmanohar
#24185
Did you by any chance try communicating the WiTilt on windows platform ?
By siekosunfire
#24186
cmanohar wrote:Did you by any chance try communicating the WiTilt on windows platform ?
Yes I did try communicating using Windows XP; however, that was for the hyperterminal only. The code that I've posted will only work under any Linux variant. If, however, you want to modify the code so it works under Windows, you'll need to visit http://beej.us/guide/bgnet/output/html/ ... ml#windows and http://tangentsoft.net/wskfaq/ to convert some of the socket function calls into code that a Windows compiler will recognize. Beyond that, BlueZ won't run on Windows, so I'm not sure what you'd do for the Bluetooth component of the code.
By Bob Mosolgo
#35907
I have gotten the WiTilt connected and communicating using the Fransom Bluetools toolkit for .NET