Inherit from Serial and use software buffers for TX and RX. This allows the UART peripherals to operate in a IRQ driven mode. Overrides most (but not all) stdio functions as Serial did

Dependencies:   Buffer

Dependents:   mbed_esp8266_demo

Fork of BufferedSerial by Sam Grove

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers BufferedSerial.cpp Source File

BufferedSerial.cpp

Go to the documentation of this file.
00001 /**
00002  * @file    BufferedSerial.cpp
00003  * @brief   Software Buffer - Extends mbed Serial functionallity adding irq driven TX and RX
00004  * @author  sam grove
00005  * @version 1.0
00006  * @see
00007  *
00008  * Copyright (c) 2013
00009  *
00010  * Licensed under the Apache License, Version 2.0 (the "License");
00011  * you may not use this file except in compliance with the License.
00012  * You may obtain a copy of the License at
00013  *
00014  *     http://www.apache.org/licenses/LICENSE-2.0
00015  *
00016  * Unless required by applicable law or agreed to in writing, software
00017  * distributed under the License is distributed on an "AS IS" BASIS,
00018  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00019  * See the License for the specific language governing permissions and
00020  * limitations under the License.
00021  */
00022 
00023 #include "BufferedSerial.h"
00024 #include <stdarg.h>
00025 
00026 BufferedSerial::BufferedSerial(PinName tx, PinName rx, uint32_t buf_size, uint32_t tx_multiple, const char* name)
00027     : SERIAL_BASE(tx, rx) , _rxbuf(buf_size), _txbuf((uint32_t)(tx_multiple*buf_size))
00028 {
00029     SERIAL_BASE::attach(this, &BufferedSerial::rxIrq, Serial::RxIrq);
00030     this->_buf_size = buf_size;
00031     this->_tx_multiple = tx_multiple;   
00032     return;
00033 }
00034 
00035 BufferedSerial::~BufferedSerial(void)
00036 {
00037     SERIAL_BASE::attach(NULL, SERIAL_BASE::RxIrq);
00038     SERIAL_BASE::attach(NULL, SERIAL_BASE::TxIrq);
00039 
00040     return;
00041 }
00042 
00043 int BufferedSerial::readable(void)
00044 {
00045     return _rxbuf.available();  // note: look if things are in the buffer
00046 }
00047 
00048 int BufferedSerial::writeable(void)
00049 {
00050     return 1;   // buffer allows overwriting by design, always true
00051 }
00052 
00053 int BufferedSerial::getc(void)
00054 {
00055     while (!readable() && !SERIAL_BASE::readable())
00056         ;
00057     return _rxbuf;
00058 }
00059 
00060 
00061 char* BufferedSerial::readl(char *s, int size) 
00062 {
00063     if (s == NULL || size <= 0)
00064         return NULL;
00065 
00066     char* ptr = s;
00067 
00068     while (1) {
00069         if (readable()) {
00070             if ((size--) > 0) {
00071                 *ptr = _rxbuf;
00072                 if (*ptr == '\n' || *ptr == 0) {
00073                     break;
00074                 }
00075                 ptr++;
00076             } else
00077                 goto end;
00078         }
00079     }
00080     if (size > 0)
00081         *ptr = 0;
00082     end: return s;
00083 }
00084 
00085 int BufferedSerial::putc(int c)
00086 {
00087     _txbuf = (char)c;
00088     BufferedSerial::prime();
00089 
00090     return c;
00091 }
00092 
00093 int BufferedSerial::puts(const char *s)
00094 {
00095     if (s != NULL) {
00096         const char* ptr = s;
00097     
00098         while(*(ptr) != 0) {
00099             _txbuf = *(ptr++);
00100         }
00101         _txbuf = '\n';  // done per puts definition
00102         BufferedSerial::prime();
00103     
00104         return (ptr - s) + 1;
00105     }
00106     return 0;
00107 }
00108 
00109 int BufferedSerial::printf(const char* format, ...)
00110 {
00111     char buffer[this->_buf_size];
00112     memset(buffer,0,this->_buf_size);
00113     int r = 0;
00114 
00115     va_list arg;
00116     va_start(arg, format);
00117     r = vsprintf(buffer, format, arg);
00118     // this may not hit the heap but should alert the user anyways
00119     if(r > this->_buf_size) {
00120         error("%s %d buffer overwrite (max_buf_size: %d exceeded: %d)!\r\n", __FILE__, __LINE__,this->_buf_size,r);
00121         va_end(arg);
00122         return 0;
00123     }
00124     va_end(arg);
00125     r = BufferedSerial::write(buffer, r);
00126 
00127     return r;
00128 }
00129 
00130 ssize_t BufferedSerial::write(const void *s, size_t length)
00131 {
00132     if (s != NULL && length > 0) {
00133         const char* ptr = (const char*)s;
00134         const char* end = ptr + length;
00135     
00136         while (ptr != end) {
00137             _txbuf = *(ptr++);
00138         }
00139         BufferedSerial::prime();
00140     
00141         return ptr - (const char*)s;
00142     }
00143     return 0;
00144 }
00145 
00146 
00147 void BufferedSerial::rxIrq(void)
00148 {
00149     // read from the peripheral and make sure something is available
00150     if(serial_readable(&_serial)) {
00151         _rxbuf = serial_getc(&_serial); // if so load them into a buffer
00152     }
00153 
00154     return;
00155 }
00156 
00157 void BufferedSerial::txIrq(void)
00158 {
00159     // see if there is room in the hardware fifo and if something is in the software fifo
00160     while(serial_writable(&_serial)) {
00161         if(_txbuf.available()) {
00162             serial_putc(&_serial, (int)_txbuf.get());
00163         } else {
00164             // disable the TX interrupt when there is nothing left to send
00165             SERIAL_BASE::attach(NULL, SERIAL_BASE::TxIrq);
00166             break;
00167         }
00168     }
00169 
00170     return;
00171 }
00172 
00173 void BufferedSerial::prime(void)
00174 {
00175     // if already busy then the irq will pick this up
00176     if(serial_writable(&_serial)) {
00177         SERIAL_BASE::attach(NULL, SERIAL_BASE::TxIrq);    // make sure not to cause contention in the irq
00178         BufferedSerial::txIrq();                // only write to hardware in one place
00179         SERIAL_BASE::attach(this, &BufferedSerial::txIrq, SERIAL_BASE::TxIrq);
00180     }
00181 
00182     return;
00183 }
00184 
00185