{"id":451,"date":"2017-04-18T12:07:22","date_gmt":"2017-04-18T10:07:22","guid":{"rendered":"http:\/\/systev.com\/?p=451"},"modified":"2020-04-27T08:26:18","modified_gmt":"2020-04-27T06:26:18","slug":"sodaq-explorer-and-bluetooth","status":"publish","type":"post","link":"https:\/\/systev.com\/sodaq-explorer-and-bluetooth\/","title":{"rendered":"SODAQ ExpLoRer and Bluetooth"},"content":{"rendered":"
SODAQ ExpLoRer board<\/a> includes a Microchip RN4871 Bluetooth module<\/a>. This post explains how to start using it.<\/p>\n <\/p>\n Check this post<\/a>.<\/p>\n Once the Microchip_RN487x library is installed, several sample applications are available (File \/ Examples \/ Microchip_RN487x-master<\/strong>), and can be used as references for some test code.<\/p>\n Let’s try to write our first application, that will request and display RN4871 firmware version (that’s always a good idea to check versions of various software building blocks you are about to use).<\/p>\n Source code is below:<\/p>\n Following result is displayed in the monitor window:<\/p>\n According to Microchip website<\/a>, that’s the latest version. Good!<\/p>\n Before going farther, one good practice is to reset the configurations into factory default, to be sure the module will behave according to the documentation. That’s exactly what I had to do: I’m using a second-hand board, and it rapidly appeared that the RN4871 was reacting in an unexpected way to the commands I was sending it. A factory reset put things back in order. The source code is below:<\/p>\n In this test, we configure the RN4871 so that it can be discovered by an Android smartphone, and that it provides one BLE GATT service, with one read characteristic and one write characteristic.<\/p>\n First, install the Microchip Bluetooth Smart Discover<\/em> application<\/a> on the smartphone.<\/p>\n Then, load following program into the board:<\/p>\n This code is derived from one of the samples provided with the library (that’s why I kept Microchip copyright notice). But there is one important difference: I added following line, for the advertisement configuration:<\/p>\nReference documentation<\/h2>\n
\n
Getting started with ExpLoRer<\/h2>\n
First test – get firmware version<\/h2>\n
#include <RN487x_BLE.h>\n\n#define debugSerial SerialUSB\n#define bleSerial Serial1\n\n#define SERIAL_TIMEOUT 10000 \/\/ 10 s\n\nconst char* fwVersion;\n\nvoid setRgbColor(uint8_t red, uint8_t green, uint8_t blue)\n{\n red = 255 - red ;\n green = 255 - green ;\n blue = 255 - blue ;\n\n analogWrite(LED_RED, red) ;\n analogWrite(LED_GREEN, green) ;\n analogWrite(LED_BLUE, blue) ;\n}\n\nvoid setup() {\n\n \/\/ Wait for monitor window to be used, up to SERIAL_TIMEOUT.\n while ((!debugSerial) && (millis() < SERIAL_TIMEOUT));\n debugSerial.begin(115200); \n\n \/\/ Set the optional debug stream\n rn487xBle.setDiag(debugSerial) ;\n \/\/ Initialize the BLE hardware\n rn487xBle.hwInit() ;\n \/\/ Open the communication pipe with the BLE module\n bleSerial.begin(rn487xBle.getDefaultBaudRate()) ;\n \/\/ Assign the BLE serial port to the BLE library\n rn487xBle.initBleStream(&bleSerial) ;\n \/\/ Finalize the init. process\n if (rn487xBle.swInit())\n {\n setRgbColor(0, 255, 0) ;\n debugSerial.println(\"Init. procedure done!\") ;\n }\n else\n {\n setRgbColor(255, 0, 0) ;\n debugSerial.println(\"Init. procedure failed!\") ;\n while(1) ;\n }\n\n}\n\nvoid loop() {\n\n \/\/ BT module must be put in command mode first.\n rn487xBle.enterCommandMode() ;\n \/\/ Request firmware version.\n bool res = rn487xBle.getFirmwareVersion();\n if (!res) {\n debugSerial.println(\"Could not get firmware version. Stopping...\");\n while(1);\n }\n \/\/ At this stage, firmware version was returned by RN4871 module. Get it.\n fwVersion = rn487xBle.getLastResponse();\n if (fwVersion == NULL) {\n debugSerial.println(\"Firmware version can't be read. Stopping...\");\n while(1);\n }\n \/\/ At this stage, we should have the firmware version.\n debugSerial.print(\"Firmware version: \"); \n debugSerial.println(fwVersion);\n \/\/ Now, stop.\n while(1);\n\n}<\/pre>\n
Init. procedure done!\nFirmware version: RN4871 V1.18.3 4\/14\/2016 (c)Microchip Technology Inc<\/pre>\n
#include <RN487x_BLE.h>\n\n#define debugSerial SerialUSB\n#define bleSerial Serial1\n#define SERIAL_TIMEOUT 10000\n\nvoid initLed()\n{\n pinMode(LED_RED, OUTPUT) ;\n pinMode(LED_GREEN, OUTPUT) ;\n pinMode(LED_BLUE, OUTPUT) ; \n}\n\nvoid setRgbColor(uint8_t red, uint8_t green, uint8_t blue)\n{\n red = 255 - red ;\n green = 255 - green ;\n blue = 255 - blue ;\n\n analogWrite(LED_RED, red) ;\n analogWrite(LED_GREEN, green) ;\n analogWrite(LED_BLUE, blue) ;\n}\n\nvoid setup()\n{\n while ((!debugSerial) && (millis() < SERIAL_TIMEOUT)) ;\n \n debugSerial.begin(115200) ;\n\n initLed() ;\n setRgbColor(127, 127, 127) ;\n\n \/\/ Set the optional debug stream\n rn487xBle.setDiag(debugSerial) ;\n \/\/ Initialize the BLE hardware\n rn487xBle.hwInit() ;\n \/\/ Open the communication pipe with the BLE module\n bleSerial.begin(rn487xBle.getDefaultBaudRate()) ;\n \/\/ Assign the BLE serial port to the BLE library\n rn487xBle.initBleStream(&bleSerial) ;\n \/\/ Finalize the init. process\n if (!rn487xBle.swInit()) {\n setRgbColor(127, 0, 0) ;\n debugSerial.println(\"Init. procedure failed!\") ;\n while(1) ; \n }\n \/\/ At this stage, init. succeeded.\n setRgbColor(0, 127, 0) ;\n debugSerial.println(\"Init. procedure done!\") ;\n\n \/\/ Perform factory reset.\n rn487xBle.enterCommandMode();\n if (!rn487xBle.factoryReset()) {\n debugSerial.println(\"Couldn't perform factory reset\");\n setRgbColor(127, 0, 0);\n while(1);\n }\n setRgbColor(127, 127, 0);\n debugSerial.println(\"Factory reset done\") ;\n\n}\n\nvoid loop()\n{\n\n}<\/pre>\n
Second test – GATT service<\/h2>\n
\/\/ Derived from BLE_Peripheral.ino\n\n\/*\n (c) 2016 Microchip Technology Inc. and its subsidiaries. You may use this\n software and any derivatives exclusively with Microchip products.\n\n THIS SOFTWARE IS SUPPLIED BY MICROCHIP \"AS IS\". NO WARRANTIES, WHETHER\n EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED\n WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A\n PARTICULAR PURPOSE, OR ITS INTERACTION WITH MICROCHIP PRODUCTS, COMBINATION\n WITH ANY OTHER PRODUCTS, OR USE IN ANY APPLICATION.\n\n IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE,\n INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND\n WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS\n BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE\n FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN\n ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,\n THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.\n\n MICROCHIP PROVIDES THIS SOFTWARE CONDITIONALLY UPON YOUR ACCEPTANCE OF THESE\n TERMS.\n*\/\n\n#include <RN487x_BLE.h>\n\n#define debugSerial SerialUSB\n#define bleSerial Serial1\n#define SERIAL_TIMEOUT 10000\n\nconst char* myDeviceName = \"testPeriph\" ; \/\/ Custom Device name\nconst char* myPrivateServiceUUID = \"AD11CF40063F11E5BE3E0002A5D5C51B\" ; \/\/ Custom private service UUID\nconst char* temperatureCharacteristicUUID = \"BF3FBD80063F11E59E690002A5D5C501\" ; \/\/ custom characteristic GATT\nconst uint8_t temperatureCharacteristicLen = 2 ; \/\/ data length (in bytes)\nconst uint16_t temperatureHandle = 0x72 ;\nchar temperaturePayload[temperatureCharacteristicLen*2] ;\nfloat temperature_s ;\nuint8_t newTempValue_u8 = 0 ;\nuint8_t prevTempValue_u8 = 0 ;\nconst char* ledCharacteristicUUID = \"BF3FBD80063F11E59E690002A5D5C503\" ; \/\/ custom characteristic GATT\nconst uint8_t ledCharacteristicLen = 6 ;\nuint16_t ledHandle = 0x75 ;\nconst char* ledPayload ;\n\nvoid initLed()\n{\n pinMode(LED_BUILTIN, OUTPUT) ;\n pinMode(LED_RED, OUTPUT) ;\n pinMode(LED_GREEN, OUTPUT) ;\n pinMode(LED_BLUE, OUTPUT) ; \n pinMode(BUTTON, INPUT_PULLUP) ;\n}\n\nvoid turnBlueLedOn()\n{\n digitalWrite(LED_BUILTIN, HIGH) ;\n}\n\nvoid turnBlueLedOff()\n{\n digitalWrite(LED_BUILTIN, LOW) ;\n}\n\nvoid setRgbColor(uint8_t red, uint8_t green, uint8_t blue)\n{\n red = 255 - red ;\n green = 255 - green ;\n blue = 255 - blue ;\n\n analogWrite(LED_RED, red) ;\n analogWrite(LED_GREEN, green) ;\n analogWrite(LED_BLUE, blue) ;\n}\n\nvoid initTemperature()\n{\n pinMode(TEMP_SENSOR, INPUT) ;\n \/\/Set ADC resolution to 12 bits\n analogReadResolution(12) ; \n}\n\nfloat getTemperature()\n{\n float mVolts = (float)analogRead(TEMP_SENSOR) * 3300.0 \/ 1023.0 ;\n float temp = (mVolts - 500.0) \/ 100.0 ;\n return temp ;\n}\n\nvoid setup()\n{\n while ((!debugSerial) && (millis() < SERIAL_TIMEOUT)) ;\n \n debugSerial.begin(115200) ;\n\n initLed() ;\n initTemperature() ;\n\n \/\/ Set the optional debug stream\n rn487xBle.setDiag(debugSerial) ;\n \/\/ Initialize the BLE hardware\n rn487xBle.hwInit() ;\n \/\/ Open the communication pipe with the BLE module\n bleSerial.begin(rn487xBle.getDefaultBaudRate()) ;\n \/\/ Assign the BLE serial port to the BLE library\n rn487xBle.initBleStream(&bleSerial) ;\n \/\/ Finalize the init. process\n if (rn487xBle.swInit())\n {\n setRgbColor(0, 255, 0) ;\n debugSerial.println(\"Init. procedure done!\") ;\n }\n else\n {\n setRgbColor(255, 0, 0) ;\n debugSerial.println(\"Init. procedure failed!\") ;\n while(1) ;\n }\n\n \/\/ Fist, enter into command mode\n rn487xBle.enterCommandMode() ;\n \/\/ Stop advertising before starting the demo\n rn487xBle.stopAdvertising() ;\n \/\/ Set the advertising output power (range: min = 5, max = 0)\n rn487xBle.setAdvPower(3) ;\n \/\/ Set the serialized device name, i.e. device n,ame + 2 last bytes from MAC address.\n rn487xBle.setSerializedName(myDeviceName) ;\n rn487xBle.clearAllServices() ;\n rn487xBle.reboot() ;\n rn487xBle.enterCommandMode() ; \n \/\/ Set a private service ...\n rn487xBle.setServiceUUID(myPrivateServiceUUID) ;\n \/\/ which contains ...\n \/\/ ...a temperature characteristic; readable and can perform notification, 2-octets size\n rn487xBle.setCharactUUID(temperatureCharacteristicUUID, READ_PROPERTY | NOTIFY_PROPERTY, temperatureCharacteristicLen) ;\n \/\/ ...an LED characteristic; properties: writable\n rn487xBle.setCharactUUID(ledCharacteristicUUID, WRITE_PROPERTY, ledCharacteristicLen) ; \n \/\/ take into account the settings by issuing a reboot\n rn487xBle.reboot() ;\n rn487xBle.enterCommandMode() ;\n \/\/ Clear adv. packet\n rn487xBle.clearImmediateAdvertising() ;\n \/\/ Start adv.\n \/\/ The line below is required, to let an Android device discover the board. \n rn487xBle.startImmediateAdvertising(AD_TYPE_FLAGS, \"06\");\n rn487xBle.startImmediateAdvertising(AD_TYPE_MANUFACTURE_SPECIFIC_DATA, \"CD00FE14AD11CF40063F11E5BE3E0002A5D5C51B\") ;\n\n debugSerial.println(\"Starter Kit as a Peripheral with private service\") ;\n debugSerial.println(\"================================================\") ;\n debugSerial.print(\"Private service: \") ;\n debugSerial.println(myPrivateServiceUUID) ;\n debugSerial.print(\"Private characteristic used for the Temperature: \") ;\n debugSerial.println(temperatureCharacteristicUUID) ;\n debugSerial.print(\"Private characteristic used for the LED: \") ;\n debugSerial.println(ledCharacteristicUUID) ;\n debugSerial.println(\"You can now establish a connection from the Microchip SmartDiscovery App\") ;\n debugSerial.print(\"with the starter kit: \") ;\n debugSerial.println(rn487xBle.getDeviceName()) ;\n\n}\n\nvoid loop()\n{\n \/\/ Check the connection status\n if (rn487xBle.getConnectionStatus())\n {\n \/\/ Connected to a peer\n debugSerial.print(\"Connected to a peer central \") ;\n debugSerial.println(rn487xBle.getLastResponse()) ;\n\n \/\/ Temperature\n prevTempValue_u8 = newTempValue_u8 ;\n temperature_s = getTemperature() ;\n newTempValue_u8 = (int)temperature_s ;\n \/\/ Update the local characteristic only if value has changed\n if (newTempValue_u8 != prevTempValue_u8)\n {\n uint8_t data = newTempValue_u8 ;\n temperaturePayload[3] = '0' + (data % 10) ; \/\/ LSB\n data \/= 10 ;\n temperaturePayload[2] = '0' + (data % 10) ;\n data \/= 10 ;\n temperaturePayload[1] = '0' + (data % 10) ;\n if (temperature_s > 0) temperaturePayload[0] = '0' ; \/\/ MSB = 0, positive temp.\n else temperaturePayload[0] = '8' ; \/\/ MSB = 1, negative temp. \n \n if (rn487xBle.writeLocalCharacteristic(temperatureHandle, temperaturePayload))\n {\n debugSerial.print(\"Temperature characteristic has been updated with the value = \") ; debugSerial.println(newTempValue_u8) ;\n }\n }\n\n \/\/ LED\n if (rn487xBle.readLocalCharacteristic(ledHandle))\n {\n \/\/ Read the local characteristic written by the client: smartphone\/tablet\n \/\/ The payload must follow the 6-bit RGB coded format:\n \/\/ [0] Red MSB\n \/\/ [1] Red LSB\n \/\/ [2] Green MSB\n \/\/ [3] Green LSB\n \/\/ [4] Blue MSB\n \/\/ [5] Blue LSB\n \/\/ Each color can be coded from range 0x00 to 0xFF\n ledPayload = rn487xBle.getLastResponse() ;\n if (ledPayload != NULL)\n {\n if (ledPayload[0] != 'N') \/\/ != \"N\/A\" response\n {\n debugSerial.println(ledPayload) ;\n if (strlen(ledPayload) == ledCharacteristicLen)\n {\n \/\/ Filter only the 6-digit len\n \/\/ Convert ASCII to integer values\n uint8_t r = (ledPayload[0] - '0') * 10 + (ledPayload[1] - '0') ;\n uint8_t g = (ledPayload[2] - '0') * 10 + (ledPayload[3] - '0') ;\n uint8_t b = (ledPayload[4] - '0') * 10 + (ledPayload[5] - '0') ;\n setRgbColor(r, g, b) ;\n }\n }\n }\n } \n }\n else\n {\n \/\/ Not connected to a peer device\n debugSerial.println(\"Not connected to a peer device\") ;\n }\n \/\/ Delay inter connection polling\n delay(3000) ;\n}<\/pre>\n
rn487xBle.startImmediateAdvertising(AD_TYPE_FLAGS, \"06\");<\/pre>\n