Saturday, August 30, 2014

RFduino and BLED112, Putting It All Together

This tutorial is a very simple example to get started with setting data on the RFduino and reading it via a BLED112 on a PC running windows.

The code for this example can be found on GitHub in the dhRFduino repository under digitalhack.

This tutorial includes a sketch to run on the RFduino that will set various data values to be read from the RFduino and a program for Windows that uses the BLED112 to connect to the RFduino and read back the data.  To set different values the RFduino sketch has to have comments changed and then be recompiled.  I wasn’t looking for elegance that will come later.  I just wanted something simple.

This tutorial makes use of the following:

  1. A Windows PC
  2. Code:: Blocks 12.11 w/ MINGW
  3. Bluegiga’s BGLib SDK
  4. The Arduino IDE version 1.5.7 BETA
  5. The RFduino RFD22102 with an RFD22121 USB Shield for RFduino or another way to code to the RFduino.  In this post I describe a method using a Sparkfun FTDI 3.3V board.
  6. The RFduino library for the Arduino IDE.  This library can be found by starting at http://www.rfduino.com/product/rfd22102-rfduino-dip/ and then scrolling halfway down the page to DOWNLOAD, than selecting DOWNLOAD and finally selecting Download RFduino Zip.

Prior to starting you should review these documents:

  1. RFduino Quick  Start Guide for step by step instructions on how to install the RFduino library in the Arduino IDE.
  2. My Bluegiga BLED112 Setup on Windows 7 blog post.
  3. My Bluegiga’s BLED112, BGLib and Code::Blocks blog post.
  4. My It Worked For Me – RFduino blog post for information on downloading code to the RFduino using a Sparkfun FTDI 3.3V board.  Reviewing this document is optional and is only needed if you are using method described in the post.

RFduino Sketch

Below is the code for the RFduino to test initial connectivity between the RFduino and the BLED112.  This code should be copied into the Arduino IDE, compiled and downloaded to the RFduino.

#include <RFduinoBLE.h>

// This function is defined in the RFduino BLE library so it gets
// called anytime a connect is completed to the RFduino.
void RFduinoBLE_onConnect(){
  Serial.println("Connect");
}

// This function is defined in the RFduino BLE library so it gets
// called any time the RFduino is disconnected from.
void RFduinoBLE_onDisconnect(){
  Serial.println("Disconnect"); 
}

void setup() {
  Serial.begin(9600);
  Serial.println("Starting...");
  // this is the data we want to appear in the advertisement
  RFduinoBLE.advertisementData = "test01";

  // start the BLE stack
  RFduinoBLE.begin();
}

// In loop we send either a byte, float of integer by uncommenting the appropriate line.
// As the code is setup now the RFduino will send an uppercase A when it is queried for data

void loop() {
  uint8_t temp = 'A';
  Serial.println("Setting value");
  RFduinoBLE.sendByte(temp);
  //RFduinoBLE.sendFloat(99.1);
  //RFduinoBLE.sendInt(32766);
  while (true) {
  }
}

Windows Program

Below is the code that is used in main.c.  To compile this code you will need to have the following files in the source directory and you will need to make sure they are all included in your Code::Blocks project definition.  This is most easily done using the process described in the Bluegiga’s BLED112, BGLib and Code::Blocks blog post.

  1. cmd_def.c
  2. commands.c – this file will need to be modified to comment out the stubs of the ble functions that are setup in main.c.  This is
    1. ble_evt_connection_status
    2. ble_evt_attclient_attribute_value
    3. ble_evt_connection_disconnected
    4. ble_rsp_gap_connect_direct
  3. apitypes.h – this file will need to be modified as described in the Bluegiga’s BLED112, BGLib and Code::Blocks blog post
  4. cmd_def.h – this file will need to be modified as described in the Bluegiga’s BLED112, BGLib and Code::Blocks blog post

In main.c there are two defines that will need to be updated. 

  1. BLEADDRESS which needs to be the address of your RFduino.
  2. COMPORT needs to be the COM port that is defined for your BLED112

If you uncomment the #define DEBUG the program will print out a number of status messages that should be useful for debugging.

Once you have the Code::Blocks project setup, and have made all the necessary changes you should build the project.

#include <stdio.h>
#include <windows.h>
#include "cmd_def.h"

//#define DEBUG
#define BLEADDRESS "d6:3e:7a:bd:b5:7d" // substitute your RFduinos address
#define COMPORT "COM8" // substitute the COM port for your BLED112
//#define COMPORT "\\\\.\\COM10" // use this notation for com ports > 9.

typedef enum {
  state_disconnected,
  state_connecting,
  state_connected,
  state_requesting_value,
  state_value_returned,
  state_finish,
} states;
states state = state_disconnected;

bd_addr btle_dev;
uint8 btle_connection;
volatile HANDLE comm_port_h;

void dump_packet(char *rxtx, int len0, unsigned char *data0, int len1, unsigned char *data1) {
  printf("%s Packet: ", rxtx);
  int i;
  for (i = 0; i < len0; i++) {
    printf("%02x ", data0[i]);
  }

  for (i = 0; i < len1; i++) {
    printf("%02x ", data1[i]);
  }
  printf("\n");
}

void change_state(states new_state) {
  state = new_state;
}

void btle_send(uint8 len1, uint8* data1, uint16 len2, uint8* data2) {
  DWORD bytes_sent;

#ifdef DEBUG
  dump_packet("TX", len1, data1, len2, data2);
#endif

  if(!WriteFile (comm_port_h, data1, len1, &bytes_sent, NULL)) {
    printf("ERROR: Writing data. %d\n",(int)GetLastError());
    exit(-1);
  }

  if(!WriteFile (comm_port_h, data2, len2, &bytes_sent, NULL)) {
    printf("ERROR: Writing data. %d\n",(int)GetLastError());
    exit(-1);
  }
}

int btle_read() {
  DWORD bytes_read;
  const struct ble_msg *btle_msg;
  struct ble_header btle_msg_hdr;
  unsigned char buf[128];

#ifdef DEBUG
  printf("above first read\n");
#endif

  if(!ReadFile(comm_port_h, (unsigned char*)&btle_msg_hdr, 4, &bytes_read, NULL)) {
    return GetLastError();
  }
  // Error if 4 bytes were not read.  This means a timeout occurred.
  if (bytes_read != 4) return -1;

  if(btle_msg_hdr.lolen) {

#ifdef DEBUG
    printf("above second read\n");
#endif

    if(!ReadFile(comm_port_h, buf, btle_msg_hdr.lolen, &bytes_read, NULL)) {
      return GetLastError();
    }
  }

#ifdef DEBUG
  dump_packet("RX", sizeof(btle_msg_hdr), (unsigned char *)&btle_msg_hdr, btle_msg_hdr.lolen, buf);
#endif

  btle_msg=ble_get_msg_hdr(btle_msg_hdr);
  if(!btle_msg) {
    printf("ERROR: Message not found:%d:%d\n",(int)btle_msg_hdr.cls,(int)btle_msg_hdr.command);
    return -1;
  }

#ifdef DEBUG
  printf("dispatching event / response\n");
#endif

  btle_msg->handler(buf);

#ifdef DEBUG
  printf("below dispatch\n");
#endif

  return 0;
}

void ble_evt_connection_status(const struct ble_msg_connection_status_evt_t *msg) {
  if (msg->flags &connection_connected) {
    change_state(state_connected);

#ifdef DEBUG
    printf("Connected\n");
#endif
  }
}

void ble_evt_attclient_attribute_value(const struct ble_msg_attclient_attribute_value_evt_t *msg) {
  union {
    float f;
    int i;
    uint8 b[4];
  } value;

  value.b[0] = msg->value.data[0];
  value.b[1] = msg->value.data[1];
  value.b[2] = msg->value.data[2];
  value.b[3] = msg->value.data[3];

  printf("----> value: (int) %d (float) %f (byte) %c\n", value.i, value.f, value.b[0]);

  if (state == state_requesting_value) change_state(state_value_returned);
}

void ble_evt_connection_disconnected(const struct ble_msg_connection_disconnected_evt_t *msg) {
  change_state(state_disconnected);

#ifdef DEBUG
  printf("Connection terminated\n");
#endif
}

void ble_rsp_gap_connect_direct(const struct ble_msg_gap_connect_direct_rsp_t *msg) {

#ifdef DEBUG
  printf("from ble_rsp_gap_connect_direct - result: %d, connection_handle: %d\n",
         msg->result, msg->connection_handle);
#endif

  btle_connection = msg->connection_handle;
}

int main(int argc, char *argv[]) {
  COMMTIMEOUTS cto;
  char *comm_port = COMPORT;
  unsigned int b[5];
  int n;

     n = sscanf(BLEADDRESS, "%X:%X:%X:%X:%X:%X", &b[5], &b[4], &b[3], &b[2], &b[1], &b[0]);
     if (n == 6 && (b[0] | b[1] | b[2] | b[3] | b[4] | b[5]) < 256) {
    for(n=0; n<6; n++)
           btle_dev.addr[n] = b[n];
     } else {
         printf("bad bluetooth address");
         return -1;
     }

  bglib_output = btle_send;

  comm_port_h = CreateFile(comm_port, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
                              NULL, OPEN_EXISTING, 0, NULL);


  if (comm_port_h == INVALID_HANDLE_VALUE) {
    printf("Error opening %s: %d\n",comm_port,(int)GetLastError());
    return -1;
  }

  // Reset dongle to get it into known state
  ble_cmd_system_reset(0);
  CloseHandle(comm_port_h);

  do {
    Sleep (500); // 0.5s
    comm_port_h = CreateFile(comm_port, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
                                NULL, OPEN_EXISTING, 0, NULL);
  } while (comm_port_h == INVALID_HANDLE_VALUE);

  // Set 10 second timeout for reads.
  cto.ReadIntervalTimeout = 0;
  cto.ReadTotalTimeoutMultiplier = 0;
  cto.ReadTotalTimeoutConstant = 10000;
  cto.WriteTotalTimeoutMultiplier = 0;
  cto.WriteTotalTimeoutConstant = 0;

  if (!SetCommTimeouts(comm_port_h, &cto)) {
    printf("Error setting port timeouts: %d\n",(int)GetLastError());
    return -1;
  }

#ifdef DEBUG
  printf("ReadIntervalTimeout: %ld, ReadTotalTimeoutConstant: %ld, ReadTotalTimeoutMultiplier %ld\n",
         cto.ReadIntervalTimeout, cto.ReadTotalTimeoutConstant, cto.ReadTotalTimeoutMultiplier);
#endif

  change_state(state_connecting);
  ble_cmd_gap_connect_direct(&btle_dev, gap_address_type_random, 40, 60, 100,0);
  while (state != state_connected) {
    if (btle_read() != 0) break;
  }

  change_state(state_requesting_value);
  ble_cmd_attclient_read_by_handle(btle_connection, 0x000e);
  while (state != state_value_returned) {
    if (btle_read() != 0) break;
  }

  ble_cmd_connection_disconnect(btle_connection);
  while (state != state_disconnected) {
    if (btle_read() != 0) break;
  }

  CloseHandle(comm_port_h);
  return 0;
}

This program is based on the Bluegiga demo programs. 

The program starts by attempting to open the designated COM port.  If the open is successful it issues a reset to the BLED112 device to get it into a known state and closes the COM port.  It then attempts to open the COM port.  This open will not succeed until the BLED112 completes resetting.  When the BLED112 resets it will disconnect and reconnect from the USB.

Next the program sets up a read timeout so that it will not lock up forever if the BLED112 stops sending data.  In this example that is unlikely to happen.

After the read timeout is setup the program instructs the BLED112 to connect to the RFduino.  When the connection completes the ble_evt_connection_status callback function is called.

After the connection is established the program instructs the BLED112 to read data from the RFduino based on the data handle..  When the data is read the ble_evt_attclient_attribute_value callback function is called which prints out the data.

Finally the program instructs the BLED112 to disconnect from the RFduino.

The ble_evt_attclient_attribute_value callback function is setup to print the data out in three of the data types that the RFduino can send: byte, float, and integer.  This allows you to see on the console the value set on the RFduino.

Getting It All To Work Together

The sequence of events that I use is to get the RFduino up and running with a Serial Monitor session going so I can see the status outputs.  Then I run the windows program which takes a couple of seconds to run and prints the value.

You can test different data types by switching the comments around in the RFduino sketch.  When you do this don’t forget to compile and download the modified code to the RFduino.

If everything is working the program should print the following line after about 6 seconds:

----> value: (int) 131481153 (float) 0.000000 (byte) A

If you change the RFduino sketch to send an integer or a float or a different character your output will obviously look slightly different.

Hope you find this helpful. My thanks to Bluegiga and RFduino because without their products none of this would be possible.

If you find something that doesn’t work for you or you have questions please post them as comments and I will get back to you as soon as I can.

Friday, August 29, 2014

Bluegiga’s BLED112, BGLib and Code::Blocks

There is a lot of good documentation on BGLib and the BGAPI on Bluegiga’s website.  I found the first couple of slides in the BGAPI BGLib Overview presentation very helpful for a high-level understanding.

Along with the sdk source two examples are installed.  Reviewing these examples provides additional information on how to use the sdk.

After you successfully install the Bluegiga SDK you will end up with a ble-1.2.2-100 folder (assuming you install version 1.2.2 of the sdk) under the install directory.  I let the install proceed with defaults so on my system it ended up on C:\Bluegiga.  The sdk is in the src directory.

image

The sdk consists of two c files and two header files.

image

  • apitypes.h consists of a number of type definitions.
  • cmd_def.h defines a number of constants and data structures.
  • cmd_def.c sets up the data structure that is used to dispatch events based on the packets received.
  • commands.c defines the default functions that get called when an event is dispatched.  These functions have no executable statements and therefore when called just return.  In your program you will need to define those functions you wish to use and comment them out or remove them from commands.c

In the examples commands.c has been renamed to stubs.c.  The examples also contain a Makefile for building them.  The Makefile contains logic for MINGW under Windows but as was planning to  use Code::Blocks I didn’t test them.

In using BGLib with MINGW in Code::Blocks 12.11 I found that the apitypes.h and cmd_def.h files had to be modified.  The modifications were necessary to get the PACKSTRUCT macro defined properly.  The problem is that PACKED is defined in windef.h for MINGW without gcc_struct which causes incorrect packing of data.

In apitypes.h I commented out the lines beginning with #ifdef __GNUC__ and ending with the corresponding #endif.  In cmd_def.h I commented out the lines starting with #ifdef PACKED down to the corresponding #else and then the corresponding #endif several lines below.

apitypes.h modifications:

image

cmd_def.h modifications:

image

To setup the scan_demo example in Code::Blocks I suggest the following steps:

Execute Code::Blocks and under File select New and create a Console project for C.

image

Enter scan_demo as the project title.  Code::Blocks will create new project folder in your projects folder.

image

The new project will have a main.c file and a scan_demo.cbp Code::Blocks project file.

image

Close Code:: Blocks and go to the folder with the Bluegiga scan_demo in it and copy all the apitypes.h, cmd_def.c, cmd)def.h, main.c and stubs.c and paste these into the Code::Blocks project folder.  You will get a warning about main.c as it already exists in the Code::Blocks project folder.  Answer that you want to replace the existing file with the copied file.

image

Execute Code::Blocks and open your scan_demo project.  Select the scan_demo project in the left side window and the select Project from the menu bar and Add Files…  Select the new files you added to your project from the example directory.

image

Using the gear icon build the project.

image

As the scan_demo program requires the COM port of the BLED112 as a parameter you will need to open a console window and navigate to the executable in your scan_demo project directory.  In this case I built a Debug copy so it was in the bin\Debug directory.

Run the scan_demo program with the appropriate COM port.  In my case this was com8:

scan_demo com8

As long as you have a BLE device that is advertising you will see its address along with the RSSI power value in the console window.

image

You should now be ready to move on to compiling an example that receives data from your BLE device.  In my case that is an RFduino which is the subject of my next post.

Hope you find this helpful.  My thanks to Bluegiga for their sdk and the documentation on their website and to the folks responsible for Code::Blocks.

If you find something that doesn’t work for you or you have questions please post them as comments and I will get back to you as soon as I can.

Thursday, August 28, 2014

Bluegiga BLED112 Setup on Windows 7

To use the Bluegiga BLED112 dongle and sdk with Windows 7 you will should follow the steps below.

Download and Install the Software

Go to the Bluegiga site and download the appropriate software.  It is recommended that you want to make sure that you download the sdk for the version of software that is loaded on your BLED112. 

I was not able to figure how to determine which version of software is running on the usb dongle without downloading the software and installing it.  Fortunately, I guessed right.  At the time that I did the the BLED112 dongle I received was running v1.2.2-100. 

To download the software you will need to register on the Bluegiga site.  Once you are registered go to this URL to download the software.

https://www.bluegiga.com/en-US/products/bluetooth-4.0-modules/bled112-bluetooth-smart-dongle/documentation/

When you get to the website you will want to select Software Releases which should expand the section to list the software versions available for download.

image

Plug in the BLED112

Once the software has installed plug in your BLED112 and wait for the drivers to install.

Access the BLED112 using the BLE GUI Software

Once the BLED112 has completed its install you should execute the BLE GUI software that was downloaded.  This can be done via the icon on the desktop or through the program menu.

When the software runs it will display a windows as shown below.

image

The software should have the COM port that was installed listed as shown in the first red circle.  As long as the right COM port is showing the next step is to select the Attach button as shown in the second red circle.  I was able to use the default baud rate.

When you are successfully connected the Attach button should change to a Detach button and next to the button should be a green Connected as shown below.

image

The next step is to select Commands from the menu bar and then select the Info command.

image

This should result in the BLED112 reporting back its version as shown below.

image

This means that the BLED112 dongle is successfully installed.

Using Device Manager to Find Your COM Port

If you run into problems with what COM port the BLED112 is connected to you can open a command window and enter devmgmt.msc which will bring up the Windows 7 device manager.  Then scroll down to Ports (COM & LPT).  Click on the triangle / arrow to expand the port listing and you should see a COM port that lists Bluegiga Bluetooth Low Energy (COMx) where COMx is the COM port that is connected to the BLED112.

image

In my next post I will discuss walking through the sdk and some changes that I had to make to get the sdk to work correctly with Code::Blocks 12.11 and MINGW.

Tuesday, August 19, 2014

RFduino and Bluegiga’s BLED112

DSCF7953

Last December I found that my local MicroCenter had the RFduino in stock and as I am interested in low energy wireless I purchased one.  Using a Sparkfun FTDI 3.3V and a customer cable I built I was able to download sketches to it.  This work is documented in my Worked For Me – RFduino post.

After setting up the Arduino IDE as described on the RFduino website I was able to successfully compile and download the AdvertisementContinous example and scan for the results on my Nexus 7 table using the BLE Explorer Scan application.

After this success the next step was to develop a simple program to receive data from the RFduino via BLA.  As I am much more comfortable with C rather than Java I decided to get a simple C program up and running before I tackled Android.

This started me down what turned into a multi-month side trip.  As Windows 7 doesn’t support bluetooth low energy with the regular bluetooth driver I decided to use Linux.  Unfortunately while Linux does support BLE getting it to work was rather involved.  After several false starts I was able to make some progress with gatttool which maybe some day I will post.

I had come across Bluegiga’s BLED112 Bluetooth USB dongle which at a high-level conceptual level is a BLE device that connects via USB with a COM port interface.  Bluegiga supplies a simple SDK, BGLIB, in C that allows you to interface via the COM port to the BLE device.  Given the progress I wasn’t making I decided to purchase one from Mouser to see if I could make faster progress.

After two weeks I can say I am very happy with what I have been able to achieve.  I have successfully been able to send information from the RFduino to my Windows 7 PC using BGLIB via BLE from a C program compiled with MINGW32 included in Code::Blocks 12.11.  I am using the 1.2.2-100 version of the SDK with some minor changes due to the way MINGW32 handles packed data on Windows.

I plan to post some detailed examples in the next couple of weeks.

Wednesday, August 6, 2014

Quick Note - Raspberry Pi - Bare Metal Programming

For a while I have wanted to give bate metal programming a go on on of the development boards I have.  Back in college one of my favorite courses was assembler.  Back then I was programming on a PDP 11/34 that supported multiple users with fewer resources than a Raspberry Pi.  Over the past weekend the weather and my todo list cooperated and I decided to give it a try.

Thanks to the wonderful Raspberry Pi community there is no shortage of resources to get you started.

These include:

An excellent complete online course called Baking Pi – Operating Systems Development on the University of Cambridge’s website.  This course walks you through 11 exercises with very good explanation and full examples.  The code is in assembler and uses the GNU Toolchain.

A series of three articles on www.valvers.com website that walk you through bare metal programming in C.  Again the content is excellent with step by step instructions and examples.

A wiki page on OSDev.org titled ARM Raspberry Pi Tutorial C gives more involved example in C that produces text output on the console port.

Another resource I found useful was Embedded Programming with the GNU Toolchain  This document is more general in nature but also helps to drive home a number of salient points including detail on the C startup and memory initialization process.

I was successfully able to download and install the GNU toolchain from launchpad.net on to my Windows 7 Pro desktop, successfully compile the examples in the www.valvers.com set of articles and the OSDev.org wiki page and copy them to an SD card where I had rename kernel.img to kernel.old and substituted my program.  When I inserted the sd card into my Raspberry Pi and turned the power on all the programs successfully ran.

For the OSDev.org wiki example I used a USB BUB connected to pins 13 – 15 on the Raspberry PI GPIO connector and putty running on my desktop to display the output

Time Flies - March - July 2014

It has been rather quiet around here.

I have been working on a bunch of stuff but nothing that has gotten far enough along to write a post about.  One big area I spent a lot of time on was Bluetooth Low Energy both from Linux on the pcDuino running Arch Linux and from Android on the Nexus 7.

I also started having PC problems and ended up building a new desktop computer.  The new computer is built with an AS Rock Z87M Extreme4 motherboard and an Intel i5-4670K processor.  The rest of the parts were scavenged from equipment at hand.

The PC has worked mostly OK for the last three month.  I had some fits with getting USB 3.0 to work on the motherboard which turned out to be a driver issue and the stock fan that comes with the processor isn’t able to keep the processor cool enough running under extreme load but that fortunately doesn’t happen with normal usage.  I have also had problems with finding a reasonably priced power supply with a quiet fan that stays quiet.

More to come soon, hopefully.