Official Sheffield ARMBand micro:bit program

Committer:
MrBedfordVan
Date:
Mon Oct 17 12:41:20 2016 +0000
Revision:
0:b9164b348919
Official Sheffield ARMBand Micro:bit program

Who changed what in which revision?

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