This is the SerialBuffered class, which wraps Serial and adds interrupt-powered buffered reading (so it will catch inbound data even when your app is busy doing something else) and simple read timeouts. There's a tiny demo app in there too.
Revision 0:b55ca3bb8017, committed 2009-11-18
- Comitter:
- jarkman
- Date:
- Wed Nov 18 21:27:15 2009 +0000
- Commit message:
Changed in this revision
diff -r 000000000000 -r b55ca3bb8017 SerialBuffered.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SerialBuffered.cpp Wed Nov 18 21:27:15 2009 +0000 @@ -0,0 +1,108 @@ + +#include "mbed.h" +#include "SerialBuffered.h" + +extern Serial loggerSerial; + +SerialBuffered::SerialBuffered( size_t bufferSize, PinName tx, PinName rx ) : Serial( tx, rx ) +{ + m_buffSize = 0; + m_contentStart = 0; + m_contentEnd = 0; + m_timeout = 1.0; + + + attach( this, &SerialBuffered::handleInterrupt ); + + m_buff = (uint8_t *) malloc( bufferSize ); + if( m_buff == NULL ) + { + //loggerSerial.printf("SerialBuffered - failed to alloc buffer size %d\r\n", (int) bufferSize ); + } + else + { + m_buffSize = bufferSize; + } +} + + +SerialBuffered::~SerialBuffered() +{ + if( m_buff ) + free( m_buff ); +} + +void SerialBuffered::setTimeout( float seconds ) +{ + m_timeout = seconds; +} + +size_t SerialBuffered::readBytes( uint8_t *bytes, size_t requested ) +{ + int i = 0; + + for( ; i < requested; ) + { + int c = getc(); + if( c < 0 ) + break; + bytes[i] = c; + i++; + } + + return i; + +} + + +int SerialBuffered::getc() +{ + m_timer.reset(); + m_timer.start(); + while( m_contentStart == m_contentEnd ) + { + + + wait_ms( 1 ); + if( m_timeout > 0 && m_timer.read() > m_timeout ) + return EOF; + } + + m_timer.stop(); + + uint8_t result = m_buff[m_contentStart++]; + m_contentStart = m_contentStart % m_buffSize; + + + return result; +} + + +int SerialBuffered::readable() +{ + return m_contentStart != m_contentEnd ; +} + +void SerialBuffered::handleInterrupt() +{ + + while( Serial::readable()) + { + if( m_contentStart == (m_contentEnd +1) % m_buffSize) + { + loggerSerial.printf("SerialBuffered - buffer overrun, data lost!\r\n" ); + Serial::getc(); + + } + else + { + + m_buff[ m_contentEnd ++ ] = Serial::getc(); + m_contentEnd = m_contentEnd % m_buffSize; + + + + } + } +} +
diff -r 000000000000 -r b55ca3bb8017 SerialBuffered.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SerialBuffered.h Wed Nov 18 21:27:15 2009 +0000 @@ -0,0 +1,39 @@ +#pragma once + +// This is a buffered serial reading class, using the serial interrupt introduced in mbed library version 18 on 17/11/09 + +// In the simplest case, construct it with a buffer size at least equal to the largest message you +// expect your program to receive in one go. + +class SerialBuffered : public Serial +{ +public: + SerialBuffered( size_t bufferSize, PinName tx, PinName rx ); + virtual ~SerialBuffered(); + + int getc(); // will block till the next character turns up, or return -1 if there is a timeout + + int readable(); // returns 1 if there is a character available to read, 0 otherwise + + void setTimeout( float seconds ); // maximum time in seconds that getc() should block + // while waiting for a character + // Pass -1 to disable the timeout. + + size_t readBytes( uint8_t *bytes, size_t requested ); // read requested bytes into a buffer, + // return number actually read, + // which may be less than requested if there has been a timeout + + +private: + + void handleInterrupt(); + + + uint8_t *m_buff; // points at a circular buffer, containing data from m_contentStart, for m_contentSize bytes, wrapping when you get to the end + uint16_t m_contentStart; // index of first bytes of content + uint16_t m_contentEnd; // index of bytes after last byte of content + uint16_t m_buffSize; + float m_timeout; + Timer m_timer; + +}; \ No newline at end of file
diff -r 000000000000 -r b55ca3bb8017 main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Wed Nov 18 21:27:15 2009 +0000 @@ -0,0 +1,67 @@ +#include "mbed.h" +#include "SerialBuffered.h" + +Serial loggerSerial(USBTX, USBRX); + +// run this with p13 joined to p14 to test the SerialBuffered class + +int main() { + + SerialBuffered *b = new SerialBuffered( 1001, p13, p14); + + b->baud( 112500 ); + b->setTimeout( 0.1 ); + + // write a bufferful + for( int i = 0; i < 1000; i ++ ) + { + b->putc( i % 0xff ); + } + + // and check it all arrived + for( int i = 0; i < 1000; i ++ ) + { + uint8_t j = b->getc(); + if( j != i % 0xff ) + { + loggerSerial.printf("Bad byte %x at %x\r\n", j, i ); + break; + } + + } + + // write another bufferful + for( int i = 0; i < 1000; i ++ ) + { + b->putc( i % 0xff ); + } + + // and check it arrived too, to confirm the circular buffer is working + for( int i = 0; i < 1000; i ++ ) + { + uint8_t j = b->getc(); + if( j != i % 0xff ) + { + loggerSerial.printf("Bad byte %x at %x\r\n", j, i ); + break; + } + } + + // write another bufferful, deliberately short + for( int i = 0; i < 999; i ++ ) + { + b->putc( i % 0xff ); + } + + + // and read it back with readBytes + b->setTimeout( 5 ); // set a long timeout so we can see we are waiting for it + + + uint8_t *buff = (uint8_t*) malloc( 1000 ); + int nRead = b->readBytes( buff, 1000 ); + + loggerSerial.printf("readBytes got %d\r\n", nRead ); + + loggerSerial.printf("Done\r\n"); +}
diff -r 000000000000 -r b55ca3bb8017 mbed.bld --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Wed Nov 18 21:27:15 2009 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/32af5db564d4