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:
sam_grove
Date:
Wed Feb 20 01:29:28 2019 +0000
Revision:
13:c17c532bc4f8
Parent:
11:779304f9c5d2
Eliminate warnings with Mbed 2 version 131 and Mbed OS 5.2.0 and newer. Added error messages to help if incompatible versions are identified (best effort)

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
ansond 10:9ee15ae3d1a3 26 BufferedSerial::BufferedSerial(PinName tx, PinName rx, uint32_t buf_size, uint32_t tx_multiple, const char* name)
sam_grove 11:779304f9c5d2 27 : RawSerial(tx, rx) , _rxbuf(buf_size), _txbuf((uint32_t)(tx_multiple*buf_size))
sam_grove 0:a977d0a3d81e 28 {
sam_grove 13:c17c532bc4f8 29 RawSerial::attach(callback(this, &BufferedSerial::rxIrq), Serial::RxIrq);
ansond 10:9ee15ae3d1a3 30 this->_buf_size = buf_size;
ansond 10:9ee15ae3d1a3 31 this->_tx_multiple = tx_multiple;
sam_grove 0:a977d0a3d81e 32 return;
sam_grove 0:a977d0a3d81e 33 }
sam_grove 0:a977d0a3d81e 34
sam_grove 0:a977d0a3d81e 35 BufferedSerial::~BufferedSerial(void)
sam_grove 0:a977d0a3d81e 36 {
sam_grove 11:779304f9c5d2 37 RawSerial::attach(NULL, RawSerial::RxIrq);
sam_grove 11:779304f9c5d2 38 RawSerial::attach(NULL, RawSerial::TxIrq);
sam_grove 4:2ba4d2e1f05d 39
sam_grove 0:a977d0a3d81e 40 return;
sam_grove 0:a977d0a3d81e 41 }
sam_grove 0:a977d0a3d81e 42
sam_grove 0:a977d0a3d81e 43 int BufferedSerial::readable(void)
sam_grove 0:a977d0a3d81e 44 {
sam_grove 0:a977d0a3d81e 45 return _rxbuf.available(); // note: look if things are in the buffer
sam_grove 0:a977d0a3d81e 46 }
sam_grove 0:a977d0a3d81e 47
sam_grove 0:a977d0a3d81e 48 int BufferedSerial::writeable(void)
sam_grove 0:a977d0a3d81e 49 {
sam_grove 0:a977d0a3d81e 50 return 1; // buffer allows overwriting by design, always true
sam_grove 0:a977d0a3d81e 51 }
sam_grove 0:a977d0a3d81e 52
sam_grove 0:a977d0a3d81e 53 int BufferedSerial::getc(void)
sam_grove 0:a977d0a3d81e 54 {
sam_grove 3:6b76fcf27545 55 return _rxbuf;
sam_grove 0:a977d0a3d81e 56 }
sam_grove 0:a977d0a3d81e 57
sam_grove 0:a977d0a3d81e 58 int BufferedSerial::putc(int c)
sam_grove 0:a977d0a3d81e 59 {
sam_grove 0:a977d0a3d81e 60 _txbuf = (char)c;
sam_grove 1:57a11fb5d529 61 BufferedSerial::prime();
sam_grove 4:2ba4d2e1f05d 62
sam_grove 0:a977d0a3d81e 63 return c;
sam_grove 0:a977d0a3d81e 64 }
sam_grove 0:a977d0a3d81e 65
sam_grove 0:a977d0a3d81e 66 int BufferedSerial::puts(const char *s)
sam_grove 0:a977d0a3d81e 67 {
ansond 7:6fa214b41d73 68 if (s != NULL) {
ansond 7:6fa214b41d73 69 const char* ptr = s;
ansond 7:6fa214b41d73 70
ansond 7:6fa214b41d73 71 while(*(ptr) != 0) {
ansond 7:6fa214b41d73 72 _txbuf = *(ptr++);
ansond 7:6fa214b41d73 73 }
ansond 7:6fa214b41d73 74 _txbuf = '\n'; // done per puts definition
ansond 7:6fa214b41d73 75 BufferedSerial::prime();
ansond 7:6fa214b41d73 76
ansond 7:6fa214b41d73 77 return (ptr - s) + 1;
sam_grove 0:a977d0a3d81e 78 }
ansond 7:6fa214b41d73 79 return 0;
sam_grove 0:a977d0a3d81e 80 }
sam_grove 0:a977d0a3d81e 81
sam_grove 0:a977d0a3d81e 82 int BufferedSerial::printf(const char* format, ...)
sam_grove 0:a977d0a3d81e 83 {
ansond 10:9ee15ae3d1a3 84 char buffer[this->_buf_size];
ansond 10:9ee15ae3d1a3 85 memset(buffer,0,this->_buf_size);
sam_grove 0:a977d0a3d81e 86 int r = 0;
sam_grove 4:2ba4d2e1f05d 87
sam_grove 0:a977d0a3d81e 88 va_list arg;
sam_grove 0:a977d0a3d81e 89 va_start(arg, format);
ansond 10:9ee15ae3d1a3 90 r = vsprintf(buffer, format, arg);
sam_grove 0:a977d0a3d81e 91 // this may not hit the heap but should alert the user anyways
ansond 10:9ee15ae3d1a3 92 if(r > this->_buf_size) {
ansond 10:9ee15ae3d1a3 93 error("%s %d buffer overwrite (max_buf_size: %d exceeded: %d)!\r\n", __FILE__, __LINE__,this->_buf_size,r);
ansond 7:6fa214b41d73 94 va_end(arg);
ansond 7:6fa214b41d73 95 return 0;
sam_grove 0:a977d0a3d81e 96 }
sam_grove 4:2ba4d2e1f05d 97 va_end(arg);
ansond 10:9ee15ae3d1a3 98 r = BufferedSerial::write(buffer, r);
sam_grove 4:2ba4d2e1f05d 99
sam_grove 0:a977d0a3d81e 100 return r;
sam_grove 0:a977d0a3d81e 101 }
sam_grove 0:a977d0a3d81e 102
sam_grove 2:7e8a450a9101 103 ssize_t BufferedSerial::write(const void *s, size_t length)
sam_grove 2:7e8a450a9101 104 {
ansond 7:6fa214b41d73 105 if (s != NULL && length > 0) {
ansond 7:6fa214b41d73 106 const char* ptr = (const char*)s;
ansond 7:6fa214b41d73 107 const char* end = ptr + length;
ansond 7:6fa214b41d73 108
ansond 7:6fa214b41d73 109 while (ptr != end) {
ansond 7:6fa214b41d73 110 _txbuf = *(ptr++);
ansond 7:6fa214b41d73 111 }
ansond 7:6fa214b41d73 112 BufferedSerial::prime();
ansond 7:6fa214b41d73 113
ansond 7:6fa214b41d73 114 return ptr - (const char*)s;
sam_grove 2:7e8a450a9101 115 }
ansond 7:6fa214b41d73 116 return 0;
sam_grove 2:7e8a450a9101 117 }
sam_grove 2:7e8a450a9101 118
sam_grove 2:7e8a450a9101 119
sam_grove 0:a977d0a3d81e 120 void BufferedSerial::rxIrq(void)
sam_grove 0:a977d0a3d81e 121 {
sam_grove 3:6b76fcf27545 122 // read from the peripheral and make sure something is available
sam_grove 4:2ba4d2e1f05d 123 if(serial_readable(&_serial)) {
sam_grove 0:a977d0a3d81e 124 _rxbuf = serial_getc(&_serial); // if so load them into a buffer
sam_grove 0:a977d0a3d81e 125 }
sam_grove 4:2ba4d2e1f05d 126
sam_grove 0:a977d0a3d81e 127 return;
sam_grove 0:a977d0a3d81e 128 }
sam_grove 0:a977d0a3d81e 129
sam_grove 0:a977d0a3d81e 130 void BufferedSerial::txIrq(void)
sam_grove 0:a977d0a3d81e 131 {
sam_grove 3:6b76fcf27545 132 // see if there is room in the hardware fifo and if something is in the software fifo
sam_grove 4:2ba4d2e1f05d 133 while(serial_writable(&_serial)) {
sam_grove 4:2ba4d2e1f05d 134 if(_txbuf.available()) {
sam_grove 4:2ba4d2e1f05d 135 serial_putc(&_serial, (int)_txbuf.get());
sam_grove 4:2ba4d2e1f05d 136 } else {
sam_grove 4:2ba4d2e1f05d 137 // disable the TX interrupt when there is nothing left to send
sam_grove 11:779304f9c5d2 138 RawSerial::attach(NULL, RawSerial::TxIrq);
sam_grove 4:2ba4d2e1f05d 139 break;
sam_grove 4:2ba4d2e1f05d 140 }
sam_grove 0:a977d0a3d81e 141 }
sam_grove 4:2ba4d2e1f05d 142
sam_grove 0:a977d0a3d81e 143 return;
sam_grove 0:a977d0a3d81e 144 }
sam_grove 0:a977d0a3d81e 145
sam_grove 1:57a11fb5d529 146 void BufferedSerial::prime(void)
sam_grove 1:57a11fb5d529 147 {
sam_grove 2:7e8a450a9101 148 // if already busy then the irq will pick this up
sam_grove 4:2ba4d2e1f05d 149 if(serial_writable(&_serial)) {
sam_grove 11:779304f9c5d2 150 RawSerial::attach(NULL, RawSerial::TxIrq); // make sure not to cause contention in the irq
sam_grove 3:6b76fcf27545 151 BufferedSerial::txIrq(); // only write to hardware in one place
sam_grove 13:c17c532bc4f8 152 RawSerial::attach(callback(this, &BufferedSerial::txIrq), RawSerial::TxIrq);
sam_grove 2:7e8a450a9101 153 }
sam_grove 4:2ba4d2e1f05d 154
sam_grove 1:57a11fb5d529 155 return;
sam_grove 1:57a11fb5d529 156 }
sam_grove 0:a977d0a3d81e 157
sam_grove 0:a977d0a3d81e 158