Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
source/AsyncSerial.cpp
- Committer:
- Marcus Chang
- Date:
- 2015-04-15
- Revision:
- 15:4d7d96cacc18
- Parent:
- 13:dbb23efed611
- Child:
- 16:55e6fbfc1e9d
File content as of revision 15:4d7d96cacc18:
#include "AsyncSerial/AsyncSerial.h"
#include "mbed.h"
#define MINIMUM_TIMEOUT 1
AsyncSerial::AsyncSerial(PinName tx, PinName rx, PinName rts, PinName cts)
: SerialBase(tx, rx),
sendBuffer(NULL),
sendLength(0),
sendIndex(0),
receiveBuffer(NULL),
receiveMaxLength(0),
receiveIndex(0),
receiveStatus(AsyncSerial::RECEIVE_TIMEOUT),
receiveResult(),
timeout(),
insideCondition(false),
conditionStartBuffer(NULL),
conditionStartLength(0),
conditionEndBuffer(NULL),
conditionEndLength(0),
conditionIndex(0),
sendHandler(),
receiveHandler(),
waitHandler()
{
// register ISR for receiving and sending
SerialBase::attach<AsyncSerial>(this, &AsyncSerial::getReady, SerialBase::RxIrq);
SerialBase::attach<AsyncSerial>(this, &AsyncSerial::putDone, SerialBase::TxIrq);
#if DEVICE_SERIAL_FC
SerialBase::set_flow_control(SerialBase::RTSCTS, rts, cts);
#endif
}
/* Tx ISR
*/
void AsyncSerial::putDone()
{
// sendIndex points to the next byte to send
sendIndex++;
if (sendIndex < sendLength)
{
// send next character if there is still more to send
SerialBase::_base_putc(sendBuffer[sendIndex]);
}
else
{
// else signal callback function
sendHandler.call();
}
}
/* Rx ISR
*/
void AsyncSerial::getReady()
{
// read character from buffer
uint8_t input = SerialBase::_base_getc();
DEBUG("%c", input);
// check if start condition has been met
if (insideCondition)
{
/* If stop condition has been set, check if the
character matches. If it does increment counter
to point to next character in sequence. Otherwise
reset sequence search.
*/
if (conditionEndBuffer != NULL)
{
if (input == conditionEndBuffer[conditionIndex])
{
conditionIndex++;
/* End condition has been met.
Set receive status to indicate sequence has been found
and re-arm timer. The timeout is responsible for
signaling the callback function and is useful for
decoupling the callback from the receive ISR.
*/
if (conditionIndex == conditionEndLength)
{
receiveStatus = AsyncSerial::RECEIVE_FOUND;
timeout.attach_us<AsyncSerial>(this, &AsyncSerial::receiveTimeout, MINIMUM_TIMEOUT);
}
}
else
{
// Character didn't match sequence. Start over.
conditionIndex = 0;
}
}
/* A receive buffer is available.
Store character in buffer and check if buffer is full,
set receive status and re-arm timeout if it is.
*/
if (receiveBuffer != NULL)
{
receiveBuffer[receiveIndex] = input;
receiveIndex++;
/* If end condition has been met we still store the character
but we do not change the receive status nor re-arm the timer.
*/
if ((receiveIndex == receiveMaxLength) && (receiveStatus != AsyncSerial::RECEIVE_FOUND))
{
receiveStatus = AsyncSerial::RECEIVE_FULL;
timeout.attach_us<AsyncSerial>(this, &AsyncSerial::receiveTimeout, MINIMUM_TIMEOUT);
}
}
}
/* Start condition has not been met.
*/
else
{
if (conditionStartBuffer != NULL)
{
if (input == conditionStartBuffer[conditionIndex])
{
conditionIndex++;
/* Set condition flag and reset index since it is reused.
*/
if (conditionIndex == conditionStartLength)
{
insideCondition = true;
conditionIndex = 0;
}
}
else
{
// Character didn't match sequence. Start over.
conditionIndex = 0;
}
}
}
}
/* Common function for signaling receive done handler or wait done handler.
*/
void AsyncSerial::getDone(uint8_t status)
{
DEBUG("getDone: %d\r\n", status);
/* Check whether to call the wait handler or the receive handler.
*/
if (receiveBuffer == NULL)
{
waitHandler.call(status);
}
else
{
receiveResult.buffer = receiveBuffer;
receiveResult.length = receiveIndex;
receiveResult.status = status;
receiveHandler.call(&receiveResult);
}
}
/* Send block of data. Function pointer interface.
*/
void AsyncSerial::send(send_done_t handler, const char* buffer, uint16_t length)
{
sendHandler.attach(handler);
send(buffer, length);
}
/* Common send block of data function.
*/
void AsyncSerial::send(const char* buffer, uint16_t length)
{
/* Signal callback function immediately if there is nothing to send.
*/
if ((buffer != NULL) && (length != 0))
{
// Store book keeping variables
sendBuffer = buffer;
sendLength = length;
sendIndex = 0;
// Send first character. ISR sends the rest.
SerialBase::_base_putc(sendBuffer[sendIndex]);
DEBUG("send: %p %d\r\n", buffer, length);
}
else
{
sendHandler.call();
}
}
/* Receiving block of data. Function pointer interface.
*/
void AsyncSerial::receive(receive_done_t _handler,
uint8_t* _receiveBuffer, uint16_t _maxLength,
const char* _conditionStartBuffer, uint16_t _conditionStartLength,
const char* _conditionEndBuffer, uint16_t _conditionEndLength,
uint32_t _timeoutMilli)
{
receiveHandler.attach(_handler);
/* Signal callback function immediately if buffer and maxLength are invalid.
*/
if ((_receiveBuffer == NULL) || (_maxLength == 0))
{
receiveResult.buffer = NULL;
receiveResult.length = 0;
receiveResult.status = AsyncSerial::RECEIVE_FULL;
receiveHandler.call(&receiveResult);
}
else
{
receive(_receiveBuffer, _maxLength,
_conditionStartBuffer, _conditionStartLength,
_conditionEndBuffer, _conditionEndLength,
_timeoutMilli);
}
}
/* Common receive function.
*/
void AsyncSerial::receive(uint8_t* _receiveBuffer, uint16_t _maxLength,
const char* _conditionStartBuffer, uint16_t _conditionStartLength,
const char* _conditionEndBuffer, uint16_t _conditionEndLength,
uint32_t _timeoutMilli)
{
// Book keeping variables for reception
receiveBuffer = _receiveBuffer;
receiveMaxLength = _maxLength;
receiveIndex = 0;
receiveStatus = AsyncSerial::RECEIVE_TIMEOUT;
// Book keeping variables for conditions
conditionStartBuffer = _conditionStartBuffer;
conditionStartLength = _conditionStartLength;
conditionEndBuffer = _conditionEndBuffer;
conditionEndLength = _conditionEndLength;
conditionIndex = 0;
// Check if optional start condition is set
if ((_conditionStartBuffer != NULL) && (_conditionStartLength != 0))
{
insideCondition = false;
}
else
{
insideCondition = true;
}
// Clear buffer. This re-arms the rx interrupts.
while (SerialBase::readable())
{
SerialBase::_base_getc();
}
// Arm timer and start receiving.
timeout.attach_us<AsyncSerial>(this, &AsyncSerial::receiveTimeout, _timeoutMilli * 1000);
DEBUG("receive: %p\r\n", _receiveBuffer);
}
/* Wait until timeout or sequence is detected.
*/
void AsyncSerial::wait(wait_done_t handler,
const char* conditionEndBuffer, uint16_t conditionEndLength,
uint32_t timeoutMilli)
{
waitHandler.attach(handler);
receive(NULL, 0,
NULL, 0,
conditionEndBuffer, conditionEndLength,
timeoutMilli);
}
/* Timeout fired. Call common receive done function.
*/
void AsyncSerial::receiveTimeout()
{
DEBUG("timeout\r\n");
getDone(receiveStatus);
}

