Fork of my original MQTTGateway

Dependencies:   mbed-http

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