/** * Reads characters until a character matches one of the given delimeters * * @param delimeters the number of characters to match against * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode * gives a different behaviour: * * ASYNC - Will attempt read the immediate buffer, and look for a match. * If there isn't, an empty ManagedString will be returned. * * SYNC_SPINWAIT - will return MICROBIT_INVALID_PARAMETER * * SYNC_SLEEP - Will first of all consider the characters in the immediate buffer, * if a match is not found, it will block on an event, fired when a * character is matched. * * @return an empty ManagedString on error, or a ManagedString containing characters */ ManagedString MicroBitUARTService::readUntil(ManagedString delimeters, MicroBitSerialMode mode) { if(mode == SYNC_SPINWAIT) return MICROBIT_INVALID_PARAMETER; int localTail = rxBufferTail; int preservedTail = rxBufferTail; int foundIndex = -1; //ASYNC mode just iterates through our stored characters checking for any matches. while(localTail != rxBufferHead && foundIndex == -1) { //we use localTail to prevent modification of the actual tail. char c = rxBuffer[localTail]; for(int delimeterIterator = 0; delimeterIterator < delimeters.length(); delimeterIterator++) if(delimeters.charAt(delimeterIterator) == c) foundIndex = localTail; localTail = (localTail + 1) % rxBufferSize; } //if our mode is SYNC_SLEEP, we set up an event to be fired when we see a //matching character. if(mode == SYNC_SLEEP && foundIndex == -1) { eventOn(delimeters, mode); foundIndex = rxBufferHead - 1; this->delimeters = ManagedString(); } if(foundIndex >= 0) { //calculate our local buffer size int localBuffSize = (preservedTail > foundIndex) ? (rxBufferSize - preservedTail) + foundIndex : foundIndex - preservedTail; uint8_t localBuff[localBuffSize + 1]; memclr(&localBuff, localBuffSize + 1); circularCopy(rxBuffer, rxBufferSize, localBuff, preservedTail, foundIndex); //plus one for the character we listened for... rxBufferTail = (rxBufferTail + localBuffSize + 1) % rxBufferSize; return ManagedString((char *)localBuff, localBuffSize); } return ManagedString(); }
/** * Reads until one of the delimeters matches a character in the rxBuff * * @param delimeters a ManagedString containing a sequence of delimeter characters e.g. ManagedString("\r\n") * * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode * gives a different behaviour: * * ASYNC - If one of the delimeters matches a character already in the rxBuff * this method will return a ManagedString up to the delimeter. * Otherwise, it will return an Empty ManagedString. * * SYNC_SPINWAIT - If one of the delimeters matches a character already in the rxBuff * this method will return a ManagedString up to the delimeter. * Otherwise, this method will spin (lock up the processor) until a * received character matches one of the delimeters. * * SYNC_SLEEP - If one of the delimeters matches a character already in the rxBuff * this method will return a ManagedString up to the delimeter. * Otherwise, the calling fiber sleeps until a character matching one * of the delimeters is seen. * * Defaults to SYNC_SLEEP. * * @return A ManagedString containing the characters up to a delimeter, or an Empty ManagedString, * if another fiber is currently using this instance for reception. * * @note delimeters are matched on a per byte basis. */ ManagedString MicroBitSerial::readUntil(ManagedString delimeters, MicroBitSerialMode mode) { if(rxInUse()) return ManagedString(); //lazy initialisation of our rx buffer if(!(status & MICROBIT_SERIAL_RX_BUFF_INIT)) { int result = initialiseRx(); if(result != MICROBIT_OK) return result; } lockRx(); int localTail = rxBuffTail; int preservedTail = rxBuffTail; int foundIndex = -1; //ASYNC mode just iterates through our stored characters checking for any matches. while(localTail != rxBuffHead && foundIndex == -1) { //we use localTail to prevent modification of the actual tail. char c = rxBuff[localTail]; for(int delimeterIterator = 0; delimeterIterator < delimeters.length(); delimeterIterator++) if(delimeters.charAt(delimeterIterator) == c) foundIndex = localTail; localTail = (localTail + 1) % rxBuffSize; } //if our mode is SYNC_SPINWAIT and we didn't see any matching characters in our buffer //spin until we find a match! if(mode == SYNC_SPINWAIT) { while(foundIndex == -1) { while(localTail == rxBuffHead); char c = rxBuff[localTail]; for(int delimeterIterator = 0; delimeterIterator < delimeters.length(); delimeterIterator++) if(delimeters.charAt(delimeterIterator) == c) foundIndex = localTail; localTail = (localTail + 1) % rxBuffSize; } } //if our mode is SYNC_SLEEP, we set up an event to be fired when we see a //matching character. if(mode == SYNC_SLEEP && foundIndex == -1) { eventOn(delimeters, mode); foundIndex = rxBuffHead - 1; this->delimeters = ManagedString(); } if(foundIndex >= 0) { //calculate our local buffer size int localBuffSize = (preservedTail > foundIndex) ? (rxBuffSize - preservedTail) + foundIndex : foundIndex - preservedTail; uint8_t localBuff[localBuffSize + 1]; memclr(&localBuff, localBuffSize + 1); circularCopy(rxBuff, rxBuffSize, localBuff, preservedTail, foundIndex); //plus one for the character we listened for... rxBuffTail = (rxBuffTail + localBuffSize + 1) % rxBuffSize; unlockRx(); return ManagedString((char *)localBuff, localBuffSize); } unlockRx(); return ManagedString(); }