Asynchronous Serial Library with flow control and tag detection.

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);
-}
-
-