Understanding the BC127 Bluetooth Module

Pages
Contributors: SFUptownMaker
Favorited Favorite 7

Arduino Library

To make the BC127 module easy to use, we've created a library for use with Arduino and Arduino-compatible boards. We've tested it extensively under v1.0.5; we can't guarantee extensive backwards compatibility, but it should work under most post-1.0 releases.

You can download the Arduino library from our GitHub repository; the library will work for both the BC127 Breakout Board and the PurpleTooth Jamboree board.

General Concepts

The BC127 library assumes you have the BC127 connected either to a hardware or software serial port. The library should support all Atmega-based Arduino boards, and should work with any hardware or software serial port normally supported by the board.

To create an instance of the BC127 library, which will allow you to interface with the BC127 through the library's commands, you need to include the BC127 library and to invoke the class constructor for the library, like this:

language:c
#include <bc127.h>
BC127 BC127Module(&serialPortName);

You can change "BC127Module" to whatever name you're most comfortable with, of course. "serialPortName" should be replaced by the name of the serial port you have the device connected to; for example, to connect it to the main hardware serial port on an Uno or similar, your constructor would look like this:

language:c
#include <bc127.h>
BC127 BC127Module(&Serial);

If you wanted to use a software serial port, you'd need a couple of other steps: first, you'd need to include the SoftwareSerial library, and you'd need a constructor for a SoftwareSerial object:

language:c
include <bc127.h>
#include <SoftwareSerial.h>

SoftwareSerial swPort(3,2); // RX pin, TX pin
BC127 BC127Module(&swPort);

You still need to do a .begin() statement in your setup() function to set the baud rate for the serial port in question; of course, that speed must match the speed set via the BAUD parameter in the BC127 module. By default, and in all the examples here, that value is going to be 9600 baud.

Sending Commands to the Module

The BC127 library is a little different to most libraries in the way it handles data. Usually, when you call a function, the return value from that function represents the data of interest. The complexity of data from the BC127 makes that a difficult prospect; to deal with that, and with the number of different ways a command can go wrong, every command for the BC127 object returns a special value, called opResult.

There are 7 possible responses from a BC127 command function; they have names for easy reference but can also be referred to as integer values:

  • REMOTE_ERROR (-5) - Most likely, there is no remote device at the address specified, or the remote device completely failed to respond.
  • CONNECT_ERROR (-4) - The remote device responded, but the operation failed because of a limitation at the remote device's end.
  • INVALID_PARAM (-3) - The local BC127 module didn't like something about the command it just received; perhaps there was a typographical error?
  • TIMEOUT_ERROR (-2) - The command you just sent had a timeout parameter, and the BC127 failed to complete its operation in the time allotted. Most commands can timeout.
  • MODULE_ERROR (-1) - The BC127 didn't like something that just happened.
  • DEFAULT_ERR (0) - You should never see this.
  • SUCCESS (1) - The command completed successfully.

As we proceed through the commands in the library, I'll point out the possible responses and implications thereof for each function.

There are three general-purpose commands for the module that we should talk about before we go any further: restore(), reset(), and writeConfig().

language:c
BC127Module.restore();

This command resets the module to its factory default settings. All currently set parameters will be reset to default, and any stored pairing addresses will be erased. However, this restoration will only persist until the next reset or power cycle.

language:c
BC127Module.writeConfig();

Writes the current configuration of the device into non-volatile memory; upon any reset, the module's settings will be restored to their current state.

language:c
BC127Module.reset();

Reset the module, loading the parameters that have been set in its non-volatile memory. Also closes all active connections.

Most changes to settings require that these three commands be sent, in this order, after the settings change to make the change take effect; we'll make note of whether or not that's the case for each later command.

All three of these can return "TIMEOUT_ERROR" or "SUCCESS". "TIMEOUT_ERROR" probably means the module isn't powered, isn't connected properly, or has the wrong baud rate setting.

language:c
BC127Module.connectState();

This command allows you to check on whether or not the module is currently connected to anything. It doesn't report what kinds of connections are present, just whether or not a connection is active.

It will return either "SUCCESS" or "CONNECT_ERROR". It takes a few hundred milliseconds to complete.

Note that because of buffer limitations, this will cause an overflow on the software serial buffer. It's designed to handle that gracefully but the overflow flag will still be set.

language:c
BC127Module.addressQuery(String address);

This will retrieve the current connected module's address and stick it in the String object address. Useful for identifying the module you're currently using.

"TIMEOUT_ERROR" probably means the module isn't powered, isn't connected properly, or has the wrong baud rate setting.

Making and Managing Connections

Obviously, we need to connect to other devices to make anything useful happen with this device. Here are the commands for connecting to other targets.

language:c
BC127Module.inquiry(int timeout);

This command scans the local airwaves for discoverable Bluetooth Classic devices and creates a list of up to five of them. The "timeout" parameter is the timeout in seconds times 1.3; that is, passing a "1" will result in a 1.3s timeout on the function.

It returns either the number of modules found (from 0 up to 5) or "TIMEOUT_ERROR". "TIMEOUT_ERROR" probably means the module isn't powered, isn't connected properly, or has the wrong baud rate setting.

language:c
BC127Module.getAddress(char index, String address);

Fetches the address at index in the list returned by inquiry() and puts it into a String object.

Can return either "SUCCESS" or "INVALID_PARAM"; "INVALID_PARAM" probably means you tried to index past the end of the list, or to access the list when it was, in fact, empty.

language:c
BC127Module.connect(char index, connType connection);
BC127Module.connect(String address, connType connection);

This is the actual connection command. It comes in two versions: the first simply attempts a connection to one of the devices discovered by an inquiry() call, and the second attempts a connection by address.

connType is another BC127 type; in this case your options are "SPP", "BLE", "A2DP", "AVRCP", "PBAP", and "HFP".

For the first, an "INVALID_PARAM" result indicates that you tried to connect to an index that's not present. For the second, it indicates that you sent an address with an improper number of characters.

For both of them, you can expect to see these responses:

  • "MODULE_ERROR" - Address invalid (maybe not all caps, or characters that aren't hex digits).
  • "CONNECT_ERROR" - Most likely, there are no devices within range that have that address.
  • "REMOTE_ERROR" - We found a device with that address, but it rejected our connection for some reason (maybe it doesn't support connections of the type we requested?).
  • "SUCCESS" - You're connected and ready to rock.

Using the SPP Connection

The SPP connection has a few commands associated with it.

language:c
BC127Module.setBaudRate(baudRates newSpeed);

This command changes the baud rate of the module. Your choices for parameters to pass are "s9600bps", "s19200bps", "s38400bps", "s57600bps", and "s115200bps".

Return values are a bit trickier here. The change takes place immediately--no reset required--so your serial port won't be set up right to receive the acknowledgement. You can, however, derive some useful information from the return value. If you get "SUCCESS", that means you just set the same value as the current setting. "MODULE_ERROR" indicates that something was wrong with the command, and "INVALID_PARAM" means you passed a bad value. If all went according to plan, you can expect a "TIMEOUT_ERROR".

By default, the SPP connection does not launch in data mode. Two commands are provided for entering and exiting data mode:

language:c
BC127Module.enterDataMode();
BC127Module.exitDataMode();

exitDataMode() automatically provides for the guard delay before and after the string, so you don't have to worry about it. Both can be expected to return either "SUCCESS" or "TIMEOUT_ERROR".

Once you are in data mode, data strings to and from the remote device will be simple strings, and you can treat it as a wired connection. Read and write data with the standard serial port operations for the port you bound to the module with the constructor.

Using the A2DP/AVRCP Connection

We've provided some commands for using the A2DP/AVRCP connection, as well.

language:c
BC127Module.musicCommands(audioCmds command);

This function allows you to send the commands driving the audio control to the module. Parameter options are "PLAY", "PAUSE", "FORWARD", "BACK", and "STOP" for track control, and "UP" and "DOWN" to increase or decrease the volume.

Control of the module's sink and source setting is important for audio applications; to stream audio from one module to another, you need to enable source mode, and to receive audio from another source, you need to make sure the module is in sink mode.

language:c
BC127Module.setClassicSink();
BC127Module.setClassicSource();

These two commands are pretty self-explanatory; note, though, that a writeConfig()/reset(), cycle must be performed after changing this setting.

Other Commands and Parameters

To make things easy for the advance user, we've also included three additional functions that allow you to send any command in the datasheet, and to alter or retrieve any parameter setting.

language:c
BC127Module.stdCmd(String command);
BC127Module.stdGetParam(String command, String *param);
BC127Module.stdSetParam(String command, String param);

Usage is simple; for stdCmd() simply send the string as formatted in the datasheet. The advantage here rather than using a simple serial print statement is that stdCmd() will handle error reporting for you.

For the other two, "command" should be the name of the parameter of interest, and "param" will be everything after the equal sign.