Pinned to some recent date

Committer:
Simon Cooksey
Date:
Thu Nov 17 16:43:53 2016 +0000
Revision:
0:fb7af294d5d9
Initial commit

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Simon Cooksey 0:fb7af294d5d9 1 /* mbed Microcontroller Library
Simon Cooksey 0:fb7af294d5d9 2 * Copyright (c) 2006-2013 ARM Limited
Simon Cooksey 0:fb7af294d5d9 3 *
Simon Cooksey 0:fb7af294d5d9 4 * Licensed under the Apache License, Version 2.0 (the "License");
Simon Cooksey 0:fb7af294d5d9 5 * you may not use this file except in compliance with the License.
Simon Cooksey 0:fb7af294d5d9 6 * You may obtain a copy of the License at
Simon Cooksey 0:fb7af294d5d9 7 *
Simon Cooksey 0:fb7af294d5d9 8 * http://www.apache.org/licenses/LICENSE-2.0
Simon Cooksey 0:fb7af294d5d9 9 *
Simon Cooksey 0:fb7af294d5d9 10 * Unless required by applicable law or agreed to in writing, software
Simon Cooksey 0:fb7af294d5d9 11 * distributed under the License is distributed on an "AS IS" BASIS,
Simon Cooksey 0:fb7af294d5d9 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Simon Cooksey 0:fb7af294d5d9 13 * See the License for the specific language governing permissions and
Simon Cooksey 0:fb7af294d5d9 14 * limitations under the License.
Simon Cooksey 0:fb7af294d5d9 15 */
Simon Cooksey 0:fb7af294d5d9 16
Simon Cooksey 0:fb7af294d5d9 17 #ifndef __BLE_UART_SERVICE_H__
Simon Cooksey 0:fb7af294d5d9 18 #define __BLE_UART_SERVICE_H__
Simon Cooksey 0:fb7af294d5d9 19
Simon Cooksey 0:fb7af294d5d9 20 #ifdef YOTTA_CFG_MBED_OS
Simon Cooksey 0:fb7af294d5d9 21 #include "mbed-drivers/mbed.h"
Simon Cooksey 0:fb7af294d5d9 22 #include "mbed-drivers/Stream.h"
Simon Cooksey 0:fb7af294d5d9 23 #else
Simon Cooksey 0:fb7af294d5d9 24 #include "mbed.h"
Simon Cooksey 0:fb7af294d5d9 25 #include "Stream.h"
Simon Cooksey 0:fb7af294d5d9 26 #endif
Simon Cooksey 0:fb7af294d5d9 27
Simon Cooksey 0:fb7af294d5d9 28 #include "ble/UUID.h"
Simon Cooksey 0:fb7af294d5d9 29 #include "ble/BLE.h"
Simon Cooksey 0:fb7af294d5d9 30
Simon Cooksey 0:fb7af294d5d9 31 extern const uint8_t UARTServiceBaseUUID[UUID::LENGTH_OF_LONG_UUID];
Simon Cooksey 0:fb7af294d5d9 32 extern const uint16_t UARTServiceShortUUID;
Simon Cooksey 0:fb7af294d5d9 33 extern const uint16_t UARTServiceTXCharacteristicShortUUID;
Simon Cooksey 0:fb7af294d5d9 34 extern const uint16_t UARTServiceRXCharacteristicShortUUID;
Simon Cooksey 0:fb7af294d5d9 35
Simon Cooksey 0:fb7af294d5d9 36 extern const uint8_t UARTServiceUUID[UUID::LENGTH_OF_LONG_UUID];
Simon Cooksey 0:fb7af294d5d9 37 extern const uint8_t UARTServiceUUID_reversed[UUID::LENGTH_OF_LONG_UUID];
Simon Cooksey 0:fb7af294d5d9 38
Simon Cooksey 0:fb7af294d5d9 39 extern const uint8_t UARTServiceTXCharacteristicUUID[UUID::LENGTH_OF_LONG_UUID];
Simon Cooksey 0:fb7af294d5d9 40 extern const uint8_t UARTServiceRXCharacteristicUUID[UUID::LENGTH_OF_LONG_UUID];
Simon Cooksey 0:fb7af294d5d9 41
Simon Cooksey 0:fb7af294d5d9 42 /**
Simon Cooksey 0:fb7af294d5d9 43 * @class UARTService.
Simon Cooksey 0:fb7af294d5d9 44 * @brief BLE Service to enable UART over BLE.
Simon Cooksey 0:fb7af294d5d9 45 */
Simon Cooksey 0:fb7af294d5d9 46 class UARTService {
Simon Cooksey 0:fb7af294d5d9 47 public:
Simon Cooksey 0:fb7af294d5d9 48 /**< Maximum length of data (in bytes) that the UART service module can transmit to the peer. */
Simon Cooksey 0:fb7af294d5d9 49 static const unsigned BLE_UART_SERVICE_MAX_DATA_LEN = (BLE_GATT_MTU_SIZE_DEFAULT - 3);
Simon Cooksey 0:fb7af294d5d9 50
Simon Cooksey 0:fb7af294d5d9 51 public:
Simon Cooksey 0:fb7af294d5d9 52
Simon Cooksey 0:fb7af294d5d9 53 /**
Simon Cooksey 0:fb7af294d5d9 54 * @param[ref] ble
Simon Cooksey 0:fb7af294d5d9 55 * BLE object for the underlying controller.
Simon Cooksey 0:fb7af294d5d9 56 */
Simon Cooksey 0:fb7af294d5d9 57 UARTService(BLE &_ble) :
Simon Cooksey 0:fb7af294d5d9 58 ble(_ble),
Simon Cooksey 0:fb7af294d5d9 59 receiveBuffer(),
Simon Cooksey 0:fb7af294d5d9 60 sendBuffer(),
Simon Cooksey 0:fb7af294d5d9 61 sendBufferIndex(0),
Simon Cooksey 0:fb7af294d5d9 62 numBytesReceived(0),
Simon Cooksey 0:fb7af294d5d9 63 receiveBufferIndex(0),
Simon Cooksey 0:fb7af294d5d9 64 txCharacteristic(UARTServiceTXCharacteristicUUID, receiveBuffer, 1, BLE_UART_SERVICE_MAX_DATA_LEN,
Simon Cooksey 0:fb7af294d5d9 65 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE),
Simon Cooksey 0:fb7af294d5d9 66 rxCharacteristic(UARTServiceRXCharacteristicUUID, sendBuffer, 1, BLE_UART_SERVICE_MAX_DATA_LEN, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY) {
Simon Cooksey 0:fb7af294d5d9 67 GattCharacteristic *charTable[] = {&txCharacteristic, &rxCharacteristic};
Simon Cooksey 0:fb7af294d5d9 68 GattService uartService(UARTServiceUUID, charTable, sizeof(charTable) / sizeof(GattCharacteristic *));
Simon Cooksey 0:fb7af294d5d9 69
Simon Cooksey 0:fb7af294d5d9 70 ble.addService(uartService);
Simon Cooksey 0:fb7af294d5d9 71 ble.onDataWritten(this, &UARTService::onDataWritten);
Simon Cooksey 0:fb7af294d5d9 72 }
Simon Cooksey 0:fb7af294d5d9 73
Simon Cooksey 0:fb7af294d5d9 74 /**
Simon Cooksey 0:fb7af294d5d9 75 * Note: TX and RX characteristics are to be interpreted from the viewpoint of the GATT client using this service.
Simon Cooksey 0:fb7af294d5d9 76 */
Simon Cooksey 0:fb7af294d5d9 77 uint16_t getTXCharacteristicHandle() {
Simon Cooksey 0:fb7af294d5d9 78 return txCharacteristic.getValueAttribute().getHandle();
Simon Cooksey 0:fb7af294d5d9 79 }
Simon Cooksey 0:fb7af294d5d9 80
Simon Cooksey 0:fb7af294d5d9 81 /**
Simon Cooksey 0:fb7af294d5d9 82 * Note: TX and RX characteristics are to be interpreted from the viewpoint of the GATT client using this service.
Simon Cooksey 0:fb7af294d5d9 83 */
Simon Cooksey 0:fb7af294d5d9 84 uint16_t getRXCharacteristicHandle() {
Simon Cooksey 0:fb7af294d5d9 85 return rxCharacteristic.getValueAttribute().getHandle();
Simon Cooksey 0:fb7af294d5d9 86 }
Simon Cooksey 0:fb7af294d5d9 87
Simon Cooksey 0:fb7af294d5d9 88 /**
Simon Cooksey 0:fb7af294d5d9 89 * We attempt to collect bytes before pushing them to the UART RX
Simon Cooksey 0:fb7af294d5d9 90 * characteristic; writing to the RX characteristic then generates
Simon Cooksey 0:fb7af294d5d9 91 * notifications for the client. Updates made in quick succession to a
Simon Cooksey 0:fb7af294d5d9 92 * notification-generating characteristic result in data being buffered
Simon Cooksey 0:fb7af294d5d9 93 * in the Bluetooth stack as notifications are sent out. The stack has
Simon Cooksey 0:fb7af294d5d9 94 * its limits for this buffering - typically a small number under 10.
Simon Cooksey 0:fb7af294d5d9 95 * Collecting data into the sendBuffer buffer helps mitigate the rate of
Simon Cooksey 0:fb7af294d5d9 96 * updates. But we shouldn't buffer a large amount of data before updating
Simon Cooksey 0:fb7af294d5d9 97 * the characteristic, otherwise the client needs to turn around and make
Simon Cooksey 0:fb7af294d5d9 98 * a long read request; this is because notifications include only the first
Simon Cooksey 0:fb7af294d5d9 99 * 20 bytes of the updated data.
Simon Cooksey 0:fb7af294d5d9 100 *
Simon Cooksey 0:fb7af294d5d9 101 * @param buffer The received update.
Simon Cooksey 0:fb7af294d5d9 102 * @param length Number of characters to be appended.
Simon Cooksey 0:fb7af294d5d9 103 * @return Number of characters appended to the rxCharacteristic.
Simon Cooksey 0:fb7af294d5d9 104 */
Simon Cooksey 0:fb7af294d5d9 105 size_t write(const void *_buffer, size_t length) {
Simon Cooksey 0:fb7af294d5d9 106 size_t origLength = length;
Simon Cooksey 0:fb7af294d5d9 107 const uint8_t *buffer = static_cast<const uint8_t *>(_buffer);
Simon Cooksey 0:fb7af294d5d9 108
Simon Cooksey 0:fb7af294d5d9 109 if (ble.getGapState().connected) {
Simon Cooksey 0:fb7af294d5d9 110 unsigned bufferIndex = 0;
Simon Cooksey 0:fb7af294d5d9 111 while (length) {
Simon Cooksey 0:fb7af294d5d9 112 unsigned bytesRemainingInSendBuffer = BLE_UART_SERVICE_MAX_DATA_LEN - sendBufferIndex;
Simon Cooksey 0:fb7af294d5d9 113 unsigned bytesToCopy = (length < bytesRemainingInSendBuffer) ? length : bytesRemainingInSendBuffer;
Simon Cooksey 0:fb7af294d5d9 114
Simon Cooksey 0:fb7af294d5d9 115 /* Copy bytes into sendBuffer. */
Simon Cooksey 0:fb7af294d5d9 116 memcpy(&sendBuffer[sendBufferIndex], &buffer[bufferIndex], bytesToCopy);
Simon Cooksey 0:fb7af294d5d9 117 length -= bytesToCopy;
Simon Cooksey 0:fb7af294d5d9 118 sendBufferIndex += bytesToCopy;
Simon Cooksey 0:fb7af294d5d9 119 bufferIndex += bytesToCopy;
Simon Cooksey 0:fb7af294d5d9 120
Simon Cooksey 0:fb7af294d5d9 121 /* Have we collected enough? */
Simon Cooksey 0:fb7af294d5d9 122 if ((sendBufferIndex == BLE_UART_SERVICE_MAX_DATA_LEN) ||
Simon Cooksey 0:fb7af294d5d9 123 // (sendBuffer[sendBufferIndex - 1] == '\r') ||
Simon Cooksey 0:fb7af294d5d9 124 (sendBuffer[sendBufferIndex - 1] == '\n')) {
Simon Cooksey 0:fb7af294d5d9 125 ble.gattServer().write(getRXCharacteristicHandle(), static_cast<const uint8_t *>(sendBuffer), sendBufferIndex);
Simon Cooksey 0:fb7af294d5d9 126 sendBufferIndex = 0;
Simon Cooksey 0:fb7af294d5d9 127 }
Simon Cooksey 0:fb7af294d5d9 128 }
Simon Cooksey 0:fb7af294d5d9 129 }
Simon Cooksey 0:fb7af294d5d9 130
Simon Cooksey 0:fb7af294d5d9 131 return origLength;
Simon Cooksey 0:fb7af294d5d9 132 }
Simon Cooksey 0:fb7af294d5d9 133
Simon Cooksey 0:fb7af294d5d9 134 /**
Simon Cooksey 0:fb7af294d5d9 135 * Helper function to write out strings.
Simon Cooksey 0:fb7af294d5d9 136 * @param str The received string.
Simon Cooksey 0:fb7af294d5d9 137 * @return Number of characters appended to the rxCharacteristic.
Simon Cooksey 0:fb7af294d5d9 138 */
Simon Cooksey 0:fb7af294d5d9 139 size_t writeString(const char *str) {
Simon Cooksey 0:fb7af294d5d9 140 return write(str, strlen(str));
Simon Cooksey 0:fb7af294d5d9 141 }
Simon Cooksey 0:fb7af294d5d9 142
Simon Cooksey 0:fb7af294d5d9 143 /**
Simon Cooksey 0:fb7af294d5d9 144 * Override for Stream::_putc().
Simon Cooksey 0:fb7af294d5d9 145 * @param c
Simon Cooksey 0:fb7af294d5d9 146 * This function writes the character c, cast to an unsigned char, to stream.
Simon Cooksey 0:fb7af294d5d9 147 * @return
Simon Cooksey 0:fb7af294d5d9 148 * The character written as an unsigned char cast to an int or EOF on error.
Simon Cooksey 0:fb7af294d5d9 149 */
Simon Cooksey 0:fb7af294d5d9 150 int _putc(int c) {
Simon Cooksey 0:fb7af294d5d9 151 return (write(&c, 1) == 1) ? 1 : EOF;
Simon Cooksey 0:fb7af294d5d9 152 }
Simon Cooksey 0:fb7af294d5d9 153
Simon Cooksey 0:fb7af294d5d9 154 /**
Simon Cooksey 0:fb7af294d5d9 155 * Override for Stream::_getc().
Simon Cooksey 0:fb7af294d5d9 156 * @return
Simon Cooksey 0:fb7af294d5d9 157 * The character read.
Simon Cooksey 0:fb7af294d5d9 158 */
Simon Cooksey 0:fb7af294d5d9 159 int _getc() {
Simon Cooksey 0:fb7af294d5d9 160 if (receiveBufferIndex == numBytesReceived) {
Simon Cooksey 0:fb7af294d5d9 161 return EOF;
Simon Cooksey 0:fb7af294d5d9 162 }
Simon Cooksey 0:fb7af294d5d9 163
Simon Cooksey 0:fb7af294d5d9 164 return receiveBuffer[receiveBufferIndex++];
Simon Cooksey 0:fb7af294d5d9 165 }
Simon Cooksey 0:fb7af294d5d9 166
Simon Cooksey 0:fb7af294d5d9 167 protected:
Simon Cooksey 0:fb7af294d5d9 168 /**
Simon Cooksey 0:fb7af294d5d9 169 * This callback allows the UART service to receive updates to the
Simon Cooksey 0:fb7af294d5d9 170 * txCharacteristic. The application should forward the call to this
Simon Cooksey 0:fb7af294d5d9 171 * function from the global onDataWritten() callback handler; if that's
Simon Cooksey 0:fb7af294d5d9 172 * not used, this method can be used as a callback directly.
Simon Cooksey 0:fb7af294d5d9 173 */
Simon Cooksey 0:fb7af294d5d9 174 void onDataWritten(const GattWriteCallbackParams *params) {
Simon Cooksey 0:fb7af294d5d9 175 if (params->handle == getTXCharacteristicHandle()) {
Simon Cooksey 0:fb7af294d5d9 176 uint16_t bytesRead = params->len;
Simon Cooksey 0:fb7af294d5d9 177 if (bytesRead <= BLE_UART_SERVICE_MAX_DATA_LEN) {
Simon Cooksey 0:fb7af294d5d9 178 numBytesReceived = bytesRead;
Simon Cooksey 0:fb7af294d5d9 179 receiveBufferIndex = 0;
Simon Cooksey 0:fb7af294d5d9 180 memcpy(receiveBuffer, params->data, numBytesReceived);
Simon Cooksey 0:fb7af294d5d9 181 }
Simon Cooksey 0:fb7af294d5d9 182 }
Simon Cooksey 0:fb7af294d5d9 183 }
Simon Cooksey 0:fb7af294d5d9 184
Simon Cooksey 0:fb7af294d5d9 185 protected:
Simon Cooksey 0:fb7af294d5d9 186 BLE &ble;
Simon Cooksey 0:fb7af294d5d9 187
Simon Cooksey 0:fb7af294d5d9 188 uint8_t receiveBuffer[BLE_UART_SERVICE_MAX_DATA_LEN]; /**< The local buffer into which we receive
Simon Cooksey 0:fb7af294d5d9 189 * inbound data before forwarding it to the
Simon Cooksey 0:fb7af294d5d9 190 * application. */
Simon Cooksey 0:fb7af294d5d9 191
Simon Cooksey 0:fb7af294d5d9 192 uint8_t sendBuffer[BLE_UART_SERVICE_MAX_DATA_LEN]; /**< The local buffer into which outbound data is
Simon Cooksey 0:fb7af294d5d9 193 * accumulated before being pushed to the
Simon Cooksey 0:fb7af294d5d9 194 * rxCharacteristic. */
Simon Cooksey 0:fb7af294d5d9 195 uint8_t sendBufferIndex;
Simon Cooksey 0:fb7af294d5d9 196 uint8_t numBytesReceived;
Simon Cooksey 0:fb7af294d5d9 197 uint8_t receiveBufferIndex;
Simon Cooksey 0:fb7af294d5d9 198
Simon Cooksey 0:fb7af294d5d9 199 GattCharacteristic txCharacteristic; /**< From the point of view of the external client, this is the characteristic
Simon Cooksey 0:fb7af294d5d9 200 * they'd write into in order to communicate with this application. */
Simon Cooksey 0:fb7af294d5d9 201 GattCharacteristic rxCharacteristic; /**< From the point of view of the external client, this is the characteristic
Simon Cooksey 0:fb7af294d5d9 202 * they'd read from in order to receive the bytes transmitted by this
Simon Cooksey 0:fb7af294d5d9 203 * application. */
Simon Cooksey 0:fb7af294d5d9 204 };
Simon Cooksey 0:fb7af294d5d9 205
Simon Cooksey 0:fb7af294d5d9 206 #endif /* #ifndef __BLE_UART_SERVICE_H__*/