Lightly modified version of the BLE stack, that doesn't bring up a DFUService by default... as we have our own.
Fork of BLE_API by
services/UARTService.h@118:620d28e7a1ba, 2014-09-22 (annotated)
- Committer:
- Rohit Grover
- Date:
- Mon Sep 22 10:59:09 2014 +0100
- Revision:
- 118:620d28e7a1ba
- Child:
- 134:49321f76753e
Release 0.2.0
=============
Highlights:
Introducing standard services to simplify applications.
Add support for over-the-air firmware updates.
Features
~~~~~~~~
- This release introduces 'templates' for common services such as heart-rate,
battery-level, device-info, UART, device-firmware-update etc. These services
take the shape of class declarations within header files aggregated under a
new folder called 'services/'. These service-classes provide a high-level
API hopefully easing the burden of developing BLE applications. The
underlying APIs to work with characteristics and services are still
available to allow greater control if needed. We expect to grow the
supported services to include all SIG defined BLE profiles.
- WriteCallbackParams now includes the characteristic's value-attribute
handle; this changes the signature of onDataWritten().
- BLEDevice::onDataWritten() now allows chaining of callbacks--this means that
it is possible to chain together multiple onDataWritten callbacks
(potentially from different modules of an application) to receive updates to
characteristics. Many services, such as DFU and UART add their own
onDataWritten callbacks behind the scenes to trap interesting events. It is
also possible to chain callbacks to functions within objects.
- Added the following expectation for GattCharacteristic: If valuePtr ==
NULL, initialLength == 0, and properties == READ for the value attribute of
a characteristic, then that particular characteristic may be considered
optional and dropped while instantiating the service with the underlying BLE
stack.
- Introducing the typedef GattAttribute::Handle_t to capture Attribute handles.
Bugfixes
~~~~~~~~
None.
Compatibility
~~~~~~~~~~~~~
The signature of onDataWritten() has seen a change; so application programs
using this new version of the BLE API will need minor modifications. Please
refer to sample programs under BLE team page.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
Rohit Grover |
118:620d28e7a1ba | 1 | /* mbed Microcontroller Library |
Rohit Grover |
118:620d28e7a1ba | 2 | * Copyright (c) 2006-2013 ARM Limited |
Rohit Grover |
118:620d28e7a1ba | 3 | * |
Rohit Grover |
118:620d28e7a1ba | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
Rohit Grover |
118:620d28e7a1ba | 5 | * you may not use this file except in compliance with the License. |
Rohit Grover |
118:620d28e7a1ba | 6 | * You may obtain a copy of the License at |
Rohit Grover |
118:620d28e7a1ba | 7 | * |
Rohit Grover |
118:620d28e7a1ba | 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
Rohit Grover |
118:620d28e7a1ba | 9 | * |
Rohit Grover |
118:620d28e7a1ba | 10 | * Unless required by applicable law or agreed to in writing, software |
Rohit Grover |
118:620d28e7a1ba | 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
Rohit Grover |
118:620d28e7a1ba | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
Rohit Grover |
118:620d28e7a1ba | 13 | * See the License for the specific language governing permissions and |
Rohit Grover |
118:620d28e7a1ba | 14 | * limitations under the License. |
Rohit Grover |
118:620d28e7a1ba | 15 | */ |
Rohit Grover |
118:620d28e7a1ba | 16 | |
Rohit Grover |
118:620d28e7a1ba | 17 | #ifndef __BLE_UART_SERVICE_H__ |
Rohit Grover |
118:620d28e7a1ba | 18 | #define __BLE_UART_SERVICE_H__ |
Rohit Grover |
118:620d28e7a1ba | 19 | |
Rohit Grover |
118:620d28e7a1ba | 20 | #include "Stream.h" |
Rohit Grover |
118:620d28e7a1ba | 21 | |
Rohit Grover |
118:620d28e7a1ba | 22 | #include "UUID.h" |
Rohit Grover |
118:620d28e7a1ba | 23 | #include "BLEDevice.h" |
Rohit Grover |
118:620d28e7a1ba | 24 | |
Rohit Grover |
118:620d28e7a1ba | 25 | extern const uint8_t UARTServiceBaseUUID[LENGTH_OF_LONG_UUID]; |
Rohit Grover |
118:620d28e7a1ba | 26 | extern const uint16_t UARTServiceShortUUID; |
Rohit Grover |
118:620d28e7a1ba | 27 | extern const uint16_t UARTServiceTXCharacteristicShortUUID; |
Rohit Grover |
118:620d28e7a1ba | 28 | extern const uint16_t UARTServiceRXCharacteristicShortUUID; |
Rohit Grover |
118:620d28e7a1ba | 29 | |
Rohit Grover |
118:620d28e7a1ba | 30 | extern const uint8_t UARTServiceUUID[LENGTH_OF_LONG_UUID]; |
Rohit Grover |
118:620d28e7a1ba | 31 | extern const uint8_t UARTServiceUUID_reversed[LENGTH_OF_LONG_UUID]; |
Rohit Grover |
118:620d28e7a1ba | 32 | |
Rohit Grover |
118:620d28e7a1ba | 33 | extern const uint8_t UARTServiceTXCharacteristicUUID[LENGTH_OF_LONG_UUID]; |
Rohit Grover |
118:620d28e7a1ba | 34 | extern const uint8_t UARTServiceRXCharacteristicUUID[LENGTH_OF_LONG_UUID]; |
Rohit Grover |
118:620d28e7a1ba | 35 | |
Rohit Grover |
118:620d28e7a1ba | 36 | class UARTService : public Stream { |
Rohit Grover |
118:620d28e7a1ba | 37 | public: |
Rohit Grover |
118:620d28e7a1ba | 38 | /**< Maximum length of data (in bytes) that can be transmitted by the UART service module to the peer. */ |
Rohit Grover |
118:620d28e7a1ba | 39 | static const unsigned GATT_MTU_SIZE_DEFAULT = 23; |
Rohit Grover |
118:620d28e7a1ba | 40 | static const unsigned BLE_UART_SERVICE_MAX_DATA_LEN = (GATT_MTU_SIZE_DEFAULT - 3); |
Rohit Grover |
118:620d28e7a1ba | 41 | |
Rohit Grover |
118:620d28e7a1ba | 42 | public: |
Rohit Grover |
118:620d28e7a1ba | 43 | UARTService(BLEDevice &_ble) : |
Rohit Grover |
118:620d28e7a1ba | 44 | Stream("blueart"), |
Rohit Grover |
118:620d28e7a1ba | 45 | ble(_ble), |
Rohit Grover |
118:620d28e7a1ba | 46 | receiveBuffer(), |
Rohit Grover |
118:620d28e7a1ba | 47 | sendBuffer(), |
Rohit Grover |
118:620d28e7a1ba | 48 | sendBufferIndex(0), |
Rohit Grover |
118:620d28e7a1ba | 49 | numBytesReceived(0), |
Rohit Grover |
118:620d28e7a1ba | 50 | receiveBufferIndex(0), |
Rohit Grover |
118:620d28e7a1ba | 51 | txCharacteristic(UARTServiceTXCharacteristicUUID, receiveBuffer, 1, BLE_UART_SERVICE_MAX_DATA_LEN, |
Rohit Grover |
118:620d28e7a1ba | 52 | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE), |
Rohit Grover |
118:620d28e7a1ba | 53 | rxCharacteristic(UARTServiceRXCharacteristicUUID, sendBuffer, 1, BLE_UART_SERVICE_MAX_DATA_LEN, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY) { |
Rohit Grover |
118:620d28e7a1ba | 54 | GattCharacteristic *charTable[] = {&txCharacteristic, &rxCharacteristic}; |
Rohit Grover |
118:620d28e7a1ba | 55 | GattService uartService(UARTServiceUUID, charTable, sizeof(charTable) / sizeof(GattCharacteristic *)); |
Rohit Grover |
118:620d28e7a1ba | 56 | |
Rohit Grover |
118:620d28e7a1ba | 57 | ble.addService(uartService); |
Rohit Grover |
118:620d28e7a1ba | 58 | ble.onDataWritten(this, &UARTService::onDataWritten); |
Rohit Grover |
118:620d28e7a1ba | 59 | } |
Rohit Grover |
118:620d28e7a1ba | 60 | |
Rohit Grover |
118:620d28e7a1ba | 61 | /** |
Rohit Grover |
118:620d28e7a1ba | 62 | * Note: TX and RX characteristics are to be interpreted from the viewpoint of the GATT client using this service. |
Rohit Grover |
118:620d28e7a1ba | 63 | */ |
Rohit Grover |
118:620d28e7a1ba | 64 | uint16_t getTXCharacteristicHandle() { |
Rohit Grover |
118:620d28e7a1ba | 65 | return txCharacteristic.getValueAttribute().getHandle(); |
Rohit Grover |
118:620d28e7a1ba | 66 | } |
Rohit Grover |
118:620d28e7a1ba | 67 | |
Rohit Grover |
118:620d28e7a1ba | 68 | /** |
Rohit Grover |
118:620d28e7a1ba | 69 | * Note: TX and RX characteristics are to be interpreted from the viewpoint of the GATT client using this service. |
Rohit Grover |
118:620d28e7a1ba | 70 | */ |
Rohit Grover |
118:620d28e7a1ba | 71 | uint16_t getRXCharacteristicHandle() { |
Rohit Grover |
118:620d28e7a1ba | 72 | return rxCharacteristic.getValueAttribute().getHandle(); |
Rohit Grover |
118:620d28e7a1ba | 73 | } |
Rohit Grover |
118:620d28e7a1ba | 74 | |
Rohit Grover |
118:620d28e7a1ba | 75 | /** |
Rohit Grover |
118:620d28e7a1ba | 76 | * Following a call to this function, all writes to stdout (such as from |
Rohit Grover |
118:620d28e7a1ba | 77 | * printf) get redirected to the outbound characteristic of this service. |
Rohit Grover |
118:620d28e7a1ba | 78 | * This might be very useful when wanting to receive debug messages over BLE. |
Rohit Grover |
118:620d28e7a1ba | 79 | * |
Rohit Grover |
118:620d28e7a1ba | 80 | * @Note: debug messages originating from printf() like calls are buffered |
Rohit Grover |
118:620d28e7a1ba | 81 | * before being sent out. A '\n' in the printf() triggers the buffer update |
Rohit Grover |
118:620d28e7a1ba | 82 | * to the underlying characteristic. |
Rohit Grover |
118:620d28e7a1ba | 83 | * |
Rohit Grover |
118:620d28e7a1ba | 84 | * @Note: long messages need to be chopped up into 20-byte updates so that |
Rohit Grover |
118:620d28e7a1ba | 85 | * they flow out completely with notifications. The receiver should be |
Rohit Grover |
118:620d28e7a1ba | 86 | * prepared to stitch these messages back. |
Rohit Grover |
118:620d28e7a1ba | 87 | */ |
Rohit Grover |
118:620d28e7a1ba | 88 | void retargetStdout() { |
Rohit Grover |
118:620d28e7a1ba | 89 | freopen("/blueart", "w", stdout); |
Rohit Grover |
118:620d28e7a1ba | 90 | } |
Rohit Grover |
118:620d28e7a1ba | 91 | |
Rohit Grover |
118:620d28e7a1ba | 92 | /** |
Rohit Grover |
118:620d28e7a1ba | 93 | * This callback allows the UART service to receive updates to the |
Rohit Grover |
118:620d28e7a1ba | 94 | * txCharacteristic. The application should forward the call to this |
Rohit Grover |
118:620d28e7a1ba | 95 | * function from the global onDataWritten() callback handler; or if that's |
Rohit Grover |
118:620d28e7a1ba | 96 | * not used, this method can be used as a callback directly. |
Rohit Grover |
118:620d28e7a1ba | 97 | */ |
Rohit Grover |
118:620d28e7a1ba | 98 | virtual void onDataWritten(const GattCharacteristicWriteCBParams *params) { |
Rohit Grover |
118:620d28e7a1ba | 99 | if (params->charHandle == getTXCharacteristicHandle()) { |
Rohit Grover |
118:620d28e7a1ba | 100 | uint16_t bytesRead = params->len; |
Rohit Grover |
118:620d28e7a1ba | 101 | if (bytesRead <= BLE_UART_SERVICE_MAX_DATA_LEN) { |
Rohit Grover |
118:620d28e7a1ba | 102 | numBytesReceived = bytesRead; |
Rohit Grover |
118:620d28e7a1ba | 103 | receiveBufferIndex = 0; |
Rohit Grover |
118:620d28e7a1ba | 104 | memcpy(receiveBuffer, params->data, numBytesReceived); |
Rohit Grover |
118:620d28e7a1ba | 105 | } |
Rohit Grover |
118:620d28e7a1ba | 106 | } |
Rohit Grover |
118:620d28e7a1ba | 107 | } |
Rohit Grover |
118:620d28e7a1ba | 108 | |
Rohit Grover |
118:620d28e7a1ba | 109 | protected: |
Rohit Grover |
118:620d28e7a1ba | 110 | /** |
Rohit Grover |
118:620d28e7a1ba | 111 | * Override for Stream::write(). |
Rohit Grover |
118:620d28e7a1ba | 112 | * |
Rohit Grover |
118:620d28e7a1ba | 113 | * We attempt to collect bytes before pushing them to the UART RX |
Rohit Grover |
118:620d28e7a1ba | 114 | * characteristic--writing to the RX characteristic will then generate |
Rohit Grover |
118:620d28e7a1ba | 115 | * notifications for the client. Updates made in quick succession to a |
Rohit Grover |
118:620d28e7a1ba | 116 | * notification-generating characteristic will result in data being buffered |
Rohit Grover |
118:620d28e7a1ba | 117 | * in the bluetooth stack as notifications are sent out. The stack will have |
Rohit Grover |
118:620d28e7a1ba | 118 | * its limits for this buffering; typically a small number under 10. |
Rohit Grover |
118:620d28e7a1ba | 119 | * Collecting data into the sendBuffer buffer helps mitigate the rate of |
Rohit Grover |
118:620d28e7a1ba | 120 | * updates. But we shouldn't buffer a large amount of data before updating |
Rohit Grover |
118:620d28e7a1ba | 121 | * the characteristic otherwise the client will need to turn around and make |
Rohit Grover |
118:620d28e7a1ba | 122 | * a long read request; this is because notifications include only the first |
Rohit Grover |
118:620d28e7a1ba | 123 | * 20 bytes of the updated data. |
Rohit Grover |
118:620d28e7a1ba | 124 | * |
Rohit Grover |
118:620d28e7a1ba | 125 | * @param buffer The received update |
Rohit Grover |
118:620d28e7a1ba | 126 | * @param length Amount of characters to be appended. |
Rohit Grover |
118:620d28e7a1ba | 127 | * @return Amount of characters appended to the rxCharacteristic. |
Rohit Grover |
118:620d28e7a1ba | 128 | */ |
Rohit Grover |
118:620d28e7a1ba | 129 | virtual ssize_t write(const void* _buffer, size_t length) { |
Rohit Grover |
118:620d28e7a1ba | 130 | size_t origLength = length; |
Rohit Grover |
118:620d28e7a1ba | 131 | const uint8_t *buffer = static_cast<const uint8_t *>(_buffer); |
Rohit Grover |
118:620d28e7a1ba | 132 | |
Rohit Grover |
118:620d28e7a1ba | 133 | if (ble.getGapState().connected) { |
Rohit Grover |
118:620d28e7a1ba | 134 | unsigned bufferIndex = 0; |
Rohit Grover |
118:620d28e7a1ba | 135 | while (length) { |
Rohit Grover |
118:620d28e7a1ba | 136 | unsigned bytesRemainingInSendBuffer = BLE_UART_SERVICE_MAX_DATA_LEN - sendBufferIndex; |
Rohit Grover |
118:620d28e7a1ba | 137 | unsigned bytesToCopy = (length < bytesRemainingInSendBuffer) ? length : bytesRemainingInSendBuffer; |
Rohit Grover |
118:620d28e7a1ba | 138 | |
Rohit Grover |
118:620d28e7a1ba | 139 | /* copy bytes into sendBuffer */ |
Rohit Grover |
118:620d28e7a1ba | 140 | memcpy(&sendBuffer[sendBufferIndex], &buffer[bufferIndex], bytesToCopy); |
Rohit Grover |
118:620d28e7a1ba | 141 | length -= bytesToCopy; |
Rohit Grover |
118:620d28e7a1ba | 142 | sendBufferIndex += bytesToCopy; |
Rohit Grover |
118:620d28e7a1ba | 143 | bufferIndex += bytesToCopy; |
Rohit Grover |
118:620d28e7a1ba | 144 | |
Rohit Grover |
118:620d28e7a1ba | 145 | /* have we collected enough? */ |
Rohit Grover |
118:620d28e7a1ba | 146 | if ((sendBufferIndex == BLE_UART_SERVICE_MAX_DATA_LEN) || |
Rohit Grover |
118:620d28e7a1ba | 147 | // (sendBuffer[sendBufferIndex - 1] == '\r') || |
Rohit Grover |
118:620d28e7a1ba | 148 | (sendBuffer[sendBufferIndex - 1] == '\n')) { |
Rohit Grover |
118:620d28e7a1ba | 149 | ble.updateCharacteristicValue(getRXCharacteristicHandle(), static_cast<const uint8_t *>(sendBuffer), sendBufferIndex); |
Rohit Grover |
118:620d28e7a1ba | 150 | sendBufferIndex = 0; |
Rohit Grover |
118:620d28e7a1ba | 151 | } |
Rohit Grover |
118:620d28e7a1ba | 152 | } |
Rohit Grover |
118:620d28e7a1ba | 153 | } |
Rohit Grover |
118:620d28e7a1ba | 154 | |
Rohit Grover |
118:620d28e7a1ba | 155 | return origLength; |
Rohit Grover |
118:620d28e7a1ba | 156 | } |
Rohit Grover |
118:620d28e7a1ba | 157 | |
Rohit Grover |
118:620d28e7a1ba | 158 | /** |
Rohit Grover |
118:620d28e7a1ba | 159 | * Override for Stream::_putc() |
Rohit Grover |
118:620d28e7a1ba | 160 | * @param c |
Rohit Grover |
118:620d28e7a1ba | 161 | * This function writes the character c, cast to an unsigned char, to stream. |
Rohit Grover |
118:620d28e7a1ba | 162 | * @return |
Rohit Grover |
118:620d28e7a1ba | 163 | * The character written as an unsigned char cast to an int or EOF on error. |
Rohit Grover |
118:620d28e7a1ba | 164 | */ |
Rohit Grover |
118:620d28e7a1ba | 165 | virtual int _putc(int c) { |
Rohit Grover |
118:620d28e7a1ba | 166 | return (write(&c, 1) == 1) ? 1 : EOF; |
Rohit Grover |
118:620d28e7a1ba | 167 | } |
Rohit Grover |
118:620d28e7a1ba | 168 | |
Rohit Grover |
118:620d28e7a1ba | 169 | virtual int _getc() { |
Rohit Grover |
118:620d28e7a1ba | 170 | if (receiveBufferIndex == numBytesReceived) { |
Rohit Grover |
118:620d28e7a1ba | 171 | return EOF; |
Rohit Grover |
118:620d28e7a1ba | 172 | } |
Rohit Grover |
118:620d28e7a1ba | 173 | |
Rohit Grover |
118:620d28e7a1ba | 174 | return receiveBuffer[receiveBufferIndex++]; |
Rohit Grover |
118:620d28e7a1ba | 175 | } |
Rohit Grover |
118:620d28e7a1ba | 176 | |
Rohit Grover |
118:620d28e7a1ba | 177 | virtual int isatty() { |
Rohit Grover |
118:620d28e7a1ba | 178 | return 1; |
Rohit Grover |
118:620d28e7a1ba | 179 | } |
Rohit Grover |
118:620d28e7a1ba | 180 | |
Rohit Grover |
118:620d28e7a1ba | 181 | private: |
Rohit Grover |
118:620d28e7a1ba | 182 | BLEDevice &ble; |
Rohit Grover |
118:620d28e7a1ba | 183 | |
Rohit Grover |
118:620d28e7a1ba | 184 | uint8_t receiveBuffer[BLE_UART_SERVICE_MAX_DATA_LEN]; /**< The local buffer into which we receive |
Rohit Grover |
118:620d28e7a1ba | 185 | * inbound data before forwarding it to the |
Rohit Grover |
118:620d28e7a1ba | 186 | * application. */ |
Rohit Grover |
118:620d28e7a1ba | 187 | |
Rohit Grover |
118:620d28e7a1ba | 188 | uint8_t sendBuffer[BLE_UART_SERVICE_MAX_DATA_LEN]; /**< The local buffer into which outbound data is |
Rohit Grover |
118:620d28e7a1ba | 189 | * accumulated before being pushed to the |
Rohit Grover |
118:620d28e7a1ba | 190 | * rxCharacteristic. */ |
Rohit Grover |
118:620d28e7a1ba | 191 | uint8_t sendBufferIndex; |
Rohit Grover |
118:620d28e7a1ba | 192 | uint8_t numBytesReceived; |
Rohit Grover |
118:620d28e7a1ba | 193 | uint8_t receiveBufferIndex; |
Rohit Grover |
118:620d28e7a1ba | 194 | |
Rohit Grover |
118:620d28e7a1ba | 195 | GattCharacteristic txCharacteristic; /**< From the point of view of the external client, this is the characteristic |
Rohit Grover |
118:620d28e7a1ba | 196 | * they'd write into in order to communicate with this application. */ |
Rohit Grover |
118:620d28e7a1ba | 197 | GattCharacteristic rxCharacteristic; /**< From the point of view of the external client, this is the characteristic |
Rohit Grover |
118:620d28e7a1ba | 198 | * they'd read from in order to receive the bytes transmitted by this |
Rohit Grover |
118:620d28e7a1ba | 199 | * application. */ |
Rohit Grover |
118:620d28e7a1ba | 200 | }; |
Rohit Grover |
118:620d28e7a1ba | 201 | |
Rohit Grover |
118:620d28e7a1ba | 202 | #endif /* #ifndef __BLE_UART_SERVICE_H__*/ |
Rohit Grover |
118:620d28e7a1ba | 203 |