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.
Diff: source/AsyncSerial.cpp
- Revision:
- 12:b45908320b9c
- Parent:
- 11:6b99dbf1b65d
- Child:
- 13:dbb23efed611
--- a/source/AsyncSerial.cpp Fri Apr 10 14:27:21 2015 +0000
+++ b/source/AsyncSerial.cpp Fri Apr 10 17:02:09 2015 +0100
@@ -11,16 +11,13 @@
sendLength(0),
sendIndex(0),
- sendHandler(),
- receiveHandler(),
- receiveResult(),
- waitHandler(),
-
isReceiving(false),
receiveBuffer(NULL),
receiveMaxLength(0),
receiveIndex(0),
receiveStatus(AsyncSerial::RECEIVE_TIMEOUT),
+ receiveResult(),
+ timeout()
insideCondition(false),
conditionStartBuffer(NULL),
@@ -28,8 +25,12 @@
conditionEndBuffer(NULL),
conditionEndLength(0),
conditionIndex(0),
- timeout()
+
+ 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);
@@ -38,36 +39,61 @@
#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
{
- sendHandler.call();
+ // 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;
@@ -76,15 +102,23 @@
}
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;
@@ -92,6 +126,8 @@
}
}
}
+ /* Start condition has not been met.
+ */
else
{
if (conditionStartBuffer != NULL)
@@ -100,6 +136,8 @@
{
conditionIndex++;
+ /* Set condition flag and reset index since it is reused.
+ */
if (conditionIndex == conditionStartLength)
{
insideCondition = true;
@@ -108,6 +146,7 @@
}
else
{
+ // Character didn't match sequence. Start over.
conditionIndex = 0;
}
}
@@ -115,13 +154,18 @@
}
}
+/* 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);
- if ((receiveBuffer == NULL) && (conditionStartBuffer == NULL))
+ /* Check whether to call the wait handler or the receive handler.
+ */
+ if (receiveBuffer == NULL)
{
waitHandler.call(status);
}
@@ -135,22 +179,30 @@
}
}
+/* Send block of data. Function pointer interface.
+*/
void AsyncSerial::send(send_done_t handler, const char* buffer, uint16_t length)
{
- sendHandler.attach(handler);
+ 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
@@ -159,60 +211,82 @@
}
}
+/* 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)
{
- if (handler)
- {
- receiveHandler.attach(handler);
+ receiveHandler.attach(handler);
- receive(buffer, maxLength,
- conditionStartBuffer, conditionStartLength,
- conditionEndBuffer, conditionEndLength,
- timeoutMilli);
- }
+ 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)
{
- receiveBuffer = buffer;
- receiveMaxLength = maxLength;
- receiveIndex = 0;
+ /* 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;
- conditionStartBuffer = _conditionStartBuffer;
- conditionStartLength = _conditionStartLength;
- conditionEndBuffer = _conditionEndBuffer;
- conditionEndLength = _conditionEndLength;
- conditionIndex = 0;
-
- if ((_conditionStartBuffer != NULL) && (_conditionStartLength != 0))
- {
- insideCondition = false;
+ receiveHandler.call(&receiveResult);
}
+ /* Otherwise, setup book keeping variables for reception.
+ */
else
{
- insideCondition = true;
- }
+ // 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;
- while (SerialBase::readable())
- {
- SerialBase::_base_getc();
+ // 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;
}
- receiveStatus = AsyncSerial::RECEIVE_TIMEOUT;
- timeout.attach_us<AsyncSerial>(this, &AsyncSerial::receiveTimeout, timeoutMilli * 1000);
- isReceiving = true;
-
- DEBUG("receive: %p\r\n", receiveBuffer);
+ 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)
@@ -225,6 +299,8 @@
timeoutMilli);
}
+/* Timeout fired. Call common receive done function.
+*/
void AsyncSerial::receiveTimeout()
{
DEBUG("timeout\r\n");
@@ -232,14 +308,3 @@
getDone(receiveStatus);
}
-int AsyncSerial::getc()
-{
- return SerialBase::_base_getc();
-}
-
-int AsyncSerial::putc(int c)
-{
- return SerialBase::_base_putc(c);
-}
-
-

