Redbear Nano firmware using Sandroide and showing how to send custom strings and parameters to the Android application
Dependencies: BLE_API MbedJSONValue mbed nRF51822
Fork of BLE_RedBearNano-SAndroidEDevice by
Diff: main.cpp
- Revision:
- 0:8d3dd6e411bf
- Child:
- 1:ff6ec7837f46
--- /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(); + } +} + + + + + + + + + + + + + + + +