Asynchronous Serial Library with flow control and tag detection.

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers AsyncSerial.cpp Source File

AsyncSerial.cpp

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2006-2015 ARM Limited
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 #include "AsyncSerial/AsyncSerial.h"
00018 
00019 #include "mbed.h"
00020 
00021 #define MINIMUM_TIMEOUT 1
00022 
00023 
00024 AsyncSerial::AsyncSerial(PinName tx, PinName rx, PinName rts, PinName cts)
00025     :   SerialBase(tx, rx),
00026 
00027         sendBuffer(NULL),
00028         sendLength(0),
00029         sendIndex(0),
00030 
00031         receiveBuffer(NULL),
00032         receiveMaxLength(0),
00033         receiveIndex(0),
00034         receiveStatus(AsyncSerial::RECEIVE_TIMEOUT),
00035         receiveResult(),
00036         timeout(),
00037 
00038         insideCondition(false),
00039         conditionStartBuffer(NULL),
00040         conditionStartLength(0),
00041         conditionEndBuffer(NULL),
00042         conditionEndLength(0),
00043         conditionIndex(0),
00044 
00045         sendHandler(),
00046         receiveHandler(),
00047         waitHandler()
00048 {
00049 #if DEVICE_SERIAL_FC
00050     if ((rts != NC) && (cts != NC))
00051     {
00052         SerialBase::set_flow_control(SerialBase::RTSCTS, rts, cts);
00053     }
00054 #endif
00055 }
00056 
00057 AsyncSerial::~AsyncSerial()
00058 {
00059     SerialBase::attach<AsyncSerial>(NULL, NULL, SerialBase::RxIrq);
00060     SerialBase::attach<AsyncSerial>(NULL, NULL, SerialBase::TxIrq);
00061 }
00062 
00063 /*  Tx ISR
00064 */
00065 void AsyncSerial::putDone()
00066 {
00067     // fill Tx buffers (in case the buffer can contain more than 1 byte)
00068     while(SerialBase::writeable())
00069     {
00070         if(sendIndex < sendLength)
00071         {
00072             // send next character if there is still more to send
00073             SerialBase::_base_putc(sendBuffer[sendIndex]);
00074 
00075             // sendIndex points to the next byte to send
00076             sendIndex++;
00077         }
00078         else
00079         {
00080             // disable the TX interrupt when there is nothing left to send
00081             SerialBase::attach<AsyncSerial>(NULL, NULL, SerialBase::TxIrq);
00082 
00083             // signal callback function
00084             sendHandler.call();
00085             break;
00086         }
00087     }
00088 }
00089 
00090 /*  Rx ISR
00091 */
00092 void AsyncSerial::getReady()
00093 {
00094     // read while there are characters in buffer
00095     while(SerialBase::readable())
00096     {
00097         // read single character from buffer
00098         uint8_t input = SerialBase::_base_getc();
00099 
00100         DEBUG("%c", input);
00101 
00102         // check if start condition has been met
00103         if (insideCondition)
00104         {
00105             /*  If stop condition has been set, check if the
00106                 character matches. If it does increment counter
00107                 to point to next character in sequence. Otherwise
00108                 reset sequence search.
00109             */
00110             if (conditionEndBuffer != NULL)
00111             {
00112                 if (input == conditionEndBuffer[conditionIndex])
00113                 {
00114                     conditionIndex++;
00115 
00116                     /*  End condition has been met.
00117                         Set receive status to indicate sequence has been found
00118                         and re-arm timer. The timeout is responsible for
00119                         signaling the callback function and is useful for
00120                         decoupling the callback from the receive ISR.
00121                     */
00122                     if (conditionIndex == conditionEndLength)
00123                     {
00124                         // Disable Rx interrupt
00125                         SerialBase::attach<AsyncSerial>(NULL, NULL, SerialBase::RxIrq);
00126 
00127                         // Fire timeout to signal callback
00128                         receiveStatus = AsyncSerial::RECEIVE_FOUND;
00129                         timeout.attach_us<AsyncSerial>(this, &AsyncSerial::receiveTimeout, MINIMUM_TIMEOUT);
00130                         break;
00131                     }
00132                 }
00133                 else
00134                 {
00135                     // Character didn't match sequence. Start over.
00136                     conditionIndex = 0;
00137                 }
00138             }
00139 
00140             /*  A receive buffer is available.
00141                 Store character in buffer and check if buffer is full,
00142                 set receive status and re-arm timeout if it is.
00143             */
00144             if (receiveBuffer != NULL)
00145             {
00146                 receiveBuffer[receiveIndex] = input;
00147                 receiveIndex++;
00148 
00149                 /*  If end condition has been met we still store the character
00150                     but we do not change the receive status nor re-arm the timer.
00151                 */
00152                 if ((receiveIndex == receiveMaxLength) && (receiveStatus != AsyncSerial::RECEIVE_FOUND))
00153                 {
00154                     // Disable Rx interrupt
00155                     SerialBase::attach<AsyncSerial>(NULL, NULL, SerialBase::RxIrq);
00156 
00157                     // Fire timeout to signal callback
00158                     receiveStatus = AsyncSerial::RECEIVE_FULL;
00159                     timeout.attach_us<AsyncSerial>(this, &AsyncSerial::receiveTimeout, MINIMUM_TIMEOUT);
00160                     break;
00161                 }
00162             }
00163         }
00164         /*  Start condition has not been met.
00165         */
00166         else
00167         {
00168             if (conditionStartBuffer != NULL)
00169             {
00170                 if (input == conditionStartBuffer[conditionIndex])
00171                 {
00172                     conditionIndex++;
00173 
00174                     /*  Set condition flag and reset index since it is reused.
00175                     */
00176                     if (conditionIndex == conditionStartLength)
00177                     {
00178                         insideCondition = true;
00179                         conditionIndex = 0;
00180                     }
00181                 }
00182                 else
00183                 {
00184                     // Character didn't match sequence. Start over.
00185                     conditionIndex = 0;
00186                 }
00187             }
00188         }
00189     }
00190 }
00191 
00192 /*  Common function for signaling receive done handler or wait done handler.
00193 */
00194 void AsyncSerial::getDone(uint8_t status)
00195 {
00196     DEBUG("getDone: %d\r\n", status);
00197 
00198     /*  Check whether to call the wait handler or the receive handler.
00199     */
00200     if (receiveBuffer == NULL)
00201     {
00202         waitHandler.call(status);
00203     }
00204     else
00205     {
00206         receiveResult.buffer = receiveBuffer;
00207         receiveResult.length = receiveIndex;
00208         receiveResult.status = status;
00209 
00210         receiveHandler.call(&receiveResult);
00211     }
00212 }
00213 
00214 /*  Send block of data. Function pointer interface.
00215 */
00216 void AsyncSerial::send(send_done_t handler, const char* buffer, uint16_t length)
00217 {
00218     sendHandler.attach(handler);
00219     send(buffer, length);
00220 }
00221 
00222 /*  Common send block of data function.
00223 */
00224 void AsyncSerial::send(const char* buffer, uint16_t length)
00225 {
00226     /*  Signal callback function immediately if there is nothing to send.
00227     */
00228     if ((buffer != NULL) && (length != 0))
00229     {
00230         // Store book keeping variables
00231         sendBuffer = buffer;
00232         sendLength = length;
00233         sendIndex = 0;
00234 
00235         if(SerialBase::writeable())
00236         {
00237             // make sure not to cause contention in the irq
00238             SerialBase::attach<AsyncSerial>(NULL, NULL, SerialBase::TxIrq);
00239 
00240             // only write to hardware in one place
00241             AsyncSerial::putDone();
00242 
00243             // enable TX interrupts
00244             SerialBase::attach<AsyncSerial>(this, &AsyncSerial::putDone, SerialBase::TxIrq);
00245         }
00246 
00247         DEBUG("send: %p %d\r\n", buffer, length);
00248     }
00249     else
00250     {
00251         sendHandler.call();
00252     }
00253 }
00254 
00255 
00256 /*  Receiving block of data. Function pointer interface.
00257 */
00258 void AsyncSerial::receive(receive_done_t _handler,
00259                           uint8_t* _receiveBuffer, uint16_t _maxLength,
00260                           const char* _conditionStartBuffer, uint16_t _conditionStartLength,
00261                           const char* _conditionEndBuffer, uint16_t _conditionEndLength,
00262                           uint32_t _timeoutMilli)
00263 {
00264     receiveHandler.attach(_handler);
00265 
00266     /*  Signal callback function immediately if buffer and maxLength are invalid.
00267     */
00268     if ((_receiveBuffer == NULL) || (_maxLength == 0))
00269     {
00270         receiveResult.buffer = NULL;
00271         receiveResult.length = 0;
00272         receiveResult.status = AsyncSerial::RECEIVE_FULL;
00273 
00274         receiveHandler.call(&receiveResult);
00275     }
00276     else
00277     {
00278         receive(_receiveBuffer, _maxLength,
00279                 _conditionStartBuffer, _conditionStartLength,
00280                 _conditionEndBuffer, _conditionEndLength,
00281                 _timeoutMilli);
00282     }
00283 }
00284 
00285 /*  Common receive function.
00286 */
00287 void AsyncSerial::receive(uint8_t* _receiveBuffer, uint16_t _maxLength,
00288                           const char* _conditionStartBuffer, uint16_t _conditionStartLength,
00289                           const char* _conditionEndBuffer, uint16_t _conditionEndLength,
00290                           uint32_t _timeoutMilli)
00291 {
00292     // Book keeping variables for reception
00293     receiveBuffer = _receiveBuffer;
00294     receiveMaxLength = _maxLength;
00295     receiveIndex = 0;
00296     receiveStatus = AsyncSerial::RECEIVE_TIMEOUT;
00297 
00298     // Book keeping variables for conditions
00299     conditionStartBuffer = _conditionStartBuffer;
00300     conditionStartLength = _conditionStartLength;
00301     conditionEndBuffer = _conditionEndBuffer;
00302     conditionEndLength = _conditionEndLength;
00303     conditionIndex = 0;
00304 
00305     // Check if optional start condition is set
00306     if ((_conditionStartBuffer != NULL) && (_conditionStartLength != 0))
00307     {
00308         insideCondition = false;
00309     }
00310     else
00311     {
00312         insideCondition = true;
00313     }
00314 
00315     // Arm timer
00316     timeout.attach_us<AsyncSerial>(this, &AsyncSerial::receiveTimeout, _timeoutMilli * 1000);
00317 
00318     // Arm Rx interrupts and start receiving
00319     SerialBase::attach<AsyncSerial>(this, &AsyncSerial::getReady, SerialBase::RxIrq);
00320 
00321     DEBUG("receive: %p\r\n", _receiveBuffer);
00322 }
00323 
00324 /*  Wait until timeout or sequence is detected.
00325 */
00326 void AsyncSerial::wait(wait_done_t handler,
00327                        const char* conditionEndBuffer, uint16_t conditionEndLength,
00328                        uint32_t timeoutMilli)
00329 {
00330     waitHandler.attach(handler);
00331 
00332     receive(NULL, 0,
00333             NULL, 0,
00334             conditionEndBuffer, conditionEndLength,
00335             timeoutMilli);
00336 }
00337 
00338 /*  Timeout fired. Call common receive done function.
00339 */
00340 void AsyncSerial::receiveTimeout()
00341 {
00342     DEBUG("timeout\r\n");
00343 
00344     // Disable Rx interrupt (interrupts are not disabled if Rx timeouts)
00345     if (receiveStatus == AsyncSerial::RECEIVE_TIMEOUT)
00346     {
00347         SerialBase::attach<AsyncSerial>(NULL, NULL, SerialBase::RxIrq);
00348     }
00349 
00350     getDone(receiveStatus);
00351 }
00352