I was looking for a system able to work with an iPhone (Bluetooth Low Emission – LBE) and a standard android (Standard bluetooth / rfcom). The RFDuino Arduino platform I have is perfect for BLE so, I decided to add a HC-05 module for the standard bluetooth.
Here is the description on how to make it !
First step : cabling the two circuits
Coming soon …
Second step : writing initialization code
HC-05 bluetooth shield need to be initialized the first time. I don’t want to detail because there is another article on HC-05 and a lot of documentation on this component online.
But the main issue to manage is to be able to do this configuration online once on the first startup. This means we are able to store in the RFduino we already have make the configuration. The good thing is that we are able to write into the flash from the arduino code and store a flag to indicate that it has been done. My flag is the version, so if I upgrade the rfduino with a new version of code I will reconfigure the hc-05. (as this new version could change the configuration).
The second issue to manage is the software reset : once the hc-05 is configured, both rfduino and hc-05 have to be restarted to take the configuration into account. This can be done for the two calling the right reset function.
Here is the code to be used for this initialization:
// Map HC-05 Serial #define blueToothSerial Serial int key = 4; void setup() { pinMode(key, OUTPUT); if ( ! isConfigured() ) { digitalWrite(key,HIGH); // switch to command mode delay(500); if ( getHC05Connection() ) { // Initial setup sendHC05AtCmd("AT+INIT",true); // Init SPP delay(2000); sendHC05AtCmd("AT+NAME=MyName",true); // BT displayed name sendHC05AtCmd("AT+PSWD=0000",true); // pairing password is 0000 sendHC05AtCmd("AT+UART=38400,0,0",true); // serial over BT rate + Arduino rate (next restart) sendHC05AtCmd("AT+IAC=9e8b33",true); // use a Password for pairing sendHC05AtCmd("AT+CMODE=1",true); // connect to any address sendHC05AtCmd("AT+CLASS=40500",true); // this bt device type ?? delay(1000); // restart sendHC05AtCmd("AT+RESET",true); digitalWrite(key,LOW); // switch to DAT MODE delay(2000); saveConfigured(); // Register configuration has been made RFduino_systemReset(); // reset while(1); } while (1); // Error loop } else { digitalWrite(key,LOW); // switch to DATA mode // Connect HC-05 blueToothSerial.begin(38400); // Bluetooth init RFduinoBLE.deviceName = "MyName"; RFduinoBLE.advertisementData = "MyName"; RFduinoBLE.advertisementInterval = MILLISECONDS(200); RFduinoBLE.txPowerLevel = -4; // (-20dbM to +4 dBm) RFduinoBLE.begin(); delay(1000); } } /* ================================================================= * CONFIGURATION SUBROUTINE * ================================================================= */ #define VERSION 0x000100 struct config_t { int version_number; }; #define CONFIG_PAGE 251 struct config_t * config = (config_t*)ADDRESS_OF_PAGE(CONFIG_PAGE); void saveConfigured() { flashPageErase(CONFIG_PAGE); struct config_t v; v.version_number = VERSION; flashWriteBlock(config, &v, sizeof(v)); } bool isConfigured() { return ( config->version_number == VERSION ); } /* ================================================================= * HC-05 SUBROUTINE * ================================================================= */ unsigned long rates[3]; #define hex2dec(x) ((x>'9')?10+x-'A':x-'0') // -- Internal #define COD_FAIL 30 #define BUFSZ 50 boolean getHC05Connection() { rates[0] = 38400; rates[2] = 115200; rates[3] = 9600; int numRates = sizeof(rates)/sizeof(unsigned long); int recvd = 0; char _buffer[128]; int _bufsize = sizeof(_buffer)/sizeof(char); for(int rn = 0; rn < numRates; rn++) { blueToothSerial.begin(rates[rn]); blueToothSerial.setTimeout(200); blueToothSerial.write("AT\r\n"); delay(200); recvd = blueToothSerial.readBytes(_buffer,_bufsize); if (recvd > 0) { return true; } } return false; } /* --- Send AT Command and get Error code back * immediate : when true directly read result, do not wait them to come * make sense when you are not waiting for a remote device answer * */ int sendHC05AtCmd(char * atcmdstr, boolean imediate) { int recvd = 0; char _buffer[128]; int _bufsize = sizeof(_buffer)/sizeof(char); int ret=-1; blueToothSerial.print(atcmdstr); blueToothSerial.print("\r\n"); delay(200); while ( ( recvd = blueToothSerial.readBytes(_buffer,_bufsize) ) == 0 && (! imediate) ) delay(100); if (recvd >= 2) { if ( _buffer[0] == 'O' && _buffer[1] == 'K' ) ret=-1; else if ( _buffer[0] == 'E' ) { // Get Error number if _buffer[8] = ')' then 1 digit error code, else 2 digit if ( recvd >= 9 ) { ret = ( _buffer[8] != ')' )?16*(hex2dec(_buffer[7]))+(hex2dec(_buffer[8])):hex2dec(_buffer[7]); print_debug2(" * Error code : ",ret); } } else if ( _buffer[0] == 'F' ) { ret=COD_FAIL; } } // Other cases : consider as valid command return ret; }
Third step : manage reception from both bluetooth devices
RFduino and HC-05 are working differently. RFduino is using callback function working with interrupts, Serial port, basically works with polling. To simplify my code I chose to work in ASCII mode with both. HC-05 uses lines (finishing by “\r\n”) LBE mode uses byte array.
/* ===================================================== * LBE - Communication subroutine * ===================================================== */ void RFduinoBLE_onReceive(char *data, int len) { uint8_t _blebuff[256]; int i=0; while ( i < len && i < 254 ) { _blebuff[i] = data[i]; i++; } _blebuff[i] = 0; uint8_t ret = proceedline(_blebuff, i); RFduinoBLE.sendByte(ret); } /* ===================================================== * HC-05 - Communication subroutine * ===================================================== */ uint8_t hc05_buffer[256]; int hc05_max = 250; int hc05_count = 0; void hc5Receive() { char hc05_ret[4]; int v; while ( blueToothSerial.available() > 0 ) { v = blueToothSerial.read(); if ( v == -1 ) break; if ( hc05_count >= hc05_max ) { hc05_count = 0; continue; } if ( (char)v == '\n' ) { hc05_buffer[hc05_count]=0; // end of line hc05_count++; // to count \n hc05_ret[0] = proceedline(hc05_buffer, hc05_count); hc05_ret[1] = '\r'; hc05_ret[2]='\n'; hc05_ret[3] = 0; send_hc_05(hc05_ret); hc05_count=0; } else { hc05_buffer[hc05_count]=(uint8_t)(v); hc05_count++; } } }
The proceedline function executes the process you want on the received data from both bluetooth connection