MODSERIAL with support for KL25Z + RTOS (beta, putc + puts currently)
Fork of MODSERIAL by
Revision 0:eb2522b41db8, committed 2010-11-20
- Comitter:
- AjK
- Date:
- Sat Nov 20 16:54:05 2010 +0000
- Child:
- 1:b7e435fbfe8e
- Commit message:
- 1.0
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/FLUSH.cpp Sat Nov 20 16:54:05 2010 +0000 @@ -0,0 +1,49 @@ +/* + Copyright (c) 2010 Andy Kirkham + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include "MODSERIAL.h" +#include "MACROS.h" + +namespace AjK { + +void +MODSERIAL::flushBuffer(IrqType type) +{ + volatile char c __attribute__((unused)); + volatile uint32_t iir __attribute__((unused)); + + uint32_t ier = _IER; + switch(type) { + case TxIrq: _IER &= ~(1UL << 1); break; + case RxIrq: _IER &= ~(1UL << 0); break; + } + buffer_in[type] = 0; + buffer_out[type] = 0; + buffer_count[type] = 0; + buffer_overflow[type] = 0; + _FCR = MODSERIAL_FIFO_RX_RESET | MODSERIAL_FIFO_TX_RESET; + _FCR = MODSERIAL_FIFO_ENABLE; + iir = _IIR; + _IER = ier; +} + +}; // namespace AjK ends
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/GETC.cpp Sat Nov 20 16:54:05 2010 +0000 @@ -0,0 +1,57 @@ +/* + Copyright (c) 2010 Andy Kirkham + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include "MODSERIAL.h" +#include "MACROS.h" + +namespace AjK { + +int x = 0; + +int +MODSERIAL::__getc(bool block) +{ + if (block) { while ( MODSERIAL_RX_BUFFER_EMPTY ) ; } // Blocks. + else if ( MODSERIAL_RX_BUFFER_EMPTY ) return -1; + + int c = buffer[RxIrq][buffer_out[RxIrq]]; + buffer_out[RxIrq]++; + if (buffer_out[RxIrq] >= buffer_size[RxIrq]) { + buffer_out[RxIrq] = 0; + } + + // If we have made space in the RX Buffer then copy over + // any characters in the RX FIFO that my reside there. + // Temporarily disable the RX IRQ so that we do not re-enter + // it under interrupts. + if ( ! MODSERIAL_RX_BUFFER_FULL ) { + uint32_t ier = _IER; + _IER &= ~(1UL << 0); + isr_rx(); + _IER = ier; + } + + buffer_count[RxIrq]--; + return c; +} + +}; // namespace AjK ends
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/INIT.cpp Sat Nov 20 16:54:05 2010 +0000 @@ -0,0 +1,78 @@ +/* + Copyright (c) 2010 Andy Kirkham + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include "MODSERIAL.h" +#include "MACROS.h" + +namespace AjK { + +void +MODSERIAL::init(int txSize, int rxSize) +{ + disableIrq(); + + setBase(); + + if (_base != NULL) { + buffer_size[RxIrq] = rxSize; + buffer[RxIrq] = (char *)malloc(buffer_size[RxIrq]); + buffer_in[RxIrq] = 0; + buffer_out[RxIrq] = 0; + buffer_count[RxIrq] = 0; + buffer_overflow[RxIrq] = 0; + Serial::attach(this, &MODSERIAL::isr_rx, Serial::RxIrq); + + buffer_size[TxIrq] = txSize; + buffer[TxIrq] = (char *)malloc(buffer_size[TxIrq]); + buffer_in[TxIrq] = 0; + buffer_out[TxIrq] = 0; + buffer_count[TxIrq] = 0; + buffer_overflow[TxIrq] = 0; + Serial::attach(this, &MODSERIAL::isr_tx, Serial::TxIrq); + } + + if (!txBufferSane()) { + error("Failed to allocate memory for TX buffer"); + } + + if (!rxBufferSane()) { + error("Failed to allocate memory for RX buffer"); + } + + _FCR = MODSERIAL_FIFO_ENABLE | MODSERIAL_FIFO_RX_RESET | MODSERIAL_FIFO_TX_RESET; + + enableIrq(); +} + +void +MODSERIAL::setBase(void) +{ + switch(_uidx) { + case 0: _base = LPC_UART0; break; + case 1: _base = LPC_UART1; break; + case 2: _base = LPC_UART2; break; + case 3: _base = LPC_UART3; break; + default : _base = NULL; break; + } +} + +}; // namespace AjK ends
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ISR_RX.cpp Sat Nov 20 16:54:05 2010 +0000 @@ -0,0 +1,54 @@ +/* + Copyright (c) 2010 Andy Kirkham + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include "MODSERIAL.h" +#include "MACROS.h" + +namespace AjK { + +void +MODSERIAL::isr_rx(void) +{ + if (_base) { + while( MODSERIAL_RBR_HAS_DATA ) { + rxc = (char)(_RBR & 0xFF); + if ( MODSERIAL_RX_BUFFER_FULL ) { + buffer_overflow[RxIrq] = rxc; // Oh dear, no room in buffer. + _isr[RxOvIrq].call(); + } + else { + if (buffer[RxIrq] != (char *)NULL) { + buffer[RxIrq][buffer_in[RxIrq]] = rxc; + buffer_count[RxIrq]++; + buffer_in[RxIrq]++; + if (buffer_in[RxIrq] >= buffer_size[RxIrq]) { + buffer_in[RxIrq] = 0; + } + } + _isr[RxIrq].call(); + } + } + } +} + +}; // namespace AjK ends +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ISR_TX.cpp Sat Nov 20 16:54:05 2010 +0000 @@ -0,0 +1,52 @@ +/* + Copyright (c) 2010 Andy Kirkham + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include "MODSERIAL.h" +#include "MACROS.h" +#include "IOMACROS.h" + +namespace AjK { + +void +MODSERIAL::isr_tx(void) +{ + if (_base) { + while (! MODSERIAL_TX_BUFFER_EMPTY && MODSERIAL_THR_HAS_SPACE ) { + _THR = txc = (uint8_t)(buffer[TxIrq][buffer_out[TxIrq]]); + buffer_count[TxIrq]--; + buffer_out[TxIrq]++; + if (buffer_out[TxIrq] >= buffer_size[TxIrq]) { + buffer_out[TxIrq] = 0; + } + _isr[TxIrq].call(); + } + + if ( MODSERIAL_TX_BUFFER_EMPTY && MODSERIAL_THR_HAS_SPACE ) { + _IER = 1; + _isr[TxEmpty].call(); + } + } +} + +}; // namespace AjK ends + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MACROS.h Sat Nov 20 16:54:05 2010 +0000 @@ -0,0 +1,61 @@ +/* + Copyright (c) 2010 Andy Kirkham + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#ifndef MODSERIAL_MACROS_H +#define MODSERIAL_MACROS_H + +#define MODSERIAL_RBR 0x00 +#define MODSERIAL_THR 0x00 +#define MODSERIAL_DLL 0x00 +#define MODSERIAL_IER 0x04 +#define MODSERIAL_DML 0x04 +#define MODSERIAL_IIR 0x08 +#define MODSERIAL_FCR 0x08 +#define MODSERIAL_LCR 0x0C +#define MODSERIAL_LSR 0x14 +#define MODSERIAL_SCR 0x1C +#define MODSERIAL_ACR 0x20 +#define MODSERIAL_ICR 0x24 +#define MODSERIAL_FDR 0x28 +#define MODSERIAL_TER 0x30 + +#define MODSERIAL_FIFO_ENABLE 1 +#define MODSERIAL_FIFO_RX_RESET 2 +#define MODSERIAL_FIFO_TX_RESET 4 + +#define _RBR *((char *)_base+MODSERIAL_RBR) +#define _THR *((char *)_base+MODSERIAL_THR) +#define _IIR *((char *)_base+MODSERIAL_IIR) +#define _IER *((char *)_base+MODSERIAL_IER) +#define _LSR *((char *)_base+MODSERIAL_LSR) +#define _FCR *((char *)_base+MODSERIAL_FCR) + +#define MODSERIAL_TX_BUFFER_EMPTY (buffer_count[TxIrq]==0) +#define MODSERIAL_RX_BUFFER_EMPTY (buffer_count[RxIrq]==0) +#define MODSERIAL_TX_BUFFER_FULL (buffer_count[TxIrq]==buffer_size[TxIrq]) +#define MODSERIAL_RX_BUFFER_FULL (buffer_count[RxIrq]==buffer_size[RxIrq]) + +#define MODSERIAL_THR_HAS_SPACE (int)_LSR&(1UL<<5) +#define MODSERIAL_TEMT_IS_EMPTY (int)_LSR&(1UL<<6) +#define MODSERIAL_RBR_HAS_DATA (int)_LSR&0x1 + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MODSERIAL.cpp Sat Nov 20 16:54:05 2010 +0000 @@ -0,0 +1,96 @@ +/* + Copyright (c) 2010 Andy Kirkham + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include "MODSERIAL.h" +#include "MACROS.h" + +namespace AjK { + +MODSERIAL::MODSERIAL(PinName tx, PinName rx, const char *name) : Serial(tx, rx, name) +{ + init(MODSERIAL_DEFAULT_TX_BUFFER_SIZE, MODSERIAL_DEFAULT_RX_BUFFER_SIZE); +} + +MODSERIAL::MODSERIAL(PinName tx, PinName rx, int bufferSize, const char *name) : Serial(tx, rx, name) +{ + init(bufferSize, bufferSize); +} + +MODSERIAL::MODSERIAL(PinName tx, PinName rx, int txSize, int rxSize, const char *name) : Serial(tx, rx, name) +{ + init(txSize, rxSize); +} + +MODSERIAL::~MODSERIAL() +{ + disableIrq(); + if (buffer[0] != NULL) free((char *)buffer[0]); + if (buffer[1] != NULL) free((char *)buffer[1]); +} + +bool +MODSERIAL::txBufferFull(void) +{ + return MODSERIAL_TX_BUFFER_FULL; +} + +bool +MODSERIAL::rxBufferFull(void) +{ + return MODSERIAL_RX_BUFFER_FULL; +} + +bool +MODSERIAL::txBufferEmpty(void) +{ + return MODSERIAL_TX_BUFFER_EMPTY; +} + +bool +MODSERIAL::rxBufferEmpty(void) +{ + return MODSERIAL_RX_BUFFER_EMPTY; +} + +void +MODSERIAL::disableIrq(void) +{ + switch(_uidx) { + case 0: NVIC_DisableIRQ(UART0_IRQn); break; + case 1: NVIC_DisableIRQ(UART1_IRQn); break; + case 2: NVIC_DisableIRQ(UART2_IRQn); break; + case 3: NVIC_DisableIRQ(UART3_IRQn); break; + } +} + +void +MODSERIAL::enableIrq(void) +{ + switch(_uidx) { + case 0: NVIC_EnableIRQ(UART0_IRQn); break; + case 1: NVIC_EnableIRQ(UART1_IRQn); break; + case 2: NVIC_EnableIRQ(UART2_IRQn); break; + case 3: NVIC_EnableIRQ(UART3_IRQn); break; + } +} + +}; // namespace AjK ends
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MODSERIAL.h Sat Nov 20 16:54:05 2010 +0000 @@ -0,0 +1,752 @@ +/* + Copyright (c) 2010 Andy Kirkham + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#ifndef MODSERIAL_H +#define MODSERIAL_H + +/** @defgroup API The MODSERIAL API */ +/** @defgroup MISC Misc MODSERIAL functions */ +/** @defgroup INTERNALS MODSERIAL Internals */ + +#ifndef MODSERIAL_DEFAULT_RX_BUFFER_SIZE +#define MODSERIAL_DEFAULT_RX_BUFFER_SIZE 256 +#endif + +#ifndef MODSERIAL_DEFAULT_TX_BUFFER_SIZE +#define MODSERIAL_DEFAULT_TX_BUFFER_SIZE 256 +#endif + +#include "mbed.h" + +namespace AjK { + +/** + * @author Andy Kirkham + * @see http://mbed.org/cookbook/MODSERIAL + * @see http://mbed.org/handbook/Serial + * @see example.cpp + * @see API + * + * <b>MODSERIAL</b> extends the Mbed library <a href="/handbook/Serial">Serial</a> to provide fully buffered + * TX and RX streams. Buffer length is fully customisable. + * + * Before using MODSERIAL users should be familar with Mbed's standard <a href="/handbook/Serial">Serial</a> + * library object. MODSERIAL is a direct "drop in" replacement for <a href="/handbook/Serial">Serial</a>. Where + * previously Serial was used, MODSERIAL can be used as adirect replacement instantly offering standard + * TX and RX buffering. By default, both TX and RX buffers are 256 bytes in length. + * + * @image html /media/uploads/mbedofficial/serial_interfaces.png + * + * Standard example: + * @code + * #include "mbed.h" + * #include "MODSERIAL.h" + * + * MODSERIAL pc(USBTX, USBRX); // tx, rx + * + * int main() { + * pc.printf("Hello World!"); + * while(1) { + * pc.putc(pc.getc() + 1); + * } + * } + * @endcode + * + * Example with alternate buffer length: + * @code + * #include "mbed.h" + * #include "MODSERIAL.h" + * + * // Make TX and RX buffers 512byes in length + * MODSERIAL pc(USBTX, USBRX, 512); // tx, rx + * + * int main() { + * pc.printf("Hello World!"); + * while(1) { + * pc.putc(pc.getc() + 1); + * } + * } + * @endcode + * + * Example with alternate buffer length: + * @code + * #include "mbed.h" + * #include "MODSERIAL.h" + * + * // Make TX 1024bytes and RX 512byes in length + * MODSERIAL pc(USBTX, USBRX, 1024, 512); // tx, rx + * + * int main() { + * pc.printf("Hello World!"); + * while(1) { + * pc.putc(pc.getc() + 1); + * } + * } + * @endcode + */ +class MODSERIAL : public Serial +{ +public: + + //! A copy of the Serial parity enum + /** @see http://mbed.org/projects/libraries/api/mbed/trunk/Serial#Serial.format */ + enum Parity { + None = 0 + , Odd + , Even + , Forced1 + , Forced0 + }; + + //! A copy of the Serial IrqType enum + enum IrqType { + RxIrq = 0 + , TxIrq + , RxOvIrq + , TxOvIrq + , TxEmpty + }; + + //! Non-blocking functions return code. + enum Result { + Ok = 0 /*!< Ok. */ + , NoMemory = -1 /*!< Memory allocation failed. */ + , NoChar = -1 /*!< No character in buffer. */ + , BufferOversize = -2 /*!< Oversized buffer. */ + }; + + /** + * The MODSERIAL constructor is used to initialise the serial object. + * + * @param tx PinName of the TX pin. + * @param rx PinName of the TX pin. + * @param name An option name for RPC usage. + */ + MODSERIAL(PinName tx, PinName rx, const char *name = NULL); + + /** + * The MODSERIAL constructor is used to initialise the serial object. + * + * @param tx PinName of the TX pin. + * @param rx PinName of the TX pin. + * @param bufferSize Integer of the TX and RX buffer sizes. + * @param name An option name for RPC usage. + */ + MODSERIAL(PinName tx, PinName rx, int bufferSize, const char *name = NULL); + + /** + * The MODSERIAL constructor is used to initialise the serial object. + * + * @param tx PinName of the TX pin. + * @param rx PinName of the TX pin. + * @param txBufferSize Integer of the TX buffer sizes. + * @param rxBufferSize Integer of the RX buffer sizes. + * @param name An option name for RPC usage. + */ + MODSERIAL(PinName tx, PinName rx, int txBufferSize, int rxBufferSize, const char *name = NULL); + + virtual ~MODSERIAL(); + + /** + * Function: attach + * + * The Mbed standard <a href="/handbook/Serial">Serial</a> library object allows an interrupt callback + * to be made when a byte is received by the TX or RX UART hardware. MODSERIAL traps these interrupts + * to enable it's buffering system. However, after the byte has been received/sent under interrupt caontrol, + * MODSERIAL can callback a user function as a notification of the interrupt. Note, user code should not + * directly interact with teh Uart hardware, MODSERIAL does that, instead, MODSERIAL API functions should + * be used. + * + * <b>Note</b>, a character is written out then, if there is room in the TX FIFO and the TX buffer is empty, + * putc() will put the character directly into THR (the output holding register). If the TX FIFO is full and + * cannot accept the character, it is placed into the TX output buffer. The TX interrupts are then enabled + * so that when teh TX FIFO empties, the TX buffer is then transferred to the THR FIFO. The TxIrq will ONLY + * be activated when this transfer of a character from BUFFER to THR FIFO takes place. If your character + * throughput is not high bandwidth, then the 16 byte TX FIFO may be enough and the TX output buffer may + * never come into play. + * + * @code + * #include "mbed.h" + * #include "MODSERIAL.h" + * + * DigitalOut led1(LED1); + * DigitalOut led2(LED2); + * DigitalOut led3(LED3); + * + * // To test, connect p9 to p10 as a loopback. + * MODSERIAL pc(p9, p10); + * + * // This function is called when a character goes into the TX buffer. + * void txCallback(void) { + * led2 = !led2; + * } + * + * // This function is called when a character goes into the RX buffer. + * void rxCallback(void) { + * led3 = !led3; + * } + * + * int main() { + * pc.baud(115200); + * pc.attach(&txCallback, MODSERIAL::TxIrq); + * pc.attach(&rxCallback, MODSERIAL::RxIrq); + * + * while(1) { + * led1 = !led1; + * wait(0.5); + * pc.putc('A'); + * wait(0.5); + * } + * ] + * @endcode + * + * @ingroup API + * @param fptr A pointer to a void function, or 0 to set as none + * @param type Which serial interrupt to attach the member function to (Seriall::RxIrq for receive, TxIrq for transmit buffer empty) + */ + void attach(void (*fptr)(void), IrqType type = RxIrq) { _isr[type].attach(fptr); } + + /** + * Function: attach + * + * The Mbed standard <a href="/handbook/Serial">Serial</a> library object allows an interrupt callback + * to be made when a byte is received by the TX or RX UART hardware. MODSERIAL traps these interrupts + * to enable it's buffering system. However, after the byte has been received/sent under interrupt caontrol, + * MODSERIAL can callback a user function as a notification of the interrupt. Note, user code should not + * directly interact with teh Uart hardware, MODSERIAL does that, instead, MODSERIAL API functions should + * be used. + * + * <b>Note</b>, a character is written out then, if there is room in the TX FIFO and the TX buffer is empty, + * putc() will put the character directly into THR (the output holding register). If the TX FIFO is full and + * cannot accept the character, it is placed into the TX output buffer. The TX interrupts are then enabled + * so that when teh TX FIFO empties, the TX buffer is then transferred to the THR FIFO. The TxIrq will ONLY + * be activated when this transfer of a character from BUFFER to THR FIFO takes place. If your character + * throughput is not high bandwidth, then the 16 byte TX FIFO may be enough and the TX output buffer may + * never come into play. + * + * @code + * #include "mbed.h" + * #include "MODSERIAL.h" + * + * DigitalOut led1(LED1); + * DigitalOut led2(LED2); + * DigitalOut led3(LED3); + * + * // To test, connect p9 to p10 as a loopback. + * MODSERIAL pc(p9, p10); + * + * class Foo { + * public: + * // This method is called when a character goes into the TX buffer. + * void txCallback(void) { led2 = !led2; } + * + * // This method is called when a character goes into the RX buffer. + * void rxCallback(void) { led3 = !led3; } + * }; + * + * Foo foo; + * + * int main() { + * pc.baud(115200); + * pc.attach(&foo, &Foo::txCallback, MODSERIAL::TxIrq); + * pc.attach(&foo, &Foo::rxCallback, MODSERIAL::RxIrq); + * + * while(1) { + * led1 = !led1; + * wait(0.5); + * pc.putc('A'); + * wait(0.5); + * } + * ] + * @endcode + * + * @ingroup API + * @param tptr A pointer to the object to call the member function on + * @param mptr A pointer to the member function to be called + * @param type Which serial interrupt to attach the member function to (Seriall::RxIrq for receive, TxIrq for transmit buffer empty) + */ + template<typename T> + void attach(T* tptr, void (T::*mptr)(void), IrqType type = RxIrq) { + if((mptr != NULL) && (tptr != NULL)) { + _isr[type].attach(tptr, mptr); + } + } + + /** + * @see attach + * @ingroup API + */ + void connect(void (*fptr)(void), IrqType type = RxIrq) { _isr[RxIrq].attach(fptr); } + + /** + * @see attach + * @ingroup API + */ + template<typename T> + void connect(T* tptr, void (T::*mptr)(void), IrqType type = RxIrq) { + if((mptr != NULL) && (tptr != NULL)) { + _isr[type].attach(tptr, mptr); + } + } + + /** + * Function: writeable + * + * Determine if there is space available to write a byte + * + * @ingroup API + * @return 1 if there is space to write a character, else 0 + */ + int writeable() { return txBufferFull() ? 0 : 1; } + + /** + * Function: readable + * + * Determine if there is a byte available to read + * + * @ingroup API + * @return 1 if there is a character available to read, else 0 + */ + int readable() { return rxBufferEmpty() ? 0 : 1; } + + /** + * Function: txBufferSane + * + * Determine if the TX buffer has been initialized. + * + * @ingroup API + * @return true if the buffer is initialized, else false + */ + bool txBufferSane(void) { return buffer[TxIrq] != (char *)NULL ? true : false; } + + /** + * Function: rxBufferSane + * + * Determine if the RX buffer has been initialized. + * + * @ingroup API + * @return true if the buffer is initialized, else false + */ + bool rxBufferSane(void) { return buffer[TxIrq] != (char *)NULL ? true : false; } + + /** + * Function: txBufferGetCount + * + * Returns how many bytes are in the TX buffer + * + * @ingroup API + * @return The number of bytes in the TX buffer + */ + int txBufferGetCount(void) { return buffer_count[TxIrq]; } + + /** + * Function: rxBufferGetCount + * + * Returns how many bytes are in the RX buffer + * + * @ingroup API + * @return The number of bytes in the RX buffer + */ + int rxBufferGetCount(void) { return buffer_count[RxIrq]; } + + /** + * Function: txBufferGetSize + * + * Returns the current size of the TX buffer + * + * @ingroup API + * @return The length iof the TX buffer in bytes + */ + int txBufferGetSize(int size) { return buffer_size[TxIrq]; } + + /** + * Function: rxBufferGetSize + * + * Returns the current size of the RX buffer + * + * @ingroup API + * @return The length iof the RX buffer in bytes + */ + int rxBufferGetSize(int size) { return buffer_size[RxIrq]; } + + /** + * Function: txBufferFull + * + * Is the TX buffer full? + * + * @ingroup API + * @return true if the TX buffer is full, otherwise false + */ + bool txBufferFull(void); + + /** + * Function: rxBufferFull + * + * Is the RX buffer full? + * + * @ingroup API + * @return true if the RX buffer is full, otherwise false + */ + bool rxBufferFull(void); + + /** + * Function: txBufferEmpty + * + * Is the TX buffer empty? + * + * @ingroup API + * @return true if the TX buffer is empty, otherwise false + */ + bool txBufferEmpty(void); + + /** + * Function: rxBufferEmpty + * + * Is the RX buffer empty? + * + * @ingroup API + * @return true if the RX buffer is empty, otherwise false + */ + bool rxBufferEmpty(void); + + /** + * Function: txBufferSetSize + * + * Change the TX buffer size. + * + * @see Result + * @ingroup API + * @param size The new TX buffer size in bytes. + * @param m Perform a memory sanity check. Errs the Mbed if memory alloc fails. + * @return Result Ok on success. + */ + int txBufferSetSize(int size, bool m) { return resizeBuffer(size, TxIrq, m); } + + /** + * Function: rxBufferSetSize + * + * Change the RX buffer size. + * + * @see Result + * @ingroup API + * @param size The new RX buffer size in bytes. + * @param m Perform a memory sanity check. Errs the Mbed if memory alloc fails. + * @return Result Ok on success. + */ + int rxBufferSetSize(int size, bool m) { return resizeBuffer(size, RxIrq, m); } + + /** + * Function: txBufferSetSize + * + * Change the TX buffer size. + * Always performs a memory sanity check, halting the Mbed on failure. + * + * @see Result + * @ingroup API + * @param size The new TX buffer size in bytes. + * @return Result Ok on success. + */ + int txBufferSetSize(int size) { return resizeBuffer(size, TxIrq, true); } + + /** + * Function: rxBufferSetSize + * + * Change the RX buffer size. + * Always performs a memory sanity check, halting the Mbed on failure. + * + * @see Result + * @ingroup API + * @param size The new RX buffer size in bytes. + * @return Result Ok on success. + */ + int rxBufferSetSize(int size) { return resizeBuffer(size, RxIrq, true); } + + /** + * Function: txBufferFlush + * + * Remove all bytes from the TX buffer. + * @ingroup API + */ + void txBufferFlush(void) { flushBuffer(TxIrq); } + + /** + * Function: rxBufferFlush + * + * Remove all bytes from the RX buffer. + * @ingroup API + */ + void rxBufferFlush(void) { flushBuffer(RxIrq); } + + /** + * Function: getcNb + * + * Like getc() but is non-blocking. If no bytes are in the RX buffer this + * function returns Result::NoChar (-1) + * + * @ingroup API + * @return A byte from the RX buffer or Result::NoChar (-1) if bufer empty. + */ + int getcNb() { return __getc(false); } + + /** + * Function: getc + * + * Overloaded version of Serial::getc() + * + * This function blocks (if the RX buffer is empty the function will wait for a + * character to arrive and then return that character). + * + * @ingroup API + * @return A byte from the RX buffer + */ + int getc() { return __getc(true); } + + /** + * Function: txGetLastChar + * + * Rteurn teh last byte to pass through the TX interrupt handler. + * + * @ingroup MISC + * @return The byte + */ + char txGetLastChar(void) { return txc; } + + /** + * Function: rxGetLastChar + * + * Return the last byte to pass through the RX interrupt handler. + * + * @ingroup MISC + * @return The byte + */ + char rxGetLastChar(void) { return rxc; } + + /** + * Function: txIsBusy + * + * If teh Uart is still actively sending characters this + * function will return true. + * + * @ingroup API + * @return bool + */ + bool txIsBusy(void) { return (_LSR & (3UL << 5) == 0) ? true : false; } + + #if 0 // Inhereted from Serial/Stream, for documentation only + /** + * Function: putc + * + * Write a character + * Inhereted from Serial/Stream + * + * @see http://mbed.org/projects/libraries/api/mbed/trunk/Serial#Serial.putc + * @ingroup API + * @param c The character to write to the serial port + */ + int putc(int c); + #endif + + #if 0 // Inhereted from Serial/Stream, for documentation only + /** + * Function: printf + * + * Write a formated string + * Inhereted from Serial/Stream + * + * @see http://mbed.org/projects/libraries/api/mbed/trunk/Serial#Serial.printf + * @ingroup API + * @param format A printf-style format string, followed by the variables to use in formating the string. + */ + int printf(const char* format, ...); + #endif + + #if 0 // Inhereted from Serial/Stream, for documentation only + /** + * Function: scanf + * + * Read a formated string + * Inhereted from Serial/Stream + * + * @see http://mbed.org/projects/libraries/api/mbed/trunk/Serial#Serial.scanf + * @ingroup API + * @param format - A scanf-style format string, followed by the pointers to variables to store the results. + */ + int scanf(const char* format, ...); + #endif + +protected: + + /** + * A pointer to the UART peripheral base address being used. + * @ingroup INTERNALS + */ + void *_base; + + /** + * The last byte to pass through the TX IRQ handler. + * @ingroup INTERNALS + */ + volatile char txc; + + /** + * The last byte to pass through the RX IRQ handler. + * @ingroup INTERNALS + */ + volatile char rxc; + + /** + * Pointers to teh TX and RX buffers. + * @ingroup INTERNALS + */ + volatile char *buffer[2]; + + /** + * Buffer in pointers. + * @ingroup INTERNALS + */ + volatile int buffer_in[2]; + + /** + * Buffer out pointers. + * @ingroup INTERNALS + */ + volatile int buffer_out[2]; + + /** + * Buffer lengths. + * @ingroup INTERNALS + */ + volatile int buffer_size[2]; + + /** + * Buffer content counters. + * @ingroup INTERNALS + */ + volatile int buffer_count[2]; + + /** + * Buffer overflow. + * @ingroup INTERNALS + */ + volatile int buffer_overflow[2]; + + /** + * Callback system. + * @ingroup INTERNALS + */ + FunctionPointer _isr[5]; + + /** + * TX Interrupt Service Routine. + * @ingroup INTERNALS + */ + void isr_tx(void); + + /** + * RX Interrupt Service Routine. + * @ingroup INTERNALS + */ + void isr_rx(void); + + /** + * Disable the interrupts for this Uart. + * @ingroup INTERNALS + */ + void disableIrq(void); + + /** + * Enable the interrupts for this Uart. + * @ingroup INTERNALS + */ + void enableIrq(void); + + /** + * Get a character from the RX buffer + * @ingroup INTERNALS + * @param bool True to block (wait for input) + * @return A byte from the buffer. + */ + int __getc(bool); + + /** + * Put a character from the TX buffer + * @ingroup INTERNALS + * @param bool True to block (wait for space in teh TX buffer if full) + * @return 0 on success + */ + int __putc(int c, bool); + + /** + * Function: _putc + * Overloaded virtual function. + */ + virtual int _putc(int c) { return __putc(c, true); } + + /** + * Function: _getc + * Overloaded virtual function. + */ + virtual int _getc() { return __getc(true); } + + /** + * Set's the Uart base pointer. + * @ingroup INTERNALS + */ + void setBase(void); + + /** + * Function: init + * Initialize the MODSERIAL object + * @ingroup INTERNALS + */ + void init(int txSize, int rxSize); + + /** + * Function: flushBuffer + * @ingroup INTERNALS + */ + void flushBuffer(IrqType type); + + /** + * Function: resizeBuffer + * @ingroup INTERNALS + */ + int resizeBuffer(int size, IrqType type = RxIrq, bool memory_check = true); + + /** + * Function: downSizeBuffer + * @ingroup INTERNALS + */ + int downSizeBuffer(int size, IrqType type, bool memory_check); + + /** + * Function: upSizeBuffer + * @ingroup INTERNALS + */ + int upSizeBuffer(int size, IrqType type, bool memory_check); +}; + +}; // namespace AjK ends + +using namespace AjK; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/PUTC.cpp Sat Nov 20 16:54:05 2010 +0000 @@ -0,0 +1,56 @@ +/* + Copyright (c) 2010 Andy Kirkham + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include "MODSERIAL.h" +#include "MACROS.h" + +namespace AjK { + +int +MODSERIAL::__putc(int c, bool block) { + uint32_t lsr = (uint32_t)*((char *)_base + MODSERIAL_LSR); + + if (lsr & 0x20 && MODSERIAL_TX_BUFFER_EMPTY ) { + _THR = (uint32_t)c; + } + else { + if (buffer[TxIrq] != (char *)NULL) { + if (block) while ( MODSERIAL_TX_BUFFER_FULL ) ; // Blocks! + else if( MODSERIAL_TX_BUFFER_FULL ) { + buffer_overflow[TxIrq] = c; // Oh dear, no room in buffer. + _isr[TxOvIrq].call(); + return -1; + } + buffer[TxIrq][buffer_in[TxIrq]] = c; + buffer_count[TxIrq]++; + buffer_in[TxIrq]++; + if (buffer_in[TxIrq] >= buffer_size[TxIrq]) { + buffer_in[TxIrq] = 0; + } + _IER |= 0x2; + } + } + + return 0; +} + +}; // namespace AjK ends
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/RESIZE.cpp Sat Nov 20 16:54:05 2010 +0000 @@ -0,0 +1,123 @@ +/* + Copyright (c) 2010 Andy Kirkham + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include "MODSERIAL.h" +#include "MACROS.h" + +namespace AjK { + +int +MODSERIAL::resizeBuffer(int size, IrqType type, bool memory_check) +{ + int rval = Ok; + + // If the requested size is the same as the current size there's nothing to do, + // just continue to use the same buffer as it's fine as it is. + if (buffer_size[type] == size) return rval; + + // Make sure the ISR cannot use the buffers while we are manipulating them. + disableIrq(); + + // If the requested buffer size is larger than the current size, + // attempt to create a new buffer and use it. + if (buffer_size[type] < size) { + rval = upSizeBuffer(size, type, memory_check); + } + else if (buffer_size[type] > size) { + rval = downSizeBuffer(size, type, memory_check); + } + + // Start the ISR system again with the new buffers. + enableIrq(); + + return rval; +} + +int +MODSERIAL::downSizeBuffer(int size, IrqType type, bool memory_check) +{ + if (size >= buffer_count[type]) { + return BufferOversize; + } + + char *s = (char *)malloc(size); + + if (s == (char *)NULL) { + if (memory_check) { + error("Failed to allocate memory for %s buffer", type == TxIrq ? "TX" : "RX"); + } + return NoMemory; + } + + int c, new_in = 0; + + do { + c = __getc(false); + if (c != -1) s[new_in++] = (char)c; + if (new_in >= size) new_in = 0; + } + while (c != -1); + + free((char *)buffer[type]); + buffer[type] = s; + buffer_in[type] = new_in; + buffer_out[type] = 0; + return Ok; +} + +int +MODSERIAL::upSizeBuffer(int size, IrqType type, bool memory_check) +{ + char *s = (char *)malloc(size); + + if (s == (char *)NULL) { + if (memory_check) { + error("Failed to allocate memory for %s buffer", type == TxIrq ? "TX" : "RX"); + } + return NoMemory; + } + + if (buffer_count[type] == 0) { // Current buffer empty? + free((char *)buffer[type]); + buffer[type] = s; + buffer_in[type] = 0; + buffer_out[type] = 0; + } + else { // Copy the current contents into the new buffer. + int c, new_in = 0; + do { + c = __getc(false); + if (c != -1) s[new_in++] = (char)c; + if (new_in >= size) new_in = 0; // Shouldn't happen, but be sure. + } + while (c != -1); + free((char *)buffer[type]); + buffer[type] = s; + buffer_in[type] = new_in; + buffer_out[type] = 0; + } + + buffer_size[type] = size; + return Ok; +} + +}; // namespace AjK ends
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/example.cpp Sat Nov 20 16:54:05 2010 +0000 @@ -0,0 +1,120 @@ +#ifdef COMPILE_EXAMPLE_CODE_MODSERIAL + +/* + * To run this test program, link p9 to p10 so the Serial loops + * back and receives characters it sends. + */ + +#include "mbed.h" +#include "MODSERIAL.h" + +DigitalOut led1(LED1); +DigitalOut led2(LED2); +DigitalOut led3(LED3); +DigitalOut led4(LED4); + +MODSERIAL pc(USBTX, USBRX); + +/* + * As experiement, you can define MODSERIAL as show here and see what + * effects it has on the LEDs. + * + * MODSERIAL uart(TX_PIN, RX_PIN, 512); + * With this, the 512 characters sent can straight into the buffer + * vary quickly. This means LED1 is only on briefly as the TX buffer + * fills. + * + * MODSERIAL uart(TX_PIN, RX_PIN, 32); + * With this, the buffer is smaller than the default 256 bytes and + * therefore LED1 stays on much longer while the system waits for + * room in the TX buffer. + */ +MODSERIAL uart(TX_PIN, RX_PIN); + +// This function is called when a character goes from the TX buffer +// to the Uart THR FIFO register. +void txCallback(void) { + led2 = !led2; +} + +// This function is called when TX buffer goes empty +void txEmpty(void) { + led2 = 0; + pc.puts(" Done. "); +} + +// This function is called when a character goes into the RX buffer. +void rxCallback(void) { + led3 = !led3; + pc.putc(uart.getc()); +} + +int main() { + int c = 'A'; + + // Ensure the baud rate for the PC "USB" serial is much + // higher than "uart" baud rate below. + pc.baud(115200); + + // Use a deliberatly slow baud to fill up the TX buffer + uart.baud(1200); + + uart.attach(&txCallback, MODSERIAL::TxIrq); + uart.attach(&rxCallback, MODSERIAL::RxIrq); + uart.attach(&txEmpty, MODSERIAL::TxEmpty); + + // Loop sending characters. We send 512 + // which is twice the default TX/RX buffer size. + + led1 = 1; // Show start of sending with LED1. + + for (int loop = 0; loop < 512; loop++) { + uart.printf("%c", c); + c++; + if (c > 'Z') c = 'A'; + } + + led1 = 0; // Show the end of sending by switching off LED1. + + // End program. Flash LED4. Notice how LED 2 and 3 continue + // to flash for a short period while the interrupt system + // continues to send the characters left in the TX buffer. + + while(1) { + led4 = !led4; + wait(0.25); + } +} + +/* + * Notes. Here is the sort of output you can expect on your PC/Mac/Linux host + * machine that is connected to the "pc" USB serial port. + * + * ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUV + * WXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQR + * STUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMN + * OPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJ + * KLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEF + * GHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZAB + * CDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQ Done. R + * + * Of interest is that last "R" character after the system has said "Done." + * This comes from the fact that the TxEmpty callback is made when the TX buffer + * becomes empty. MODSERIAL makes use of the fact that the Uarts built into the + * LPC17xx device use a 16 byte FIFO on both RX and TX channels. This means that + * when the TxEmpty callback is made, the TX buffer is empty, but that just means + * the "last few characters" were written to the TX FIFO. So although the TX + * buffer has gone empty, the Uart's transmit system is still sending any remaining + * characters from it's TX FIFO. If you want to be truely sure all the characters + * you have sent have left the Mbed then call txIsBusy(); This function will + * return true if characters are still being sent. If it returns false after + * the Tx buffer is empty then all your characters have been sent. + * + * In a similar way, when characters are received into the RX FIFO, the entire + * FIFO contents is moved to the RX buffer, assuming there is room left in the + * RX buffer. If there is not, any remaining characters are left in the RX FIFO + * and will be moved to the RX buffer on the next interrupt or when the running + * program removes a character(s) from the RX buffer with the getc() method. + */ + +#endif