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
Fork of BufferedSerial by
BufferedSerial.cpp
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
Generated on Sun Jul 17 2022 01:45:36 by 1.7.2