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:   buffered_serial_test BLE_Police_HRM evena_BLE_Police_HRM df-2014-workshop-rfid-case-generator-k64f ... more

Example

 #include "mbed.h"
 #include "BufferedSerial.h"

 BufferedSerial pc(USBTX, USBRX);

 int main()
 {
     pc.baud(115200);
   
     while(1)
     {
         Timer s;
       
         s.start();
         pc.printf("Hello World - buff\n");
         int buffered_time = s.read_us();
         wait(0.1f); // give time for the buffer to empty
       
         s.reset();
         printf("Hello World - poll\n");
         int polled_time = s.read_us();
         s.stop();
         wait(0.1f); // give time for the buffer to empty
       
         pc.printf("printf buffered took %d us\n", buffered_time);
         pc.printf("printf polled took %d us\n", polled_time);
         wait(0.5f);
     }
 }
Committer:
ansond
Date:
Fri Jan 02 03:47:26 2015 +0000
Revision:
7:6fa214b41d73
Parent:
6:8287e83943f0
Child:
8:506247a040bc
made updates to enable the ability to expand the internal buffer. Additionally, used the definition to set the size of the ring buffers in the constructor initializer list. Increased the default buffer size to 512. Additional clean ups (param cks)

Who changed what in which revision?

UserRevisionLine numberNew contents of line
sam_grove 0:a977d0a3d81e 1 /**
sam_grove 0:a977d0a3d81e 2 * @file BufferedSerial.cpp
sam_grove 0:a977d0a3d81e 3 * @brief Software Buffer - Extends mbed Serial functionallity adding irq driven TX and RX
sam_grove 0:a977d0a3d81e 4 * @author sam grove
sam_grove 0:a977d0a3d81e 5 * @version 1.0
sam_grove 4:2ba4d2e1f05d 6 * @see
sam_grove 0:a977d0a3d81e 7 *
sam_grove 0:a977d0a3d81e 8 * Copyright (c) 2013
sam_grove 0:a977d0a3d81e 9 *
sam_grove 0:a977d0a3d81e 10 * Licensed under the Apache License, Version 2.0 (the "License");
sam_grove 0:a977d0a3d81e 11 * you may not use this file except in compliance with the License.
sam_grove 0:a977d0a3d81e 12 * You may obtain a copy of the License at
sam_grove 0:a977d0a3d81e 13 *
sam_grove 0:a977d0a3d81e 14 * http://www.apache.org/licenses/LICENSE-2.0
sam_grove 0:a977d0a3d81e 15 *
sam_grove 0:a977d0a3d81e 16 * Unless required by applicable law or agreed to in writing, software
sam_grove 0:a977d0a3d81e 17 * distributed under the License is distributed on an "AS IS" BASIS,
sam_grove 0:a977d0a3d81e 18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
sam_grove 0:a977d0a3d81e 19 * See the License for the specific language governing permissions and
sam_grove 0:a977d0a3d81e 20 * limitations under the License.
sam_grove 0:a977d0a3d81e 21 */
sam_grove 0:a977d0a3d81e 22
sam_grove 0:a977d0a3d81e 23 #include "BufferedSerial.h"
sam_grove 0:a977d0a3d81e 24 #include <stdarg.h>
sam_grove 0:a977d0a3d81e 25
sam_grove 0:a977d0a3d81e 26 BufferedSerial::BufferedSerial(PinName tx, PinName rx, const char* name)
ansond 7:6fa214b41d73 27 : SERIAL_BASE(tx, rx), _rxbuf(BUFFEREDSERIAL_MAX_BUFFER_SIZE), _txbuf(BUFFEREDSERIAL_MAX_BUFFER_SIZE)
sam_grove 0:a977d0a3d81e 28 {
ansond 6:8287e83943f0 29 SERIAL_BASE::attach(this, &BufferedSerial::rxIrq, Serial::RxIrq);
ansond 7:6fa214b41d73 30
sam_grove 0:a977d0a3d81e 31 return;
sam_grove 0:a977d0a3d81e 32 }
sam_grove 0:a977d0a3d81e 33
sam_grove 0:a977d0a3d81e 34 BufferedSerial::~BufferedSerial(void)
sam_grove 0:a977d0a3d81e 35 {
ansond 6:8287e83943f0 36 SERIAL_BASE::attach(NULL, SERIAL_BASE::RxIrq);
ansond 6:8287e83943f0 37 SERIAL_BASE::attach(NULL, SERIAL_BASE::TxIrq);
sam_grove 4:2ba4d2e1f05d 38
sam_grove 0:a977d0a3d81e 39 return;
sam_grove 0:a977d0a3d81e 40 }
sam_grove 0:a977d0a3d81e 41
sam_grove 0:a977d0a3d81e 42 int BufferedSerial::readable(void)
sam_grove 0:a977d0a3d81e 43 {
sam_grove 0:a977d0a3d81e 44 return _rxbuf.available(); // note: look if things are in the buffer
sam_grove 0:a977d0a3d81e 45 }
sam_grove 0:a977d0a3d81e 46
sam_grove 0:a977d0a3d81e 47 int BufferedSerial::writeable(void)
sam_grove 0:a977d0a3d81e 48 {
sam_grove 0:a977d0a3d81e 49 return 1; // buffer allows overwriting by design, always true
sam_grove 0:a977d0a3d81e 50 }
sam_grove 0:a977d0a3d81e 51
sam_grove 0:a977d0a3d81e 52 int BufferedSerial::getc(void)
sam_grove 0:a977d0a3d81e 53 {
sam_grove 3:6b76fcf27545 54 return _rxbuf;
sam_grove 0:a977d0a3d81e 55 }
sam_grove 0:a977d0a3d81e 56
sam_grove 0:a977d0a3d81e 57 int BufferedSerial::putc(int c)
sam_grove 0:a977d0a3d81e 58 {
sam_grove 0:a977d0a3d81e 59 _txbuf = (char)c;
sam_grove 1:57a11fb5d529 60 BufferedSerial::prime();
sam_grove 4:2ba4d2e1f05d 61
sam_grove 0:a977d0a3d81e 62 return c;
sam_grove 0:a977d0a3d81e 63 }
sam_grove 0:a977d0a3d81e 64
sam_grove 0:a977d0a3d81e 65 int BufferedSerial::puts(const char *s)
sam_grove 0:a977d0a3d81e 66 {
ansond 7:6fa214b41d73 67 if (s != NULL) {
ansond 7:6fa214b41d73 68 const char* ptr = s;
ansond 7:6fa214b41d73 69
ansond 7:6fa214b41d73 70 while(*(ptr) != 0) {
ansond 7:6fa214b41d73 71 _txbuf = *(ptr++);
ansond 7:6fa214b41d73 72 }
ansond 7:6fa214b41d73 73 _txbuf = '\n'; // done per puts definition
ansond 7:6fa214b41d73 74 BufferedSerial::prime();
ansond 7:6fa214b41d73 75
ansond 7:6fa214b41d73 76 return (ptr - s) + 1;
sam_grove 0:a977d0a3d81e 77 }
ansond 7:6fa214b41d73 78 return 0;
sam_grove 0:a977d0a3d81e 79 }
sam_grove 0:a977d0a3d81e 80
sam_grove 0:a977d0a3d81e 81 int BufferedSerial::printf(const char* format, ...)
sam_grove 0:a977d0a3d81e 82 {
ansond 7:6fa214b41d73 83 memset(this->_buffer,0,BUFFEREDSERIAL_MAX_BUFFER_SIZE+1);
sam_grove 0:a977d0a3d81e 84 int r = 0;
sam_grove 4:2ba4d2e1f05d 85
sam_grove 0:a977d0a3d81e 86 va_list arg;
sam_grove 0:a977d0a3d81e 87 va_start(arg, format);
ansond 7:6fa214b41d73 88 r = vsprintf(this->_buffer, format, arg);
sam_grove 0:a977d0a3d81e 89 // this may not hit the heap but should alert the user anyways
ansond 7:6fa214b41d73 90 if(r > BUFFEREDSERIAL_MAX_BUFFER_SIZE) {
ansond 7:6fa214b41d73 91 error("%s %d buffer overwrite (max_buf_size: %d exceeded: %d)!\r\n", __FILE__, __LINE__,BUFFEREDSERIAL_MAX_BUFFER_SIZE,r);
ansond 7:6fa214b41d73 92 va_end(arg);
ansond 7:6fa214b41d73 93 return 0;
sam_grove 0:a977d0a3d81e 94 }
sam_grove 4:2ba4d2e1f05d 95 va_end(arg);
ansond 7:6fa214b41d73 96 r = BufferedSerial::write(this->_buffer, r);
sam_grove 4:2ba4d2e1f05d 97
sam_grove 0:a977d0a3d81e 98 return r;
sam_grove 0:a977d0a3d81e 99 }
sam_grove 0:a977d0a3d81e 100
sam_grove 2:7e8a450a9101 101 ssize_t BufferedSerial::write(const void *s, size_t length)
sam_grove 2:7e8a450a9101 102 {
ansond 7:6fa214b41d73 103 if (s != NULL && length > 0) {
ansond 7:6fa214b41d73 104 const char* ptr = (const char*)s;
ansond 7:6fa214b41d73 105 const char* end = ptr + length;
ansond 7:6fa214b41d73 106
ansond 7:6fa214b41d73 107 while (ptr != end) {
ansond 7:6fa214b41d73 108 _txbuf = *(ptr++);
ansond 7:6fa214b41d73 109 }
ansond 7:6fa214b41d73 110 BufferedSerial::prime();
ansond 7:6fa214b41d73 111
ansond 7:6fa214b41d73 112 return ptr - (const char*)s;
sam_grove 2:7e8a450a9101 113 }
ansond 7:6fa214b41d73 114 return 0;
sam_grove 2:7e8a450a9101 115 }
sam_grove 2:7e8a450a9101 116
sam_grove 2:7e8a450a9101 117
sam_grove 0:a977d0a3d81e 118 void BufferedSerial::rxIrq(void)
sam_grove 0:a977d0a3d81e 119 {
sam_grove 3:6b76fcf27545 120 // read from the peripheral and make sure something is available
sam_grove 4:2ba4d2e1f05d 121 if(serial_readable(&_serial)) {
sam_grove 0:a977d0a3d81e 122 _rxbuf = serial_getc(&_serial); // if so load them into a buffer
sam_grove 0:a977d0a3d81e 123 }
sam_grove 4:2ba4d2e1f05d 124
sam_grove 0:a977d0a3d81e 125 return;
sam_grove 0:a977d0a3d81e 126 }
sam_grove 0:a977d0a3d81e 127
sam_grove 0:a977d0a3d81e 128 void BufferedSerial::txIrq(void)
sam_grove 0:a977d0a3d81e 129 {
sam_grove 3:6b76fcf27545 130 // see if there is room in the hardware fifo and if something is in the software fifo
sam_grove 4:2ba4d2e1f05d 131 while(serial_writable(&_serial)) {
sam_grove 4:2ba4d2e1f05d 132 if(_txbuf.available()) {
sam_grove 4:2ba4d2e1f05d 133 serial_putc(&_serial, (int)_txbuf.get());
sam_grove 4:2ba4d2e1f05d 134 } else {
sam_grove 4:2ba4d2e1f05d 135 // disable the TX interrupt when there is nothing left to send
ansond 6:8287e83943f0 136 SERIAL_BASE::attach(NULL, SERIAL_BASE::TxIrq);
sam_grove 4:2ba4d2e1f05d 137 break;
sam_grove 4:2ba4d2e1f05d 138 }
sam_grove 0:a977d0a3d81e 139 }
sam_grove 4:2ba4d2e1f05d 140
sam_grove 0:a977d0a3d81e 141 return;
sam_grove 0:a977d0a3d81e 142 }
sam_grove 0:a977d0a3d81e 143
sam_grove 1:57a11fb5d529 144 void BufferedSerial::prime(void)
sam_grove 1:57a11fb5d529 145 {
sam_grove 2:7e8a450a9101 146 // if already busy then the irq will pick this up
sam_grove 4:2ba4d2e1f05d 147 if(serial_writable(&_serial)) {
ansond 6:8287e83943f0 148 SERIAL_BASE::attach(NULL, SERIAL_BASE::TxIrq); // make sure not to cause contention in the irq
sam_grove 3:6b76fcf27545 149 BufferedSerial::txIrq(); // only write to hardware in one place
ansond 6:8287e83943f0 150 SERIAL_BASE::attach(this, &BufferedSerial::txIrq, SERIAL_BASE::TxIrq);
sam_grove 2:7e8a450a9101 151 }
sam_grove 4:2ba4d2e1f05d 152
sam_grove 1:57a11fb5d529 153 return;
sam_grove 1:57a11fb5d529 154 }
sam_grove 0:a977d0a3d81e 155
sam_grove 0:a977d0a3d81e 156