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

Fork of BufferedSerial by Sam Grove

Committer:
sam_grove
Date:
Mon Dec 30 18:16:39 2013 +0000
Revision:
4:2ba4d2e1f05d
Parent:
3:6b76fcf27545
Child:
6:8287e83943f0
Disable TX IRQ when nothing is left in the buffer (FRDM support). Tested example program with KL46Z, KL25Z and LPC11U24. LPC1768 doesn't work. Need to investigate.

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)
sam_grove 0:a977d0a3d81e 27 : Serial(tx, rx, name)
sam_grove 0:a977d0a3d81e 28 {
sam_grove 0:a977d0a3d81e 29 Serial::attach(this, &BufferedSerial::rxIrq, Serial::RxIrq);
sam_grove 4:2ba4d2e1f05d 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 {
sam_grove 0:a977d0a3d81e 36 Serial::attach(NULL, Serial::RxIrq);
sam_grove 0:a977d0a3d81e 37 Serial::attach(NULL, Serial::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 {
sam_grove 2:7e8a450a9101 67 const char* ptr = s;
sam_grove 4:2ba4d2e1f05d 68
sam_grove 4:2ba4d2e1f05d 69 while(*(ptr) != 0) {
sam_grove 2:7e8a450a9101 70 _txbuf = *(ptr++);
sam_grove 0:a977d0a3d81e 71 }
sam_grove 2:7e8a450a9101 72 _txbuf = '\n'; // done per puts definition
sam_grove 1:57a11fb5d529 73 BufferedSerial::prime();
sam_grove 4:2ba4d2e1f05d 74
sam_grove 2:7e8a450a9101 75 return (ptr - s) + 1;
sam_grove 0:a977d0a3d81e 76 }
sam_grove 0:a977d0a3d81e 77
sam_grove 0:a977d0a3d81e 78 int BufferedSerial::printf(const char* format, ...)
sam_grove 0:a977d0a3d81e 79 {
sam_grove 0:a977d0a3d81e 80 char buf[256] = {0};
sam_grove 0:a977d0a3d81e 81 int r = 0;
sam_grove 4:2ba4d2e1f05d 82
sam_grove 0:a977d0a3d81e 83 va_list arg;
sam_grove 0:a977d0a3d81e 84 va_start(arg, format);
sam_grove 0:a977d0a3d81e 85 r = vsprintf(buf, format, arg);
sam_grove 0:a977d0a3d81e 86 // this may not hit the heap but should alert the user anyways
sam_grove 4:2ba4d2e1f05d 87 if(r > sizeof(buf)) {
sam_grove 4:2ba4d2e1f05d 88 error("%s %d buffer overwrite!\n", __FILE__, __LINE__);
sam_grove 0:a977d0a3d81e 89 }
sam_grove 4:2ba4d2e1f05d 90 va_end(arg);
sam_grove 2:7e8a450a9101 91 r = BufferedSerial::write(buf, r);
sam_grove 4:2ba4d2e1f05d 92
sam_grove 0:a977d0a3d81e 93 return r;
sam_grove 0:a977d0a3d81e 94 }
sam_grove 0:a977d0a3d81e 95
sam_grove 2:7e8a450a9101 96 ssize_t BufferedSerial::write(const void *s, size_t length)
sam_grove 2:7e8a450a9101 97 {
sam_grove 2:7e8a450a9101 98 const char* ptr = (const char*)s;
sam_grove 2:7e8a450a9101 99 const char* end = ptr + length;
sam_grove 4:2ba4d2e1f05d 100
sam_grove 4:2ba4d2e1f05d 101 while (ptr != end) {
sam_grove 2:7e8a450a9101 102 _txbuf = *(ptr++);
sam_grove 2:7e8a450a9101 103 }
sam_grove 2:7e8a450a9101 104 BufferedSerial::prime();
sam_grove 4:2ba4d2e1f05d 105
sam_grove 4:2ba4d2e1f05d 106 return ptr - (const char*)s;
sam_grove 2:7e8a450a9101 107 }
sam_grove 2:7e8a450a9101 108
sam_grove 2:7e8a450a9101 109
sam_grove 0:a977d0a3d81e 110 void BufferedSerial::rxIrq(void)
sam_grove 0:a977d0a3d81e 111 {
sam_grove 3:6b76fcf27545 112 // read from the peripheral and make sure something is available
sam_grove 4:2ba4d2e1f05d 113 if(serial_readable(&_serial)) {
sam_grove 0:a977d0a3d81e 114 _rxbuf = serial_getc(&_serial); // if so load them into a buffer
sam_grove 0:a977d0a3d81e 115 }
sam_grove 4:2ba4d2e1f05d 116
sam_grove 0:a977d0a3d81e 117 return;
sam_grove 0:a977d0a3d81e 118 }
sam_grove 0:a977d0a3d81e 119
sam_grove 0:a977d0a3d81e 120 void BufferedSerial::txIrq(void)
sam_grove 0:a977d0a3d81e 121 {
sam_grove 3:6b76fcf27545 122 // see if there is room in the hardware fifo and if something is in the software fifo
sam_grove 4:2ba4d2e1f05d 123 while(serial_writable(&_serial)) {
sam_grove 4:2ba4d2e1f05d 124 if(_txbuf.available()) {
sam_grove 4:2ba4d2e1f05d 125 serial_putc(&_serial, (int)_txbuf.get());
sam_grove 4:2ba4d2e1f05d 126 } else {
sam_grove 4:2ba4d2e1f05d 127 // disable the TX interrupt when there is nothing left to send
sam_grove 4:2ba4d2e1f05d 128 Serial::attach(NULL, Serial::TxIrq);
sam_grove 4:2ba4d2e1f05d 129 break;
sam_grove 4:2ba4d2e1f05d 130 }
sam_grove 0:a977d0a3d81e 131 }
sam_grove 4:2ba4d2e1f05d 132
sam_grove 0:a977d0a3d81e 133 return;
sam_grove 0:a977d0a3d81e 134 }
sam_grove 0:a977d0a3d81e 135
sam_grove 1:57a11fb5d529 136 void BufferedSerial::prime(void)
sam_grove 1:57a11fb5d529 137 {
sam_grove 2:7e8a450a9101 138 // if already busy then the irq will pick this up
sam_grove 4:2ba4d2e1f05d 139 if(serial_writable(&_serial)) {
sam_grove 4:2ba4d2e1f05d 140 Serial::attach(NULL, Serial::TxIrq); // make sure not to cause contention in the irq
sam_grove 3:6b76fcf27545 141 BufferedSerial::txIrq(); // only write to hardware in one place
sam_grove 3:6b76fcf27545 142 Serial::attach(this, &BufferedSerial::txIrq, Serial::TxIrq);
sam_grove 2:7e8a450a9101 143 }
sam_grove 4:2ba4d2e1f05d 144
sam_grove 1:57a11fb5d529 145 return;
sam_grove 1:57a11fb5d529 146 }
sam_grove 0:a977d0a3d81e 147
sam_grove 0:a977d0a3d81e 148