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-10
- Revision:
- 12:b45908320b9c
- Parent:
- 11:6b99dbf1b65d
- Child:
- 13:dbb23efed611
File content as of revision 12:b45908320b9c:
#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),
isReceiving(false),
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()
{
/* Only read characters from buffer if we are receiving.
On platforms with flow control, the full buffer will
force the sender to pause. This will prevent loss of
data between calls to receive.
*/
if (isReceiving)
{
// 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)
{
// stop reception
isReceiving = false;
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* buffer, uint16_t maxLength,
const char* conditionStartBuffer, uint16_t conditionStartLength,
const char* conditionEndBuffer, uint16_t conditionEndLength,
uint32_t timeoutMilli)
{
receiveHandler.attach(handler);
receive(buffer, maxLength,
conditionStartBuffer, conditionStartLength,
conditionEndBuffer, conditionEndLength,
timeoutMilli);
}
/* Common receive function.
*/
void AsyncSerial::receive(uint8_t* buffer, uint16_t maxLength,
const char* _conditionStartBuffer, uint16_t _conditionStartLength,
const char* _conditionEndBuffer, uint16_t _conditionEndLength,
uint32_t timeoutMilli)
{
/* Signal callback function immediately if buffer and maxLength are invalid.
*/
if ((buffer == NULL) || (maxLength == 0))
{
receiveResult.buffer = NULL;
receiveResult.length = 0;
receiveResult.status = AsyncSerial::RECEIVE_FULL;
receiveHandler.call(&receiveResult);
}
/* Otherwise, setup book keeping variables for reception.
*/
else
{
// Book keeping variables for reception
receiveBuffer = buffer;
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);
isReceiving = true;
}
DEBUG("receive: %p\r\n", buffer);
}
/* 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);
}

