fork

Dependencies:   BLE_API mbed-dev-bin nRF51822

Dependents:   microbit

Fork of microbit-dal by Lancaster University

Committer:
Jonathan Austin
Date:
Thu Apr 07 01:33:22 2016 +0100
Revision:
1:8aa5cdb4ab67
Child:
3:d86a4ddc1867
Synchronized with git rev 55cb9199

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Jonathan Austin 1:8aa5cdb4ab67 1 /*
Jonathan Austin 1:8aa5cdb4ab67 2 The MIT License (MIT)
Jonathan Austin 1:8aa5cdb4ab67 3
Jonathan Austin 1:8aa5cdb4ab67 4 Copyright (c) 2016 British Broadcasting Corporation.
Jonathan Austin 1:8aa5cdb4ab67 5 This software is provided by Lancaster University by arrangement with the BBC.
Jonathan Austin 1:8aa5cdb4ab67 6
Jonathan Austin 1:8aa5cdb4ab67 7 Permission is hereby granted, free of charge, to any person obtaining a
Jonathan Austin 1:8aa5cdb4ab67 8 copy of this software and associated documentation files (the "Software"),
Jonathan Austin 1:8aa5cdb4ab67 9 to deal in the Software without restriction, including without limitation
Jonathan Austin 1:8aa5cdb4ab67 10 the rights to use, copy, modify, merge, publish, distribute, sublicense,
Jonathan Austin 1:8aa5cdb4ab67 11 and/or sell copies of the Software, and to permit persons to whom the
Jonathan Austin 1:8aa5cdb4ab67 12 Software is furnished to do so, subject to the following conditions:
Jonathan Austin 1:8aa5cdb4ab67 13
Jonathan Austin 1:8aa5cdb4ab67 14 The above copyright notice and this permission notice shall be included in
Jonathan Austin 1:8aa5cdb4ab67 15 all copies or substantial portions of the Software.
Jonathan Austin 1:8aa5cdb4ab67 16
Jonathan Austin 1:8aa5cdb4ab67 17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Jonathan Austin 1:8aa5cdb4ab67 18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Jonathan Austin 1:8aa5cdb4ab67 19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
Jonathan Austin 1:8aa5cdb4ab67 20 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
Jonathan Austin 1:8aa5cdb4ab67 21 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
Jonathan Austin 1:8aa5cdb4ab67 22 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
Jonathan Austin 1:8aa5cdb4ab67 23 DEALINGS IN THE SOFTWARE.
Jonathan Austin 1:8aa5cdb4ab67 24 */
Jonathan Austin 1:8aa5cdb4ab67 25
Jonathan Austin 1:8aa5cdb4ab67 26 /**
Jonathan Austin 1:8aa5cdb4ab67 27 * Class definition for the custom MicroBit UART Service.
Jonathan Austin 1:8aa5cdb4ab67 28 * Provides a BLE service that acts as a UART port, enabling the reception and transmission
Jonathan Austin 1:8aa5cdb4ab67 29 * of an arbitrary number of bytes.
Jonathan Austin 1:8aa5cdb4ab67 30 */
Jonathan Austin 1:8aa5cdb4ab67 31
Jonathan Austin 1:8aa5cdb4ab67 32 #include "ble/UUID.h"
Jonathan Austin 1:8aa5cdb4ab67 33
Jonathan Austin 1:8aa5cdb4ab67 34 #include "ExternalEvents.h"
Jonathan Austin 1:8aa5cdb4ab67 35 #include "MicroBitUARTService.h"
Jonathan Austin 1:8aa5cdb4ab67 36 #include "MicroBitFiber.h"
Jonathan Austin 1:8aa5cdb4ab67 37 #include "ErrorNo.h"
Jonathan Austin 1:8aa5cdb4ab67 38 #include "NotifyEvents.h"
Jonathan Austin 1:8aa5cdb4ab67 39
Jonathan Austin 1:8aa5cdb4ab67 40 static uint8_t txBufferHead = 0;
Jonathan Austin 1:8aa5cdb4ab67 41 static uint8_t txBufferTail = 0;
Jonathan Austin 1:8aa5cdb4ab67 42
Jonathan Austin 1:8aa5cdb4ab67 43 static GattCharacteristic* rxCharacteristic = NULL;
Jonathan Austin 1:8aa5cdb4ab67 44
Jonathan Austin 1:8aa5cdb4ab67 45 /**
Jonathan Austin 1:8aa5cdb4ab67 46 * A callback function for whenever a Bluetooth device consumes our RX Buffer
Jonathan Austin 1:8aa5cdb4ab67 47 */
Jonathan Austin 1:8aa5cdb4ab67 48 void on_confirmation_received_callback(uint16_t handle)
Jonathan Austin 1:8aa5cdb4ab67 49 {
Jonathan Austin 1:8aa5cdb4ab67 50 #if CONFIG_ENABLED(MICROBIT_DBG)
Jonathan Austin 1:8aa5cdb4ab67 51 SERIAL_DEBUG->printf("RECEIVED!! %d \r\n",handle);
Jonathan Austin 1:8aa5cdb4ab67 52 #endif
Jonathan Austin 1:8aa5cdb4ab67 53 if(handle == rxCharacteristic->getValueAttribute().getHandle())
Jonathan Austin 1:8aa5cdb4ab67 54 {
Jonathan Austin 1:8aa5cdb4ab67 55 txBufferTail = txBufferHead;
Jonathan Austin 1:8aa5cdb4ab67 56 MicroBitEvent(MICROBIT_ID_NOTIFY, MICROBIT_UART_S_EVT_TX_EMPTY);
Jonathan Austin 1:8aa5cdb4ab67 57 }
Jonathan Austin 1:8aa5cdb4ab67 58 }
Jonathan Austin 1:8aa5cdb4ab67 59
Jonathan Austin 1:8aa5cdb4ab67 60 /**
Jonathan Austin 1:8aa5cdb4ab67 61 * Constructor for the UARTService.
Jonathan Austin 1:8aa5cdb4ab67 62 * @param _ble an instance of BLEDevice
Jonathan Austin 1:8aa5cdb4ab67 63 * @param rxBufferSize the size of the rxBuffer
Jonathan Austin 1:8aa5cdb4ab67 64 * @param txBufferSize the size of the txBuffer
Jonathan Austin 1:8aa5cdb4ab67 65 *
Jonathan Austin 1:8aa5cdb4ab67 66 * @note defaults to 20
Jonathan Austin 1:8aa5cdb4ab67 67 */
Jonathan Austin 1:8aa5cdb4ab67 68 MicroBitUARTService::MicroBitUARTService(BLEDevice &_ble, uint8_t rxBufferSize, uint8_t txBufferSize) : ble(_ble)
Jonathan Austin 1:8aa5cdb4ab67 69 {
Jonathan Austin 1:8aa5cdb4ab67 70
Jonathan Austin 1:8aa5cdb4ab67 71 txBuffer = (uint8_t *)malloc(txBufferSize);
Jonathan Austin 1:8aa5cdb4ab67 72 rxBuffer = (uint8_t *)malloc(rxBufferSize);
Jonathan Austin 1:8aa5cdb4ab67 73
Jonathan Austin 1:8aa5cdb4ab67 74 rxBufferHead = 0;
Jonathan Austin 1:8aa5cdb4ab67 75 rxBufferTail = 0;
Jonathan Austin 1:8aa5cdb4ab67 76 this->rxBufferSize = rxBufferSize;
Jonathan Austin 1:8aa5cdb4ab67 77
Jonathan Austin 1:8aa5cdb4ab67 78 txBufferHead = 0;
Jonathan Austin 1:8aa5cdb4ab67 79 txBufferTail = 0;
Jonathan Austin 1:8aa5cdb4ab67 80 this->txBufferSize = txBufferSize;
Jonathan Austin 1:8aa5cdb4ab67 81
Jonathan Austin 1:8aa5cdb4ab67 82 GattCharacteristic txCharacteristic(UARTServiceTXCharacteristicUUID, rxBuffer, 1, rxBufferSize, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE);
Jonathan Austin 1:8aa5cdb4ab67 83
Jonathan Austin 1:8aa5cdb4ab67 84 rxCharacteristic = new GattCharacteristic(UARTServiceRXCharacteristicUUID, txBuffer, 1, txBufferSize, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE);
Jonathan Austin 1:8aa5cdb4ab67 85
Jonathan Austin 1:8aa5cdb4ab67 86 GattCharacteristic *charTable[] = {&txCharacteristic, rxCharacteristic};
Jonathan Austin 1:8aa5cdb4ab67 87
Jonathan Austin 1:8aa5cdb4ab67 88 GattService uartService(UARTServiceUUID, charTable, sizeof(charTable) / sizeof(GattCharacteristic *));
Jonathan Austin 1:8aa5cdb4ab67 89
Jonathan Austin 1:8aa5cdb4ab67 90 _ble.addService(uartService);
Jonathan Austin 1:8aa5cdb4ab67 91
Jonathan Austin 1:8aa5cdb4ab67 92 this->txCharacteristicHandle = txCharacteristic.getValueAttribute().getHandle();
Jonathan Austin 1:8aa5cdb4ab67 93
Jonathan Austin 1:8aa5cdb4ab67 94 _ble.gattServer().onDataWritten(this, &MicroBitUARTService::onDataWritten);
Jonathan Austin 1:8aa5cdb4ab67 95 _ble.gattServer().onConfirmationReceived(on_confirmation_received_callback);
Jonathan Austin 1:8aa5cdb4ab67 96 }
Jonathan Austin 1:8aa5cdb4ab67 97
Jonathan Austin 1:8aa5cdb4ab67 98 /**
Jonathan Austin 1:8aa5cdb4ab67 99 * A callback function for whenever a Bluetooth device writes to our TX characteristic.
Jonathan Austin 1:8aa5cdb4ab67 100 */
Jonathan Austin 1:8aa5cdb4ab67 101 void MicroBitUARTService::onDataWritten(const GattWriteCallbackParams *params) {
Jonathan Austin 1:8aa5cdb4ab67 102 if (params->handle == this->txCharacteristicHandle)
Jonathan Austin 1:8aa5cdb4ab67 103 {
Jonathan Austin 1:8aa5cdb4ab67 104 uint16_t bytesWritten = params->len;
Jonathan Austin 1:8aa5cdb4ab67 105
Jonathan Austin 1:8aa5cdb4ab67 106 for(int byteIterator = 0; byteIterator < bytesWritten; byteIterator++)
Jonathan Austin 1:8aa5cdb4ab67 107 {
Jonathan Austin 1:8aa5cdb4ab67 108 int newHead = (rxBufferHead + 1) % rxBufferSize;
Jonathan Austin 1:8aa5cdb4ab67 109
Jonathan Austin 1:8aa5cdb4ab67 110 if(newHead != rxBufferTail)
Jonathan Austin 1:8aa5cdb4ab67 111 {
Jonathan Austin 1:8aa5cdb4ab67 112 char c = params->data[byteIterator];
Jonathan Austin 1:8aa5cdb4ab67 113
Jonathan Austin 1:8aa5cdb4ab67 114 int delimeterOffset = 0;
Jonathan Austin 1:8aa5cdb4ab67 115 int delimLength = this->delimeters.length();
Jonathan Austin 1:8aa5cdb4ab67 116
Jonathan Austin 1:8aa5cdb4ab67 117 //iterate through our delimeters (if any) to see if there is a match
Jonathan Austin 1:8aa5cdb4ab67 118 while(delimeterOffset < delimLength)
Jonathan Austin 1:8aa5cdb4ab67 119 {
Jonathan Austin 1:8aa5cdb4ab67 120 //fire an event if there is to block any waiting fibers
Jonathan Austin 1:8aa5cdb4ab67 121 if(this->delimeters.charAt(delimeterOffset) == c)
Jonathan Austin 1:8aa5cdb4ab67 122 MicroBitEvent(MICROBIT_ID_BLE_UART, MICROBIT_UART_S_EVT_DELIM_MATCH);
Jonathan Austin 1:8aa5cdb4ab67 123
Jonathan Austin 1:8aa5cdb4ab67 124 delimeterOffset++;
Jonathan Austin 1:8aa5cdb4ab67 125 }
Jonathan Austin 1:8aa5cdb4ab67 126
Jonathan Austin 1:8aa5cdb4ab67 127 rxBuffer[rxBufferHead] = c;
Jonathan Austin 1:8aa5cdb4ab67 128
Jonathan Austin 1:8aa5cdb4ab67 129 rxBufferHead = newHead;
Jonathan Austin 1:8aa5cdb4ab67 130
Jonathan Austin 1:8aa5cdb4ab67 131 if(rxBufferHead == rxBuffHeadMatch)
Jonathan Austin 1:8aa5cdb4ab67 132 {
Jonathan Austin 1:8aa5cdb4ab67 133 rxBuffHeadMatch = -1;
Jonathan Austin 1:8aa5cdb4ab67 134 MicroBitEvent(MICROBIT_ID_BLE_UART, MICROBIT_UART_S_EVT_HEAD_MATCH);
Jonathan Austin 1:8aa5cdb4ab67 135 }
Jonathan Austin 1:8aa5cdb4ab67 136 }
Jonathan Austin 1:8aa5cdb4ab67 137 else
Jonathan Austin 1:8aa5cdb4ab67 138 MicroBitEvent(MICROBIT_ID_BLE_UART, MICROBIT_UART_S_EVT_RX_FULL);
Jonathan Austin 1:8aa5cdb4ab67 139 }
Jonathan Austin 1:8aa5cdb4ab67 140 }
Jonathan Austin 1:8aa5cdb4ab67 141 }
Jonathan Austin 1:8aa5cdb4ab67 142
Jonathan Austin 1:8aa5cdb4ab67 143 /**
Jonathan Austin 1:8aa5cdb4ab67 144 * An internal method that copies values from a circular buffer to a linear buffer.
Jonathan Austin 1:8aa5cdb4ab67 145 *
Jonathan Austin 1:8aa5cdb4ab67 146 * @param circularBuff a pointer to the source circular buffer
Jonathan Austin 1:8aa5cdb4ab67 147 * @param circularBuffSize the size of the circular buffer
Jonathan Austin 1:8aa5cdb4ab67 148 * @param linearBuff a pointer to the destination linear buffer
Jonathan Austin 1:8aa5cdb4ab67 149 * @param tailPosition the tail position in the circular buffer you want to copy from
Jonathan Austin 1:8aa5cdb4ab67 150 * @param headPosition the head position in the circular buffer you want to copy to
Jonathan Austin 1:8aa5cdb4ab67 151 *
Jonathan Austin 1:8aa5cdb4ab67 152 * @note this method assumes that the linear buffer has the appropriate amount of
Jonathan Austin 1:8aa5cdb4ab67 153 * memory to contain the copy operation
Jonathan Austin 1:8aa5cdb4ab67 154 */
Jonathan Austin 1:8aa5cdb4ab67 155 void MicroBitUARTService::circularCopy(uint8_t *circularBuff, uint8_t circularBuffSize, uint8_t *linearBuff, uint16_t tailPosition, uint16_t headPosition)
Jonathan Austin 1:8aa5cdb4ab67 156 {
Jonathan Austin 1:8aa5cdb4ab67 157 int toBuffIndex = 0;
Jonathan Austin 1:8aa5cdb4ab67 158
Jonathan Austin 1:8aa5cdb4ab67 159 while(tailPosition != headPosition)
Jonathan Austin 1:8aa5cdb4ab67 160 {
Jonathan Austin 1:8aa5cdb4ab67 161 linearBuff[toBuffIndex++] = circularBuff[tailPosition];
Jonathan Austin 1:8aa5cdb4ab67 162
Jonathan Austin 1:8aa5cdb4ab67 163 tailPosition = (tailPosition + 1) % circularBuffSize;
Jonathan Austin 1:8aa5cdb4ab67 164 }
Jonathan Austin 1:8aa5cdb4ab67 165 }
Jonathan Austin 1:8aa5cdb4ab67 166
Jonathan Austin 1:8aa5cdb4ab67 167 /**
Jonathan Austin 1:8aa5cdb4ab67 168 * Retreives a single character from our RxBuffer.
Jonathan Austin 1:8aa5cdb4ab67 169 *
Jonathan Austin 1:8aa5cdb4ab67 170 * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode
Jonathan Austin 1:8aa5cdb4ab67 171 * gives a different behaviour:
Jonathan Austin 1:8aa5cdb4ab67 172 *
Jonathan Austin 1:8aa5cdb4ab67 173 * ASYNC - Will attempt to read a single character, and return immediately
Jonathan Austin 1:8aa5cdb4ab67 174 *
Jonathan Austin 1:8aa5cdb4ab67 175 * SYNC_SPINWAIT - will return MICROBIT_INVALID_PARAMETER
Jonathan Austin 1:8aa5cdb4ab67 176 *
Jonathan Austin 1:8aa5cdb4ab67 177 * SYNC_SLEEP - Will configure the event and block the current fiber until the
Jonathan Austin 1:8aa5cdb4ab67 178 * event is received.
Jonathan Austin 1:8aa5cdb4ab67 179 *
Jonathan Austin 1:8aa5cdb4ab67 180 * @return MICROBIT_INVALID_PARAMETER if the mode given is SYNC_SPINWAIT, a character or MICROBIT_NO_DATA
Jonathan Austin 1:8aa5cdb4ab67 181 */
Jonathan Austin 1:8aa5cdb4ab67 182 int MicroBitUARTService::getc(MicroBitSerialMode mode)
Jonathan Austin 1:8aa5cdb4ab67 183 {
Jonathan Austin 1:8aa5cdb4ab67 184 if(mode == SYNC_SPINWAIT)
Jonathan Austin 1:8aa5cdb4ab67 185 return MICROBIT_INVALID_PARAMETER;
Jonathan Austin 1:8aa5cdb4ab67 186
Jonathan Austin 1:8aa5cdb4ab67 187 if(mode == ASYNC)
Jonathan Austin 1:8aa5cdb4ab67 188 {
Jonathan Austin 1:8aa5cdb4ab67 189 if(!isReadable())
Jonathan Austin 1:8aa5cdb4ab67 190 return MICROBIT_NO_DATA;
Jonathan Austin 1:8aa5cdb4ab67 191 }
Jonathan Austin 1:8aa5cdb4ab67 192
Jonathan Austin 1:8aa5cdb4ab67 193 if(mode == SYNC_SLEEP)
Jonathan Austin 1:8aa5cdb4ab67 194 {
Jonathan Austin 1:8aa5cdb4ab67 195 if(!isReadable())
Jonathan Austin 1:8aa5cdb4ab67 196 eventAfter(1, mode);
Jonathan Austin 1:8aa5cdb4ab67 197 }
Jonathan Austin 1:8aa5cdb4ab67 198
Jonathan Austin 1:8aa5cdb4ab67 199 char c = rxBuffer[rxBufferTail];
Jonathan Austin 1:8aa5cdb4ab67 200
Jonathan Austin 1:8aa5cdb4ab67 201 rxBufferTail = (rxBufferTail + 1) % rxBufferSize;
Jonathan Austin 1:8aa5cdb4ab67 202
Jonathan Austin 1:8aa5cdb4ab67 203 return c;
Jonathan Austin 1:8aa5cdb4ab67 204 }
Jonathan Austin 1:8aa5cdb4ab67 205
Jonathan Austin 1:8aa5cdb4ab67 206 /**
Jonathan Austin 1:8aa5cdb4ab67 207 * places a single character into our transmission buffer,
Jonathan Austin 1:8aa5cdb4ab67 208 *
Jonathan Austin 1:8aa5cdb4ab67 209 * @param c the character to transmit
Jonathan Austin 1:8aa5cdb4ab67 210 *
Jonathan Austin 1:8aa5cdb4ab67 211 * @return the number of characters written (0, or 1).
Jonathan Austin 1:8aa5cdb4ab67 212 */
Jonathan Austin 1:8aa5cdb4ab67 213 int MicroBitUARTService::putc(char c)
Jonathan Austin 1:8aa5cdb4ab67 214 {
Jonathan Austin 1:8aa5cdb4ab67 215 return (send((uint8_t *)&c, 1) == 1) ? 1 : EOF;
Jonathan Austin 1:8aa5cdb4ab67 216 }
Jonathan Austin 1:8aa5cdb4ab67 217
Jonathan Austin 1:8aa5cdb4ab67 218 /**
Jonathan Austin 1:8aa5cdb4ab67 219 * Copies characters into the buffer used for Transmitting to the central device.
Jonathan Austin 1:8aa5cdb4ab67 220 *
Jonathan Austin 1:8aa5cdb4ab67 221 * @param buf a buffer containing length number of bytes.
Jonathan Austin 1:8aa5cdb4ab67 222 * @param length the size of the buffer.
Jonathan Austin 1:8aa5cdb4ab67 223 *
Jonathan Austin 1:8aa5cdb4ab67 224 * @return the number of characters copied into the buffer
Jonathan Austin 1:8aa5cdb4ab67 225 *
Jonathan Austin 1:8aa5cdb4ab67 226 * @note no modes for sending are available at the moment, due to interrupt overhead.
Jonathan Austin 1:8aa5cdb4ab67 227 */
Jonathan Austin 1:8aa5cdb4ab67 228 int MicroBitUARTService::send(const uint8_t *buf, int length)
Jonathan Austin 1:8aa5cdb4ab67 229 {
Jonathan Austin 1:8aa5cdb4ab67 230 if(length < 1)
Jonathan Austin 1:8aa5cdb4ab67 231 return MICROBIT_INVALID_PARAMETER;
Jonathan Austin 1:8aa5cdb4ab67 232
Jonathan Austin 1:8aa5cdb4ab67 233 int bytesWritten = 0;
Jonathan Austin 1:8aa5cdb4ab67 234
Jonathan Austin 1:8aa5cdb4ab67 235 if (ble.getGapState().connected) {
Jonathan Austin 1:8aa5cdb4ab67 236
Jonathan Austin 1:8aa5cdb4ab67 237 for(int bufferIterator = 0; bufferIterator < length; bufferIterator++)
Jonathan Austin 1:8aa5cdb4ab67 238 {
Jonathan Austin 1:8aa5cdb4ab67 239 int nextHead = (txBufferHead + 1) % txBufferSize;
Jonathan Austin 1:8aa5cdb4ab67 240
Jonathan Austin 1:8aa5cdb4ab67 241 if(nextHead != txBufferTail)
Jonathan Austin 1:8aa5cdb4ab67 242 {
Jonathan Austin 1:8aa5cdb4ab67 243 txBuffer[txBufferHead] = buf[bufferIterator];
Jonathan Austin 1:8aa5cdb4ab67 244
Jonathan Austin 1:8aa5cdb4ab67 245 txBufferHead = nextHead;
Jonathan Austin 1:8aa5cdb4ab67 246
Jonathan Austin 1:8aa5cdb4ab67 247 bytesWritten++;
Jonathan Austin 1:8aa5cdb4ab67 248 }
Jonathan Austin 1:8aa5cdb4ab67 249 }
Jonathan Austin 1:8aa5cdb4ab67 250
Jonathan Austin 1:8aa5cdb4ab67 251 int size = txBufferedSize();
Jonathan Austin 1:8aa5cdb4ab67 252
Jonathan Austin 1:8aa5cdb4ab67 253 #if CONFIG_ENABLED(MICROBIT_DBG)
Jonathan Austin 1:8aa5cdb4ab67 254 SERIAL_DEBUG->printf("tx size: %d", size);
Jonathan Austin 1:8aa5cdb4ab67 255 #endif
Jonathan Austin 1:8aa5cdb4ab67 256
Jonathan Austin 1:8aa5cdb4ab67 257 uint8_t temp[size] = { 0 };
Jonathan Austin 1:8aa5cdb4ab67 258
Jonathan Austin 1:8aa5cdb4ab67 259 circularCopy(txBuffer, txBufferSize, temp, txBufferTail, txBufferHead);
Jonathan Austin 1:8aa5cdb4ab67 260
Jonathan Austin 1:8aa5cdb4ab67 261 #if CONFIG_ENABLED(MICROBIT_DBG)
Jonathan Austin 1:8aa5cdb4ab67 262 for(int i = 0; i < size; i++)
Jonathan Austin 1:8aa5cdb4ab67 263 SERIAL_DEBUG->printf("%c",temp[i]);
Jonathan Austin 1:8aa5cdb4ab67 264 #endif
Jonathan Austin 1:8aa5cdb4ab67 265
Jonathan Austin 1:8aa5cdb4ab67 266 ble.gattServer().write(rxCharacteristic->getValueAttribute().getHandle(), temp, size);
Jonathan Austin 1:8aa5cdb4ab67 267 }
Jonathan Austin 1:8aa5cdb4ab67 268
Jonathan Austin 1:8aa5cdb4ab67 269 #if CONFIG_ENABLED(MICROBIT_DBG)
Jonathan Austin 1:8aa5cdb4ab67 270 SERIAL_DEBUG->printf("written: %d \r\n",bytesWritten);
Jonathan Austin 1:8aa5cdb4ab67 271 #endif
Jonathan Austin 1:8aa5cdb4ab67 272
Jonathan Austin 1:8aa5cdb4ab67 273 return bytesWritten;
Jonathan Austin 1:8aa5cdb4ab67 274 }
Jonathan Austin 1:8aa5cdb4ab67 275
Jonathan Austin 1:8aa5cdb4ab67 276 /**
Jonathan Austin 1:8aa5cdb4ab67 277 * Copies characters into the buffer used for Transmitting to the central device.
Jonathan Austin 1:8aa5cdb4ab67 278 *
Jonathan Austin 1:8aa5cdb4ab67 279 * @param s the string to transmit
Jonathan Austin 1:8aa5cdb4ab67 280 *
Jonathan Austin 1:8aa5cdb4ab67 281 * @return the number of characters copied into the buffer
Jonathan Austin 1:8aa5cdb4ab67 282 *
Jonathan Austin 1:8aa5cdb4ab67 283 * @note no modes for sending are available at the moment, due to interrupt overhead.
Jonathan Austin 1:8aa5cdb4ab67 284 */
Jonathan Austin 1:8aa5cdb4ab67 285 int MicroBitUARTService::send(ManagedString s)
Jonathan Austin 1:8aa5cdb4ab67 286 {
Jonathan Austin 1:8aa5cdb4ab67 287 return send((uint8_t *)s.toCharArray(), s.length());
Jonathan Austin 1:8aa5cdb4ab67 288 }
Jonathan Austin 1:8aa5cdb4ab67 289
Jonathan Austin 1:8aa5cdb4ab67 290 /**
Jonathan Austin 1:8aa5cdb4ab67 291 * Reads a number of characters from the rxBuffer and fills user given buffer.
Jonathan Austin 1:8aa5cdb4ab67 292 *
Jonathan Austin 1:8aa5cdb4ab67 293 * @param buf a pointer to a buffer of len bytes.
Jonathan Austin 1:8aa5cdb4ab67 294 * @param len the size of the user allocated buffer
Jonathan Austin 1:8aa5cdb4ab67 295 * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode
Jonathan Austin 1:8aa5cdb4ab67 296 * gives a different behaviour:
Jonathan Austin 1:8aa5cdb4ab67 297 *
Jonathan Austin 1:8aa5cdb4ab67 298 * ASYNC - Will attempt to read all available characters, and return immediately
Jonathan Austin 1:8aa5cdb4ab67 299 * until the buffer limit is reached
Jonathan Austin 1:8aa5cdb4ab67 300 *
Jonathan Austin 1:8aa5cdb4ab67 301 * SYNC_SPINWAIT - will return MICROBIT_INVALID_PARAMETER
Jonathan Austin 1:8aa5cdb4ab67 302 *
Jonathan Austin 1:8aa5cdb4ab67 303 * SYNC_SLEEP - Will first of all determine whether the given number of characters
Jonathan Austin 1:8aa5cdb4ab67 304 * are available in our buffer, if not, it will set an event and sleep
Jonathan Austin 1:8aa5cdb4ab67 305 * until the number of characters are avaialable.
Jonathan Austin 1:8aa5cdb4ab67 306 *
Jonathan Austin 1:8aa5cdb4ab67 307 * @return the number of characters digested
Jonathan Austin 1:8aa5cdb4ab67 308 */
Jonathan Austin 1:8aa5cdb4ab67 309 int MicroBitUARTService::read(uint8_t *buf, int len, MicroBitSerialMode mode)
Jonathan Austin 1:8aa5cdb4ab67 310 {
Jonathan Austin 1:8aa5cdb4ab67 311 if(mode == SYNC_SPINWAIT)
Jonathan Austin 1:8aa5cdb4ab67 312 return MICROBIT_INVALID_PARAMETER;
Jonathan Austin 1:8aa5cdb4ab67 313
Jonathan Austin 1:8aa5cdb4ab67 314 int i = 0;
Jonathan Austin 1:8aa5cdb4ab67 315
Jonathan Austin 1:8aa5cdb4ab67 316 if(mode == ASYNC)
Jonathan Austin 1:8aa5cdb4ab67 317 {
Jonathan Austin 1:8aa5cdb4ab67 318 int c;
Jonathan Austin 1:8aa5cdb4ab67 319
Jonathan Austin 1:8aa5cdb4ab67 320 while((c = getc(mode)) > 0 && i < len)
Jonathan Austin 1:8aa5cdb4ab67 321 {
Jonathan Austin 1:8aa5cdb4ab67 322 buf[i] = c;
Jonathan Austin 1:8aa5cdb4ab67 323 i++;
Jonathan Austin 1:8aa5cdb4ab67 324 }
Jonathan Austin 1:8aa5cdb4ab67 325 }
Jonathan Austin 1:8aa5cdb4ab67 326
Jonathan Austin 1:8aa5cdb4ab67 327 if(mode == SYNC_SLEEP)
Jonathan Austin 1:8aa5cdb4ab67 328 {
Jonathan Austin 1:8aa5cdb4ab67 329 if(len > rxBufferedSize())
Jonathan Austin 1:8aa5cdb4ab67 330 eventAfter(len - rxBufferedSize(), mode);
Jonathan Austin 1:8aa5cdb4ab67 331
Jonathan Austin 1:8aa5cdb4ab67 332 while(i < len)
Jonathan Austin 1:8aa5cdb4ab67 333 {
Jonathan Austin 1:8aa5cdb4ab67 334 buf[i] = (char)getc(mode);
Jonathan Austin 1:8aa5cdb4ab67 335 i++;
Jonathan Austin 1:8aa5cdb4ab67 336 }
Jonathan Austin 1:8aa5cdb4ab67 337 }
Jonathan Austin 1:8aa5cdb4ab67 338
Jonathan Austin 1:8aa5cdb4ab67 339 return i;
Jonathan Austin 1:8aa5cdb4ab67 340 }
Jonathan Austin 1:8aa5cdb4ab67 341
Jonathan Austin 1:8aa5cdb4ab67 342 /**
Jonathan Austin 1:8aa5cdb4ab67 343 * Reads a number of characters from the rxBuffer and returns them as a ManagedString
Jonathan Austin 1:8aa5cdb4ab67 344 *
Jonathan Austin 1:8aa5cdb4ab67 345 * @param len the number of characters to read.
Jonathan Austin 1:8aa5cdb4ab67 346 * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode
Jonathan Austin 1:8aa5cdb4ab67 347 * gives a different behaviour:
Jonathan Austin 1:8aa5cdb4ab67 348 *
Jonathan Austin 1:8aa5cdb4ab67 349 * ASYNC - Will attempt to read all available characters, and return immediately
Jonathan Austin 1:8aa5cdb4ab67 350 * until the buffer limit is reached
Jonathan Austin 1:8aa5cdb4ab67 351 *
Jonathan Austin 1:8aa5cdb4ab67 352 * SYNC_SPINWAIT - will return MICROBIT_INVALID_PARAMETER
Jonathan Austin 1:8aa5cdb4ab67 353 *
Jonathan Austin 1:8aa5cdb4ab67 354 * SYNC_SLEEP - Will first of all determine whether the given number of characters
Jonathan Austin 1:8aa5cdb4ab67 355 * are available in our buffer, if not, it will set an event and sleep
Jonathan Austin 1:8aa5cdb4ab67 356 * until the number of characters are avaialable.
Jonathan Austin 1:8aa5cdb4ab67 357 *
Jonathan Austin 1:8aa5cdb4ab67 358 * @return an empty ManagedString on error, or a ManagedString containing characters
Jonathan Austin 1:8aa5cdb4ab67 359 */
Jonathan Austin 1:8aa5cdb4ab67 360 ManagedString MicroBitUARTService::read(int len, MicroBitSerialMode mode)
Jonathan Austin 1:8aa5cdb4ab67 361 {
Jonathan Austin 1:8aa5cdb4ab67 362 uint8_t buf[len + 1] = { 0 };
Jonathan Austin 1:8aa5cdb4ab67 363
Jonathan Austin 1:8aa5cdb4ab67 364 int ret = read(buf, len, mode);
Jonathan Austin 1:8aa5cdb4ab67 365
Jonathan Austin 1:8aa5cdb4ab67 366 if(ret < 1)
Jonathan Austin 1:8aa5cdb4ab67 367 return ManagedString();
Jonathan Austin 1:8aa5cdb4ab67 368
Jonathan Austin 1:8aa5cdb4ab67 369 return ManagedString((const char *)buf);
Jonathan Austin 1:8aa5cdb4ab67 370 }
Jonathan Austin 1:8aa5cdb4ab67 371
Jonathan Austin 1:8aa5cdb4ab67 372 /**
Jonathan Austin 1:8aa5cdb4ab67 373 * Reads characters until a character matches one of the given delimeters
Jonathan Austin 1:8aa5cdb4ab67 374 *
Jonathan Austin 1:8aa5cdb4ab67 375 * @param delimeters the number of characters to match against
Jonathan Austin 1:8aa5cdb4ab67 376 * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode
Jonathan Austin 1:8aa5cdb4ab67 377 * gives a different behaviour:
Jonathan Austin 1:8aa5cdb4ab67 378 *
Jonathan Austin 1:8aa5cdb4ab67 379 * ASYNC - Will attempt read the immediate buffer, and look for a match.
Jonathan Austin 1:8aa5cdb4ab67 380 * If there isn't, an empty ManagedString will be returned.
Jonathan Austin 1:8aa5cdb4ab67 381 *
Jonathan Austin 1:8aa5cdb4ab67 382 * SYNC_SPINWAIT - will return MICROBIT_INVALID_PARAMETER
Jonathan Austin 1:8aa5cdb4ab67 383 *
Jonathan Austin 1:8aa5cdb4ab67 384 * SYNC_SLEEP - Will first of all consider the characters in the immediate buffer,
Jonathan Austin 1:8aa5cdb4ab67 385 * if a match is not found, it will block on an event, fired when a
Jonathan Austin 1:8aa5cdb4ab67 386 * character is matched.
Jonathan Austin 1:8aa5cdb4ab67 387 *
Jonathan Austin 1:8aa5cdb4ab67 388 * @return an empty ManagedString on error, or a ManagedString containing characters
Jonathan Austin 1:8aa5cdb4ab67 389 */
Jonathan Austin 1:8aa5cdb4ab67 390 ManagedString MicroBitUARTService::readUntil(ManagedString delimeters, MicroBitSerialMode mode)
Jonathan Austin 1:8aa5cdb4ab67 391 {
Jonathan Austin 1:8aa5cdb4ab67 392 if(mode == SYNC_SPINWAIT)
Jonathan Austin 1:8aa5cdb4ab67 393 return MICROBIT_INVALID_PARAMETER;
Jonathan Austin 1:8aa5cdb4ab67 394
Jonathan Austin 1:8aa5cdb4ab67 395 int localTail = rxBufferTail;
Jonathan Austin 1:8aa5cdb4ab67 396 int preservedTail = rxBufferTail;
Jonathan Austin 1:8aa5cdb4ab67 397
Jonathan Austin 1:8aa5cdb4ab67 398 int foundIndex = -1;
Jonathan Austin 1:8aa5cdb4ab67 399
Jonathan Austin 1:8aa5cdb4ab67 400 //ASYNC mode just iterates through our stored characters checking for any matches.
Jonathan Austin 1:8aa5cdb4ab67 401 while(localTail != rxBufferHead && foundIndex == -1)
Jonathan Austin 1:8aa5cdb4ab67 402 {
Jonathan Austin 1:8aa5cdb4ab67 403 //we use localTail to prevent modification of the actual tail.
Jonathan Austin 1:8aa5cdb4ab67 404 char c = rxBuffer[localTail];
Jonathan Austin 1:8aa5cdb4ab67 405
Jonathan Austin 1:8aa5cdb4ab67 406 for(int delimeterIterator = 0; delimeterIterator < delimeters.length(); delimeterIterator++)
Jonathan Austin 1:8aa5cdb4ab67 407 if(delimeters.charAt(delimeterIterator) == c)
Jonathan Austin 1:8aa5cdb4ab67 408 foundIndex = localTail;
Jonathan Austin 1:8aa5cdb4ab67 409
Jonathan Austin 1:8aa5cdb4ab67 410 localTail = (localTail + 1) % rxBufferSize;
Jonathan Austin 1:8aa5cdb4ab67 411 }
Jonathan Austin 1:8aa5cdb4ab67 412
Jonathan Austin 1:8aa5cdb4ab67 413 //if our mode is SYNC_SLEEP, we set up an event to be fired when we see a
Jonathan Austin 1:8aa5cdb4ab67 414 //matching character.
Jonathan Austin 1:8aa5cdb4ab67 415 if(mode == SYNC_SLEEP && foundIndex == -1)
Jonathan Austin 1:8aa5cdb4ab67 416 {
Jonathan Austin 1:8aa5cdb4ab67 417 eventOn(delimeters, mode);
Jonathan Austin 1:8aa5cdb4ab67 418
Jonathan Austin 1:8aa5cdb4ab67 419 foundIndex = rxBufferHead - 1;
Jonathan Austin 1:8aa5cdb4ab67 420
Jonathan Austin 1:8aa5cdb4ab67 421 this->delimeters = ManagedString();
Jonathan Austin 1:8aa5cdb4ab67 422 }
Jonathan Austin 1:8aa5cdb4ab67 423
Jonathan Austin 1:8aa5cdb4ab67 424 if(foundIndex >= 0)
Jonathan Austin 1:8aa5cdb4ab67 425 {
Jonathan Austin 1:8aa5cdb4ab67 426 //calculate our local buffer size
Jonathan Austin 1:8aa5cdb4ab67 427 int localBuffSize = (preservedTail > foundIndex) ? (rxBufferSize - preservedTail) + foundIndex : foundIndex - preservedTail;
Jonathan Austin 1:8aa5cdb4ab67 428
Jonathan Austin 1:8aa5cdb4ab67 429 uint8_t localBuff[localBuffSize + 1] = { 0 };
Jonathan Austin 1:8aa5cdb4ab67 430
Jonathan Austin 1:8aa5cdb4ab67 431 circularCopy(rxBuffer, rxBufferSize, localBuff, preservedTail, foundIndex);
Jonathan Austin 1:8aa5cdb4ab67 432
Jonathan Austin 1:8aa5cdb4ab67 433 //plus one for the character we listened for...
Jonathan Austin 1:8aa5cdb4ab67 434 rxBufferTail = (rxBufferTail + localBuffSize + 1) % rxBufferSize;
Jonathan Austin 1:8aa5cdb4ab67 435
Jonathan Austin 1:8aa5cdb4ab67 436 return ManagedString((char *)localBuff, localBuffSize);
Jonathan Austin 1:8aa5cdb4ab67 437 }
Jonathan Austin 1:8aa5cdb4ab67 438
Jonathan Austin 1:8aa5cdb4ab67 439 return ManagedString();
Jonathan Austin 1:8aa5cdb4ab67 440 }
Jonathan Austin 1:8aa5cdb4ab67 441
Jonathan Austin 1:8aa5cdb4ab67 442 /**
Jonathan Austin 1:8aa5cdb4ab67 443 * Configures an event to be fired on a match with one of the delimeters.
Jonathan Austin 1:8aa5cdb4ab67 444 *
Jonathan Austin 1:8aa5cdb4ab67 445 * @param delimeters the characters to match received characters against e.g. ManagedString("\r\n")
Jonathan Austin 1:8aa5cdb4ab67 446 * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode
Jonathan Austin 1:8aa5cdb4ab67 447 * gives a different behaviour:
Jonathan Austin 1:8aa5cdb4ab67 448 *
Jonathan Austin 1:8aa5cdb4ab67 449 * ASYNC - Will configure the event and return immediately.
Jonathan Austin 1:8aa5cdb4ab67 450 *
Jonathan Austin 1:8aa5cdb4ab67 451 * SYNC_SPINWAIT - will return MICROBIT_INVALID_PARAMETER
Jonathan Austin 1:8aa5cdb4ab67 452 *
Jonathan Austin 1:8aa5cdb4ab67 453 * SYNC_SLEEP - Will configure the event and block the current fiber until the
Jonathan Austin 1:8aa5cdb4ab67 454 * event is received.
Jonathan Austin 1:8aa5cdb4ab67 455 *
Jonathan Austin 1:8aa5cdb4ab67 456 * @return MICROBIT_INVALID_PARAMETER if the mode given is SYNC_SPINWAIT, otherwise MICROBIT_OK.
Jonathan Austin 1:8aa5cdb4ab67 457 *
Jonathan Austin 1:8aa5cdb4ab67 458 * @note delimeters are matched on a per byte basis.
Jonathan Austin 1:8aa5cdb4ab67 459 */
Jonathan Austin 1:8aa5cdb4ab67 460 int MicroBitUARTService::eventOn(ManagedString delimeters, MicroBitSerialMode mode)
Jonathan Austin 1:8aa5cdb4ab67 461 {
Jonathan Austin 1:8aa5cdb4ab67 462 if(mode == SYNC_SPINWAIT)
Jonathan Austin 1:8aa5cdb4ab67 463 return MICROBIT_INVALID_PARAMETER;
Jonathan Austin 1:8aa5cdb4ab67 464
Jonathan Austin 1:8aa5cdb4ab67 465 //configure our head match...
Jonathan Austin 1:8aa5cdb4ab67 466 this->delimeters = delimeters;
Jonathan Austin 1:8aa5cdb4ab67 467
Jonathan Austin 1:8aa5cdb4ab67 468 //block!
Jonathan Austin 1:8aa5cdb4ab67 469 if(mode == SYNC_SLEEP)
Jonathan Austin 1:8aa5cdb4ab67 470 fiber_wait_for_event(MICROBIT_ID_BLE_UART, MICROBIT_UART_S_EVT_DELIM_MATCH);
Jonathan Austin 1:8aa5cdb4ab67 471
Jonathan Austin 1:8aa5cdb4ab67 472 return MICROBIT_OK;
Jonathan Austin 1:8aa5cdb4ab67 473 }
Jonathan Austin 1:8aa5cdb4ab67 474
Jonathan Austin 1:8aa5cdb4ab67 475 /**
Jonathan Austin 1:8aa5cdb4ab67 476 * Configures an event to be fired after "len" characters.
Jonathan Austin 1:8aa5cdb4ab67 477 *
Jonathan Austin 1:8aa5cdb4ab67 478 * @param len the number of characters to wait before triggering the event
Jonathan Austin 1:8aa5cdb4ab67 479 * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode
Jonathan Austin 1:8aa5cdb4ab67 480 * gives a different behaviour:
Jonathan Austin 1:8aa5cdb4ab67 481 *
Jonathan Austin 1:8aa5cdb4ab67 482 * ASYNC - Will configure the event and return immediately.
Jonathan Austin 1:8aa5cdb4ab67 483 *
Jonathan Austin 1:8aa5cdb4ab67 484 * SYNC_SPINWAIT - will return MICROBIT_INVALID_PARAMETER
Jonathan Austin 1:8aa5cdb4ab67 485 *
Jonathan Austin 1:8aa5cdb4ab67 486 * SYNC_SLEEP - Will configure the event and block the current fiber until the
Jonathan Austin 1:8aa5cdb4ab67 487 * event is received.
Jonathan Austin 1:8aa5cdb4ab67 488 *
Jonathan Austin 1:8aa5cdb4ab67 489 * @return MICROBIT_INVALID_PARAMETER if the mode given is SYNC_SPINWAIT, otherwise MICROBIT_OK.
Jonathan Austin 1:8aa5cdb4ab67 490 */
Jonathan Austin 1:8aa5cdb4ab67 491 int MicroBitUARTService::eventAfter(int len, MicroBitSerialMode mode)
Jonathan Austin 1:8aa5cdb4ab67 492 {
Jonathan Austin 1:8aa5cdb4ab67 493 if(mode == SYNC_SPINWAIT)
Jonathan Austin 1:8aa5cdb4ab67 494 return MICROBIT_INVALID_PARAMETER;
Jonathan Austin 1:8aa5cdb4ab67 495
Jonathan Austin 1:8aa5cdb4ab67 496 //configure our head match...
Jonathan Austin 1:8aa5cdb4ab67 497 this->rxBuffHeadMatch = (rxBufferHead + len) % rxBufferSize;
Jonathan Austin 1:8aa5cdb4ab67 498
Jonathan Austin 1:8aa5cdb4ab67 499 //block!
Jonathan Austin 1:8aa5cdb4ab67 500 if(mode == SYNC_SLEEP)
Jonathan Austin 1:8aa5cdb4ab67 501 fiber_wait_for_event(MICROBIT_ID_BLE_UART, MICROBIT_UART_S_EVT_HEAD_MATCH);
Jonathan Austin 1:8aa5cdb4ab67 502
Jonathan Austin 1:8aa5cdb4ab67 503 return MICROBIT_OK;
Jonathan Austin 1:8aa5cdb4ab67 504 }
Jonathan Austin 1:8aa5cdb4ab67 505
Jonathan Austin 1:8aa5cdb4ab67 506 /**
Jonathan Austin 1:8aa5cdb4ab67 507 * Determines if we have space in our rxBuff.
Jonathan Austin 1:8aa5cdb4ab67 508 *
Jonathan Austin 1:8aa5cdb4ab67 509 * @return 1 if we have space, 0 if we do not.
Jonathan Austin 1:8aa5cdb4ab67 510 *
Jonathan Austin 1:8aa5cdb4ab67 511 * @note the reason we do not wrap the super's readable() method is so that we
Jonathan Austin 1:8aa5cdb4ab67 512 * don't interfere with communities that use manual calls to uBit.serial.readable()
Jonathan Austin 1:8aa5cdb4ab67 513 */
Jonathan Austin 1:8aa5cdb4ab67 514 int MicroBitUARTService::isReadable()
Jonathan Austin 1:8aa5cdb4ab67 515 {
Jonathan Austin 1:8aa5cdb4ab67 516 return (rxBufferTail != rxBufferHead) ? 1 : 0;
Jonathan Austin 1:8aa5cdb4ab67 517 }
Jonathan Austin 1:8aa5cdb4ab67 518
Jonathan Austin 1:8aa5cdb4ab67 519 /**
Jonathan Austin 1:8aa5cdb4ab67 520 * @return The currently buffered number of bytes in our rxBuff.
Jonathan Austin 1:8aa5cdb4ab67 521 */
Jonathan Austin 1:8aa5cdb4ab67 522 int MicroBitUARTService::rxBufferedSize()
Jonathan Austin 1:8aa5cdb4ab67 523 {
Jonathan Austin 1:8aa5cdb4ab67 524 if(rxBufferTail > rxBufferHead)
Jonathan Austin 1:8aa5cdb4ab67 525 return (rxBufferSize - rxBufferTail) + rxBufferHead;
Jonathan Austin 1:8aa5cdb4ab67 526
Jonathan Austin 1:8aa5cdb4ab67 527 return rxBufferHead - rxBufferTail;
Jonathan Austin 1:8aa5cdb4ab67 528 }
Jonathan Austin 1:8aa5cdb4ab67 529
Jonathan Austin 1:8aa5cdb4ab67 530 /**
Jonathan Austin 1:8aa5cdb4ab67 531 * @return The currently buffered number of bytes in our txBuff.
Jonathan Austin 1:8aa5cdb4ab67 532 */
Jonathan Austin 1:8aa5cdb4ab67 533 int MicroBitUARTService::txBufferedSize()
Jonathan Austin 1:8aa5cdb4ab67 534 {
Jonathan Austin 1:8aa5cdb4ab67 535 if(txBufferTail > txBufferHead)
Jonathan Austin 1:8aa5cdb4ab67 536 return (txBufferSize - txBufferTail) + txBufferHead;
Jonathan Austin 1:8aa5cdb4ab67 537
Jonathan Austin 1:8aa5cdb4ab67 538 return txBufferHead - txBufferTail;
Jonathan Austin 1:8aa5cdb4ab67 539 }