CHE-WEI LIN / BufferedSerial

Dependencies:   Buffer

Dependents:   ATParser

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     : RawSerial(tx, rx) , _rxbuf(buf_size), _txbuf((uint32_t)(tx_multiple*buf_size))
00028 {
00029     RawSerial::attach(callback(this, &BufferedSerial::rxIrq), Serial::RxIrq);
00030     this->_buf_size = buf_size;
00031     this->_tx_multiple = tx_multiple;   
00032     return;
00033 }
00034 
00035 void BufferedSerial::attach(Callback<void()> func)
00036 {
00037     if(func) {
00038         this->_rx.attach(func);
00039     }
00040 }
00041 
00042 BufferedSerial::~BufferedSerial(void)
00043 {
00044     RawSerial::attach(NULL, RawSerial::RxIrq);
00045     RawSerial::attach(NULL, RawSerial::TxIrq);
00046 
00047     return;
00048 }
00049 
00050 int BufferedSerial::readable(void)
00051 {
00052     return _rxbuf.available();  // note: look if things are in the buffer
00053 }
00054 
00055 int BufferedSerial::writeable(void)
00056 {
00057     return 1;   // buffer allows overwriting by design, always true
00058 }
00059 
00060 int BufferedSerial::getc(void)
00061 {
00062     return _rxbuf;
00063 }
00064 
00065 int BufferedSerial::putc(int c)
00066 {
00067     _txbuf = (char)c;
00068     BufferedSerial::prime();
00069 
00070     return c;
00071 }
00072 
00073 int BufferedSerial::puts(const char *s)
00074 {
00075     if (s != NULL) {
00076         const char* ptr = s;
00077     
00078         while(*(ptr) != 0) {
00079             _txbuf = *(ptr++);
00080         }
00081         _txbuf = '\n';  // done per puts definition
00082         BufferedSerial::prime();
00083     
00084         return (ptr - s) + 1;
00085     }
00086     return 0;
00087 }
00088 
00089 int BufferedSerial::printf(const char* format, ...)
00090 {
00091     char buffer[this->_buf_size];
00092     memset(buffer,0,this->_buf_size);
00093     int r = 0;
00094 
00095     va_list arg;
00096     va_start(arg, format);
00097     r = vsprintf(buffer, format, arg);
00098     // this may not hit the heap but should alert the user anyways
00099     if(r > this->_buf_size) {
00100         error("%s %d buffer overwrite (max_buf_size: %d exceeded: %d)!\r\n", __FILE__, __LINE__,this->_buf_size,r);
00101         va_end(arg);
00102         return 0;
00103     }
00104     va_end(arg);
00105     r = BufferedSerial::write(buffer, r);
00106 
00107     return r;
00108 }
00109 
00110 ssize_t BufferedSerial::write(const void *s, size_t length)
00111 {
00112     if (s != NULL && length > 0) {
00113         const char* ptr = (const char*)s;
00114         const char* end = ptr + length;
00115     
00116         while (ptr != end) {
00117             _txbuf = *(ptr++);
00118         }
00119         BufferedSerial::prime();
00120     
00121         return ptr - (const char*)s;
00122     }
00123     return 0;
00124 }
00125 
00126 
00127 void BufferedSerial::rxIrq(void)
00128 {
00129     // read from the peripheral and make sure something is available
00130     if(serial_readable(&_serial)) {
00131         _rxbuf = serial_getc(&_serial); // if so load them into a buffer
00132         _rx.call();
00133     }
00134 
00135     return;
00136 }
00137 
00138 void BufferedSerial::txIrq(void)
00139 {
00140     // see if there is room in the hardware fifo and if something is in the software fifo
00141     while(serial_writable(&_serial)) {
00142         if(_txbuf.available()) {
00143             serial_putc(&_serial, (int)_txbuf.get());
00144         } else {
00145             // disable the TX interrupt when there is nothing left to send
00146             RawSerial::attach(NULL, RawSerial::TxIrq);
00147             break;
00148         }
00149     }
00150 
00151     return;
00152 }
00153 
00154 void BufferedSerial::prime(void)
00155 {
00156     // if already busy then the irq will pick this up
00157     if(serial_writable(&_serial)) {
00158         RawSerial::attach(NULL, RawSerial::TxIrq);    // make sure not to cause contention in the irq
00159         BufferedSerial::txIrq();                // only write to hardware in one place
00160         RawSerial::attach(callback(this, &BufferedSerial::txIrq), RawSerial::TxIrq);
00161     }
00162 
00163     return;
00164 }
00165 
00166