Port of RedBear BLE Shield Arduino Sketch to RedBear Nano. This firmware enables BLE clients to initialize, read and write Nano pins over the air via Bluetooth, using the same protocol used by Redbear BLE Shield. This enables working with Nano devices from any SAndroidE powered application (http://es3.unibs.it/SAndroidE/).

Dependencies:   BLE_API mbed nRF51822 MbedJSONValue

Committer:
giowild
Date:
Mon Nov 28 10:58:38 2016 +0000
Revision:
0:8d3dd6e411bf
Child:
1:ff6ec7837f46
First working release

Who changed what in which revision?

UserRevisionLine numberNew contents of line
giowild 0:8d3dd6e411bf 1 /*
giowild 0:8d3dd6e411bf 2
giowild 0:8d3dd6e411bf 3 Copyright (c) 2016 Giovanni Lenzi
giowild 0:8d3dd6e411bf 4
giowild 0:8d3dd6e411bf 5 */
giowild 0:8d3dd6e411bf 6
giowild 0:8d3dd6e411bf 7 /*
giowild 0:8d3dd6e411bf 8 * This firmware is a port the RedBear BLE Shield Arduino Sketch(https://github.com/RedBearLab/nRF8001/blob/master/examples/BLEControllerSketch/BLEControllerSketch.ino),
giowild 0:8d3dd6e411bf 9 * to Redbear Nano (http://redbearlab.com/blenano/).
giowild 0:8d3dd6e411bf 10 * After connection of Nano to PC using the provided MK20 USB board,
giowild 0:8d3dd6e411bf 11 * you need to download the compiled firmware to your local disk
giowild 0:8d3dd6e411bf 12 * and drag and drop it to the newly created MBED drive.
giowild 0:8d3dd6e411bf 13 * Once flashed, you may access your Nano device with the NanoChat test application
giowild 0:8d3dd6e411bf 14 * or from any SAndroidE powered application (http://es3.unibs.it/SAndroidE/)
giowild 0:8d3dd6e411bf 15 */
giowild 0:8d3dd6e411bf 16
giowild 0:8d3dd6e411bf 17 #include "mbed.h"
giowild 0:8d3dd6e411bf 18 #include "ble/BLE.h"
giowild 0:8d3dd6e411bf 19
giowild 0:8d3dd6e411bf 20 #define BLE_UUID_TXRX_SERVICE 0x0000 /**< The UUID of the Nordic UART Service. */
giowild 0:8d3dd6e411bf 21 #define BLE_UUID_TX_CHARACTERISTIC 0x0002 /**< The UUID of the TX Characteristic. */
giowild 0:8d3dd6e411bf 22 #define BLE_UUIDS_RX_CHARACTERISTIC 0x0003 /**< The UUID of the RX Characteristic. */
giowild 0:8d3dd6e411bf 23
giowild 0:8d3dd6e411bf 24 #define TXRX_BUF_LEN 20
giowild 0:8d3dd6e411bf 25
giowild 0:8d3dd6e411bf 26 // pin modes
giowild 0:8d3dd6e411bf 27 #define PIN_INPUT 0 // digital input pin
giowild 0:8d3dd6e411bf 28 #define PIN_OUTPUT 1 // digital output pin
giowild 0:8d3dd6e411bf 29 #define PIN_ANALOG 2 // analog pin in analogInput mode
giowild 0:8d3dd6e411bf 30 #define PIN_PWM 3 // digital pin in PWM output mode
giowild 0:8d3dd6e411bf 31 #define PIN_SERVO 4 // digital pin in Servo output mode
giowild 0:8d3dd6e411bf 32 #define PIN_NOTSET 5 // pin not set
giowild 0:8d3dd6e411bf 33
giowild 0:8d3dd6e411bf 34 BLE ble;
giowild 0:8d3dd6e411bf 35
giowild 0:8d3dd6e411bf 36 // The Nordic UART Service
giowild 0:8d3dd6e411bf 37 static const uint8_t uart_base_uuid[] = {0x71, 0x3D, 0, 0, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E};
giowild 0:8d3dd6e411bf 38 static const uint8_t uart_tx_uuid[] = {0x71, 0x3D, 0, 3, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E};
giowild 0:8d3dd6e411bf 39 static const uint8_t uart_rx_uuid[] = {0x71, 0x3D, 0, 2, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E};
giowild 0:8d3dd6e411bf 40 static const uint8_t uart_base_uuid_rev[] = {0x1E, 0x94, 0x8D, 0xF1, 0x48, 0x31, 0x94, 0xBA, 0x75, 0x4C, 0x3E, 0x50, 0, 0, 0x3D, 0x71};
giowild 0:8d3dd6e411bf 41
giowild 0:8d3dd6e411bf 42 uint8_t payloadTicker[TXRX_BUF_LEN] = {0,};
giowild 0:8d3dd6e411bf 43 uint8_t txPayload[TXRX_BUF_LEN] = {0,};
giowild 0:8d3dd6e411bf 44 uint8_t rxPayload[TXRX_BUF_LEN] = {0,};
giowild 0:8d3dd6e411bf 45
giowild 0:8d3dd6e411bf 46 GattCharacteristic txCharacteristic (uart_tx_uuid, txPayload, 1, TXRX_BUF_LEN, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE);
giowild 0:8d3dd6e411bf 47 GattCharacteristic rxCharacteristic (uart_rx_uuid, rxPayload, 1, TXRX_BUF_LEN, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
giowild 0:8d3dd6e411bf 48 GattCharacteristic *uartChars[] = {&txCharacteristic, &rxCharacteristic};
giowild 0:8d3dd6e411bf 49 GattService uartService(uart_base_uuid, uartChars, sizeof(uartChars) / sizeof(GattCharacteristic *));
giowild 0:8d3dd6e411bf 50
giowild 0:8d3dd6e411bf 51 static const int maxPins = 30;
giowild 0:8d3dd6e411bf 52 uint8_t pinTypes[maxPins];
giowild 0:8d3dd6e411bf 53 uint16_t prevValues[maxPins];
giowild 0:8d3dd6e411bf 54
giowild 0:8d3dd6e411bf 55 DigitalInOut digitals[] = {P0_0,P0_7,P0_15,P0_19,P0_28,P0_29};
giowild 0:8d3dd6e411bf 56 int mapDigitals[] = { 0,-1,-1,-1,-1,-1,-1, 1,-1,-1,-1,-1,-1,-1,-1, 2,-1,-1,-1, 3,-1,-1,-1,-1,-1,-1,-1,-1, 4, 5,-1};
giowild 0:8d3dd6e411bf 57 AnalogIn analogs[] = {P0_1, P0_2, P0_3, P0_4, P0_5, P0_6};
giowild 0:8d3dd6e411bf 58 int mapAnalogs[] = {-1, 0, 1, 2, 3, 4, 5,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
giowild 0:8d3dd6e411bf 59
giowild 0:8d3dd6e411bf 60
giowild 0:8d3dd6e411bf 61 void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params)
giowild 0:8d3dd6e411bf 62 {
giowild 0:8d3dd6e411bf 63 //pc.printf("Disconnected \r\n");
giowild 0:8d3dd6e411bf 64 //pc.printf("Restart advertising \r\n");
giowild 0:8d3dd6e411bf 65 ble.startAdvertising();
giowild 0:8d3dd6e411bf 66 }
giowild 0:8d3dd6e411bf 67
giowild 0:8d3dd6e411bf 68 bool initPin(int pin, uint8_t type){
giowild 0:8d3dd6e411bf 69 bool ret=false;
giowild 0:8d3dd6e411bf 70 if (pin>=0 && pin<31) { // "initPin(): Pin number out of bounds"
giowild 0:8d3dd6e411bf 71 if ((type==PIN_INPUT||type==PIN_OUTPUT) && mapDigitals[pin]>=0) {
giowild 0:8d3dd6e411bf 72 if (type==PIN_INPUT) digitals[mapDigitals[pin]].input(); // initialize as input
giowild 0:8d3dd6e411bf 73 if (type==PIN_OUTPUT) digitals[mapDigitals[pin]].output(); // initialize as input
giowild 0:8d3dd6e411bf 74 pinTypes[pin] = type; // mark the pin as initialized
giowild 0:8d3dd6e411bf 75 ret =true;
giowild 0:8d3dd6e411bf 76 } else if (type==PIN_ANALOG && mapAnalogs[pin]>=0) {
giowild 0:8d3dd6e411bf 77 pinTypes[pin] = type; // mark the pin as initialized
giowild 0:8d3dd6e411bf 78 ret =true;
giowild 0:8d3dd6e411bf 79 }
giowild 0:8d3dd6e411bf 80 }
giowild 0:8d3dd6e411bf 81 return ret;
giowild 0:8d3dd6e411bf 82 }
giowild 0:8d3dd6e411bf 83
giowild 0:8d3dd6e411bf 84 uint16_t readPin(int pin) {
giowild 0:8d3dd6e411bf 85 uint8_t mode = pinTypes[pin];
giowild 0:8d3dd6e411bf 86 if (mode==PIN_INPUT) { // exists and is initialized as digital output
giowild 0:8d3dd6e411bf 87 mode = 0;
giowild 0:8d3dd6e411bf 88 return (((uint16_t)mode)<<8 | (uint16_t)(digitals[mapDigitals[pin]].read()));
giowild 0:8d3dd6e411bf 89 } else if (mode==PIN_OUTPUT) { // exists and is initialized as digital output
giowild 0:8d3dd6e411bf 90 mode = 1;
giowild 0:8d3dd6e411bf 91 return (((uint16_t)mode)<<8 | (uint16_t)(digitals[mapDigitals[pin]].read()));
giowild 0:8d3dd6e411bf 92 } else if (mode==PIN_ANALOG) { // exists and is initialized as digital output
giowild 0:8d3dd6e411bf 93 mode = 2;
giowild 0:8d3dd6e411bf 94 uint16_t value = analogs[mapAnalogs[pin]].read_u16();
giowild 0:8d3dd6e411bf 95 uint8_t value_lo = value;
giowild 0:8d3dd6e411bf 96 uint8_t value_hi = value>>8;
giowild 0:8d3dd6e411bf 97 mode = (value_hi << 4) | mode;
giowild 0:8d3dd6e411bf 98 return (((uint16_t)mode)<<8) | (uint16_t)value_lo;
giowild 0:8d3dd6e411bf 99 }
giowild 0:8d3dd6e411bf 100 return 0;
giowild 0:8d3dd6e411bf 101 }
giowild 0:8d3dd6e411bf 102
giowild 0:8d3dd6e411bf 103 void sendPinValue(int pin, uint16_t value) {
giowild 0:8d3dd6e411bf 104 uint8_t buf[TXRX_BUF_LEN];
giowild 0:8d3dd6e411bf 105 buf[0]='G';
giowild 0:8d3dd6e411bf 106 buf[1]=pin;
giowild 0:8d3dd6e411bf 107 buf[2]=(uint8_t)(value>>8); buf[3]=(uint8_t)value;
giowild 0:8d3dd6e411bf 108 ble.updateCharacteristicValue(rxCharacteristic.getValueAttribute().getHandle(), buf, 4);
giowild 0:8d3dd6e411bf 109 prevValues[pin] = value;
giowild 0:8d3dd6e411bf 110 }
giowild 0:8d3dd6e411bf 111
giowild 0:8d3dd6e411bf 112 void parseRedBearCmd(){
giowild 0:8d3dd6e411bf 113 uint8_t buf[TXRX_BUF_LEN];
giowild 0:8d3dd6e411bf 114 memset(buf, 0, TXRX_BUF_LEN);
giowild 0:8d3dd6e411bf 115
giowild 0:8d3dd6e411bf 116 uint8_t startOffset = txPayload[0]==0?1:0;
giowild 0:8d3dd6e411bf 117 uint8_t index = startOffset;
giowild 0:8d3dd6e411bf 118 uint8_t cmd = txPayload[index++], pin=txPayload[index++], mode=PIN_NOTSET;
giowild 0:8d3dd6e411bf 119 pin = pin>=48?pin-48:pin;
giowild 0:8d3dd6e411bf 120
giowild 0:8d3dd6e411bf 121 switch (cmd) {
giowild 0:8d3dd6e411bf 122 case 'Z':sendPinValue(pin,readPin(pin));
giowild 0:8d3dd6e411bf 123 break;
giowild 0:8d3dd6e411bf 124 case 'X':initPin(7, PIN_OUTPUT);
giowild 0:8d3dd6e411bf 125 break;
giowild 0:8d3dd6e411bf 126 case 'Y':uint8_t value2write = txPayload[index++]-48;
giowild 0:8d3dd6e411bf 127 if (mapDigitals[pin]>=0) {
giowild 0:8d3dd6e411bf 128 digitals[mapDigitals[pin]].write(value2write==0?0:1);
giowild 0:8d3dd6e411bf 129 sendPinValue(pin,readPin(pin));
giowild 0:8d3dd6e411bf 130 }
giowild 0:8d3dd6e411bf 131 break;
giowild 0:8d3dd6e411bf 132
giowild 0:8d3dd6e411bf 133 case 'M': //pc.printf("Querying pin %u mode\n",pin);
giowild 0:8d3dd6e411bf 134 buf[0]=cmd;
giowild 0:8d3dd6e411bf 135 buf[1]=pin;
giowild 0:8d3dd6e411bf 136 buf[2]=pinTypes[pin];
giowild 0:8d3dd6e411bf 137 ble.updateCharacteristicValue(rxCharacteristic.getValueAttribute().getHandle(), buf, 3);
giowild 0:8d3dd6e411bf 138 break;
giowild 0:8d3dd6e411bf 139
giowild 0:8d3dd6e411bf 140 case 'S': // set pin mode
giowild 0:8d3dd6e411bf 141 mode = txPayload[index++];
giowild 0:8d3dd6e411bf 142 mode = mode>=48?mode-48:mode;
giowild 0:8d3dd6e411bf 143 if (initPin(pin, mode)) { // analogs are already initialized
giowild 0:8d3dd6e411bf 144 sendPinValue(pin,readPin(pin));
giowild 0:8d3dd6e411bf 145 }
giowild 0:8d3dd6e411bf 146 break;
giowild 0:8d3dd6e411bf 147
giowild 0:8d3dd6e411bf 148 case 'G': //pc.printf("Reading pin %u\n",pin);
giowild 0:8d3dd6e411bf 149 switch (pinTypes[pin]) {
giowild 0:8d3dd6e411bf 150 case PIN_INPUT:
giowild 0:8d3dd6e411bf 151 case PIN_ANALOG:
giowild 0:8d3dd6e411bf 152 sendPinValue(pin,readPin(pin));
giowild 0:8d3dd6e411bf 153 break;
giowild 0:8d3dd6e411bf 154 case PIN_OUTPUT: // TODO: send warning pin not readable (is an output)
giowild 0:8d3dd6e411bf 155 default: // TODO: send warning pin not initialized
giowild 0:8d3dd6e411bf 156 buf[0]=PIN_NOTSET;
giowild 0:8d3dd6e411bf 157 buf[1]=PIN_NOTSET;
giowild 0:8d3dd6e411bf 158 buf[2]=PIN_NOTSET;
giowild 0:8d3dd6e411bf 159 ble.updateCharacteristicValue(rxCharacteristic.getValueAttribute().getHandle(), buf, 3);
giowild 0:8d3dd6e411bf 160 break;
giowild 0:8d3dd6e411bf 161 }
giowild 0:8d3dd6e411bf 162 break;
giowild 0:8d3dd6e411bf 163
giowild 0:8d3dd6e411bf 164 case 'T':
giowild 0:8d3dd6e411bf 165 switch (pinTypes[pin]) {
giowild 0:8d3dd6e411bf 166 case PIN_OUTPUT:
giowild 0:8d3dd6e411bf 167 uint8_t value2write = txPayload[index++];
giowild 0:8d3dd6e411bf 168 if (mapDigitals[pin]>=0) {
giowild 0:8d3dd6e411bf 169 digitals[mapDigitals[pin]].write(value2write==0?0:1);
giowild 0:8d3dd6e411bf 170 sendPinValue(pin,readPin(pin));
giowild 0:8d3dd6e411bf 171 }
giowild 0:8d3dd6e411bf 172 break;
giowild 0:8d3dd6e411bf 173 case PIN_INPUT: // TODO: send warning pin not writable (is an input)
giowild 0:8d3dd6e411bf 174 case PIN_ANALOG: // TODO: send warning pin not writable (is an input)
giowild 0:8d3dd6e411bf 175 default: // TODO: send warning pin not initialized
giowild 0:8d3dd6e411bf 176 buf[0]='T';
giowild 0:8d3dd6e411bf 177 buf[1]='T';
giowild 0:8d3dd6e411bf 178 buf[2]='T';
giowild 0:8d3dd6e411bf 179 ble.updateCharacteristicValue(rxCharacteristic.getValueAttribute().getHandle(), buf, 3);
giowild 0:8d3dd6e411bf 180 break;
giowild 0:8d3dd6e411bf 181 }
giowild 0:8d3dd6e411bf 182 break;
giowild 0:8d3dd6e411bf 183
giowild 0:8d3dd6e411bf 184 default:
giowild 0:8d3dd6e411bf 185 // echo received buffer
giowild 0:8d3dd6e411bf 186 ble.updateCharacteristicValue(rxCharacteristic.getValueAttribute().getHandle(), &txPayload[startOffset], strlen((char *)&txPayload[startOffset])); // FIXME
giowild 0:8d3dd6e411bf 187 break;
giowild 0:8d3dd6e411bf 188 }
giowild 0:8d3dd6e411bf 189 }
giowild 0:8d3dd6e411bf 190
giowild 0:8d3dd6e411bf 191
giowild 0:8d3dd6e411bf 192 void WrittenHandler(const GattWriteCallbackParams *Handler)
giowild 0:8d3dd6e411bf 193 {
giowild 0:8d3dd6e411bf 194 uint8_t buf[TXRX_BUF_LEN];
giowild 0:8d3dd6e411bf 195 uint16_t bytesRead;
giowild 0:8d3dd6e411bf 196
giowild 0:8d3dd6e411bf 197 if (Handler->handle == txCharacteristic.getValueAttribute().getHandle()) //only if empty
giowild 0:8d3dd6e411bf 198 {
giowild 0:8d3dd6e411bf 199 ble.readCharacteristicValue(txCharacteristic.getValueAttribute().getHandle(), buf, &bytesRead);
giowild 0:8d3dd6e411bf 200 memset(txPayload, 0, TXRX_BUF_LEN);
giowild 0:8d3dd6e411bf 201 memcpy(txPayload, buf, TXRX_BUF_LEN);
giowild 0:8d3dd6e411bf 202
giowild 0:8d3dd6e411bf 203 ble.updateCharacteristicValue(rxCharacteristic.getValueAttribute().getHandle(), buf, bytesRead);
giowild 0:8d3dd6e411bf 204 parseRedBearCmd();
giowild 0:8d3dd6e411bf 205 }
giowild 0:8d3dd6e411bf 206 }
giowild 0:8d3dd6e411bf 207
giowild 0:8d3dd6e411bf 208 void m_status_check_handle(void)
giowild 0:8d3dd6e411bf 209 {
giowild 0:8d3dd6e411bf 210 for (int pin=0; pin<maxPins;pin++){
giowild 0:8d3dd6e411bf 211 if (pinTypes[pin]==PIN_INPUT||pinTypes[pin]==PIN_ANALOG) {
giowild 0:8d3dd6e411bf 212 uint16_t value = readPin(pin);
giowild 0:8d3dd6e411bf 213 //uint16_t prevValue = 33;
giowild 0:8d3dd6e411bf 214 if (prevValues[pin] != value) {
giowild 0:8d3dd6e411bf 215 sendPinValue(pin,value);
giowild 0:8d3dd6e411bf 216 }
giowild 0:8d3dd6e411bf 217 }
giowild 0:8d3dd6e411bf 218 }
giowild 0:8d3dd6e411bf 219 }
giowild 0:8d3dd6e411bf 220
giowild 0:8d3dd6e411bf 221 int main(void)
giowild 0:8d3dd6e411bf 222 {
giowild 0:8d3dd6e411bf 223 for (int i=0;i<maxPins;i++) {
giowild 0:8d3dd6e411bf 224 pinTypes[i] = PIN_NOTSET;
giowild 0:8d3dd6e411bf 225 prevValues[i] = 0;
giowild 0:8d3dd6e411bf 226 }
giowild 0:8d3dd6e411bf 227
giowild 0:8d3dd6e411bf 228 //memset(txPayload, 0, TXRX_BUF_LEN);
giowild 0:8d3dd6e411bf 229
giowild 0:8d3dd6e411bf 230 ble.init();
giowild 0:8d3dd6e411bf 231 ble.onDisconnection(disconnectionCallback);
giowild 0:8d3dd6e411bf 232 ble.onDataWritten(WrittenHandler);
giowild 0:8d3dd6e411bf 233
giowild 0:8d3dd6e411bf 234 // setup advertising
giowild 0:8d3dd6e411bf 235 ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED);
giowild 0:8d3dd6e411bf 236 ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
giowild 0:8d3dd6e411bf 237 ble.accumulateAdvertisingPayload(GapAdvertisingData::SHORTENED_LOCAL_NAME,
giowild 0:8d3dd6e411bf 238 (const uint8_t *)"MyNano", sizeof("MyNano") - 1);
giowild 0:8d3dd6e411bf 239 ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS,
giowild 0:8d3dd6e411bf 240 (const uint8_t *)uart_base_uuid_rev, sizeof(uart_base_uuid));
giowild 0:8d3dd6e411bf 241 // 100ms; in multiples of 0.625ms.
giowild 0:8d3dd6e411bf 242 ble.setAdvertisingInterval(160);
giowild 0:8d3dd6e411bf 243
giowild 0:8d3dd6e411bf 244 ble.addService(uartService);
giowild 0:8d3dd6e411bf 245
giowild 0:8d3dd6e411bf 246 ble.startAdvertising();
giowild 0:8d3dd6e411bf 247
giowild 0:8d3dd6e411bf 248 Ticker ticker;
giowild 0:8d3dd6e411bf 249 ticker.attach(m_status_check_handle, 0.2);
giowild 0:8d3dd6e411bf 250
giowild 0:8d3dd6e411bf 251 while(1)
giowild 0:8d3dd6e411bf 252 {
giowild 0:8d3dd6e411bf 253 ble.waitForEvent();
giowild 0:8d3dd6e411bf 254 }
giowild 0:8d3dd6e411bf 255 }
giowild 0:8d3dd6e411bf 256
giowild 0:8d3dd6e411bf 257
giowild 0:8d3dd6e411bf 258
giowild 0:8d3dd6e411bf 259
giowild 0:8d3dd6e411bf 260
giowild 0:8d3dd6e411bf 261
giowild 0:8d3dd6e411bf 262
giowild 0:8d3dd6e411bf 263
giowild 0:8d3dd6e411bf 264
giowild 0:8d3dd6e411bf 265
giowild 0:8d3dd6e411bf 266
giowild 0:8d3dd6e411bf 267
giowild 0:8d3dd6e411bf 268
giowild 0:8d3dd6e411bf 269
giowild 0:8d3dd6e411bf 270
giowild 0:8d3dd6e411bf 271