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
Diff: main.cpp
- Revision:
- 0:8d3dd6e411bf
- Child:
- 1:ff6ec7837f46
diff -r 000000000000 -r 8d3dd6e411bf main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Mon Nov 28 10:58:38 2016 +0000 @@ -0,0 +1,271 @@ +/* + +Copyright (c) 2016 Giovanni Lenzi + +*/ + +/* + * This firmware is a port the RedBear BLE Shield Arduino Sketch(https://github.com/RedBearLab/nRF8001/blob/master/examples/BLEControllerSketch/BLEControllerSketch.ino), + * to Redbear Nano (http://redbearlab.com/blenano/). + * After connection of Nano to PC using the provided MK20 USB board, + * you need to download the compiled firmware to your local disk + * and drag and drop it to the newly created MBED drive. + * Once flashed, you may access your Nano device with the NanoChat test application + * or from any SAndroidE powered application (http://es3.unibs.it/SAndroidE/) + */ + +#include "mbed.h" +#include "ble/BLE.h" + +#define BLE_UUID_TXRX_SERVICE 0x0000 /**< The UUID of the Nordic UART Service. */ +#define BLE_UUID_TX_CHARACTERISTIC 0x0002 /**< The UUID of the TX Characteristic. */ +#define BLE_UUIDS_RX_CHARACTERISTIC 0x0003 /**< The UUID of the RX Characteristic. */ + +#define TXRX_BUF_LEN 20 + +// pin modes +#define PIN_INPUT 0 // digital input pin +#define PIN_OUTPUT 1 // digital output pin +#define PIN_ANALOG 2 // analog pin in analogInput mode +#define PIN_PWM 3 // digital pin in PWM output mode +#define PIN_SERVO 4 // digital pin in Servo output mode +#define PIN_NOTSET 5 // pin not set + +BLE ble; + +// The Nordic UART Service +static const uint8_t uart_base_uuid[] = {0x71, 0x3D, 0, 0, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E}; +static const uint8_t uart_tx_uuid[] = {0x71, 0x3D, 0, 3, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E}; +static const uint8_t uart_rx_uuid[] = {0x71, 0x3D, 0, 2, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E}; +static const uint8_t uart_base_uuid_rev[] = {0x1E, 0x94, 0x8D, 0xF1, 0x48, 0x31, 0x94, 0xBA, 0x75, 0x4C, 0x3E, 0x50, 0, 0, 0x3D, 0x71}; + +uint8_t payloadTicker[TXRX_BUF_LEN] = {0,}; +uint8_t txPayload[TXRX_BUF_LEN] = {0,}; +uint8_t rxPayload[TXRX_BUF_LEN] = {0,}; + +GattCharacteristic txCharacteristic (uart_tx_uuid, txPayload, 1, TXRX_BUF_LEN, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE); +GattCharacteristic rxCharacteristic (uart_rx_uuid, rxPayload, 1, TXRX_BUF_LEN, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY); +GattCharacteristic *uartChars[] = {&txCharacteristic, &rxCharacteristic}; +GattService uartService(uart_base_uuid, uartChars, sizeof(uartChars) / sizeof(GattCharacteristic *)); + +static const int maxPins = 30; +uint8_t pinTypes[maxPins]; +uint16_t prevValues[maxPins]; + +DigitalInOut digitals[] = {P0_0,P0_7,P0_15,P0_19,P0_28,P0_29}; +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}; +AnalogIn analogs[] = {P0_1, P0_2, P0_3, P0_4, P0_5, P0_6}; +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}; + + +void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params) +{ + //pc.printf("Disconnected \r\n"); + //pc.printf("Restart advertising \r\n"); + ble.startAdvertising(); +} + +bool initPin(int pin, uint8_t type){ + bool ret=false; + if (pin>=0 && pin<31) { // "initPin(): Pin number out of bounds" + if ((type==PIN_INPUT||type==PIN_OUTPUT) && mapDigitals[pin]>=0) { + if (type==PIN_INPUT) digitals[mapDigitals[pin]].input(); // initialize as input + if (type==PIN_OUTPUT) digitals[mapDigitals[pin]].output(); // initialize as input + pinTypes[pin] = type; // mark the pin as initialized + ret =true; + } else if (type==PIN_ANALOG && mapAnalogs[pin]>=0) { + pinTypes[pin] = type; // mark the pin as initialized + ret =true; + } + } + return ret; +} + +uint16_t readPin(int pin) { + uint8_t mode = pinTypes[pin]; + if (mode==PIN_INPUT) { // exists and is initialized as digital output + mode = 0; + return (((uint16_t)mode)<<8 | (uint16_t)(digitals[mapDigitals[pin]].read())); + } else if (mode==PIN_OUTPUT) { // exists and is initialized as digital output + mode = 1; + return (((uint16_t)mode)<<8 | (uint16_t)(digitals[mapDigitals[pin]].read())); + } else if (mode==PIN_ANALOG) { // exists and is initialized as digital output + mode = 2; + uint16_t value = analogs[mapAnalogs[pin]].read_u16(); + uint8_t value_lo = value; + uint8_t value_hi = value>>8; + mode = (value_hi << 4) | mode; + return (((uint16_t)mode)<<8) | (uint16_t)value_lo; + } + return 0; +} + +void sendPinValue(int pin, uint16_t value) { + uint8_t buf[TXRX_BUF_LEN]; + buf[0]='G'; + buf[1]=pin; + buf[2]=(uint8_t)(value>>8); buf[3]=(uint8_t)value; + ble.updateCharacteristicValue(rxCharacteristic.getValueAttribute().getHandle(), buf, 4); + prevValues[pin] = value; +} + +void parseRedBearCmd(){ + uint8_t buf[TXRX_BUF_LEN]; + memset(buf, 0, TXRX_BUF_LEN); + + uint8_t startOffset = txPayload[0]==0?1:0; + uint8_t index = startOffset; + uint8_t cmd = txPayload[index++], pin=txPayload[index++], mode=PIN_NOTSET; + pin = pin>=48?pin-48:pin; + + switch (cmd) { + case 'Z':sendPinValue(pin,readPin(pin)); + break; + case 'X':initPin(7, PIN_OUTPUT); + break; + case 'Y':uint8_t value2write = txPayload[index++]-48; + if (mapDigitals[pin]>=0) { + digitals[mapDigitals[pin]].write(value2write==0?0:1); + sendPinValue(pin,readPin(pin)); + } + break; + + case 'M': //pc.printf("Querying pin %u mode\n",pin); + buf[0]=cmd; + buf[1]=pin; + buf[2]=pinTypes[pin]; + ble.updateCharacteristicValue(rxCharacteristic.getValueAttribute().getHandle(), buf, 3); + break; + + case 'S': // set pin mode + mode = txPayload[index++]; + mode = mode>=48?mode-48:mode; + if (initPin(pin, mode)) { // analogs are already initialized + sendPinValue(pin,readPin(pin)); + } + break; + + case 'G': //pc.printf("Reading pin %u\n",pin); + switch (pinTypes[pin]) { + case PIN_INPUT: + case PIN_ANALOG: + sendPinValue(pin,readPin(pin)); + break; + case PIN_OUTPUT: // TODO: send warning pin not readable (is an output) + default: // TODO: send warning pin not initialized + buf[0]=PIN_NOTSET; + buf[1]=PIN_NOTSET; + buf[2]=PIN_NOTSET; + ble.updateCharacteristicValue(rxCharacteristic.getValueAttribute().getHandle(), buf, 3); + break; + } + break; + + case 'T': + switch (pinTypes[pin]) { + case PIN_OUTPUT: + uint8_t value2write = txPayload[index++]; + if (mapDigitals[pin]>=0) { + digitals[mapDigitals[pin]].write(value2write==0?0:1); + sendPinValue(pin,readPin(pin)); + } + break; + case PIN_INPUT: // TODO: send warning pin not writable (is an input) + case PIN_ANALOG: // TODO: send warning pin not writable (is an input) + default: // TODO: send warning pin not initialized + buf[0]='T'; + buf[1]='T'; + buf[2]='T'; + ble.updateCharacteristicValue(rxCharacteristic.getValueAttribute().getHandle(), buf, 3); + break; + } + break; + + default: + // echo received buffer + ble.updateCharacteristicValue(rxCharacteristic.getValueAttribute().getHandle(), &txPayload[startOffset], strlen((char *)&txPayload[startOffset])); // FIXME + break; + } +} + + +void WrittenHandler(const GattWriteCallbackParams *Handler) +{ + uint8_t buf[TXRX_BUF_LEN]; + uint16_t bytesRead; + + if (Handler->handle == txCharacteristic.getValueAttribute().getHandle()) //only if empty + { + ble.readCharacteristicValue(txCharacteristic.getValueAttribute().getHandle(), buf, &bytesRead); + memset(txPayload, 0, TXRX_BUF_LEN); + memcpy(txPayload, buf, TXRX_BUF_LEN); + + ble.updateCharacteristicValue(rxCharacteristic.getValueAttribute().getHandle(), buf, bytesRead); + parseRedBearCmd(); + } +} + +void m_status_check_handle(void) +{ + for (int pin=0; pin<maxPins;pin++){ + if (pinTypes[pin]==PIN_INPUT||pinTypes[pin]==PIN_ANALOG) { + uint16_t value = readPin(pin); + //uint16_t prevValue = 33; + if (prevValues[pin] != value) { + sendPinValue(pin,value); + } + } + } +} + +int main(void) +{ + for (int i=0;i<maxPins;i++) { + pinTypes[i] = PIN_NOTSET; + prevValues[i] = 0; + } + + //memset(txPayload, 0, TXRX_BUF_LEN); + + ble.init(); + ble.onDisconnection(disconnectionCallback); + ble.onDataWritten(WrittenHandler); + + // setup advertising + ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED); + ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); + ble.accumulateAdvertisingPayload(GapAdvertisingData::SHORTENED_LOCAL_NAME, + (const uint8_t *)"MyNano", sizeof("MyNano") - 1); + ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS, + (const uint8_t *)uart_base_uuid_rev, sizeof(uart_base_uuid)); + // 100ms; in multiples of 0.625ms. + ble.setAdvertisingInterval(160); + + ble.addService(uartService); + + ble.startAdvertising(); + + Ticker ticker; + ticker.attach(m_status_check_handle, 0.2); + + while(1) + { + ble.waitForEvent(); + } +} + + + + + + + + + + + + + + + +