/** * Copies characters into the buffer used for Transmitting to the central device. * * @param buf a buffer containing length number of bytes. * @param length the size of the buffer. * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode * gives a different behaviour: * * ASYNC - Will copy as many characters as it can into the buffer for transmission, * and return control to the user. * * SYNC_SPINWAIT - will return MICROBIT_INVALID_PARAMETER * * SYNC_SLEEP - Will perform a cooperative blocking wait until all * given characters have been received by the connected * device. * * @return the number of characters written, or MICROBIT_NOT_SUPPORTED if there is * no connected device, or the connected device has not enabled indications. */ int MicroBitUARTService::send(const uint8_t *buf, int length, MicroBitSerialMode mode) { if(length < 1 || mode == SYNC_SPINWAIT) return MICROBIT_INVALID_PARAMETER; bool updatesEnabled = false; ble.gattServer().areUpdatesEnabled(*txCharacteristic, &updatesEnabled); if(!ble.getGapState().connected && !updatesEnabled) return MICROBIT_NOT_SUPPORTED; int bytesWritten = 0; while(bytesWritten < length && ble.getGapState().connected && updatesEnabled) { for(int bufferIterator = bytesWritten; bufferIterator < length; bufferIterator++) { int nextHead = (txBufferHead + 1) % txBufferSize; if(nextHead != txBufferTail) { txBuffer[txBufferHead] = buf[bufferIterator]; txBufferHead = nextHead; bytesWritten++; } } int size = txBufferedSize(); uint8_t temp[size]; memclr(&temp, size); circularCopy(txBuffer, txBufferSize, temp, txBufferTail, txBufferHead); if(mode == SYNC_SLEEP) fiber_wake_on_event(MICROBIT_ID_NOTIFY, MICROBIT_UART_S_EVT_TX_EMPTY); ble.gattServer().write(txCharacteristic->getValueAttribute().getHandle(), temp, size); if(mode == SYNC_SLEEP) schedule(); else break; ble.gattServer().areUpdatesEnabled(*txCharacteristic, &updatesEnabled); } return bytesWritten; }
/** * An internal method to configure an interrupt on tx buffer and also * a best effort copy operation to move bytes from a user buffer to our txBuff * * @param string a pointer to the first character of the users' buffer. * * @param len the length of the string, and ultimately the maximum number of bytes * that will be copied dependent on the state of txBuff * * @param mode determines whether to configure the current fiber context or not. If * The mode is SYNC_SPINWAIT, the context will not be configured, otherwise * no context will be configured. * * @return the number of bytes copied into the buffer. */ int MicroBitSerial::setTxInterrupt(uint8_t *string, int len, MicroBitSerialMode mode) { int copiedBytes = 0; for(copiedBytes = 0; copiedBytes < len; copiedBytes++) { uint16_t nextHead = (txBuffHead + 1) % txBuffSize; if(nextHead != txBuffTail) { this->txBuff[txBuffHead] = string[copiedBytes]; txBuffHead = nextHead; } else break; } if(mode != SYNC_SPINWAIT) fiber_wake_on_event(MICROBIT_ID_NOTIFY, MICROBIT_SERIAL_EVT_TX_EMPTY); //set the TX interrupt attach(this, &MicroBitSerial::dataWritten, Serial::TxIrq); return copiedBytes; }