buffered_serial.cpp

00001 /*
00002  * buffered_serial.h
00003  *
00004  * Implements a variable size buffer for received serial data
00005  *
00006  * Author: Nick Young (9/26/10)
00007  * Portions of code by: Richard Sewel (11/17/09)
00008  *
00009  */
00010 
00011 #include "mbed.h"
00012 #include "buffered_serial.h"
00013 
00014 /**
00015  * Constructs a BufferedSerial object
00016  *
00017  * Creates a BufferedSerial with default settings of 9600 8N1.
00018  * Valid (TX/RX) pairs are {(USBTX/USBRX), (9/10), (13/14), (28/27)}.
00019  * Valid baud rates are {110, 300, 600, 1200, 2400, 4800, 9600, 14400,
00020  * 19200, 38400, 57600, 115200, 230400, 460800, 921600}.
00021  * Maximum buffer size is 256 bytes.
00022  *
00023  * @param PinName tx
00024  *   The transmit out (TXO) pin for this serial port
00025  * @param PinName rx
00026  *   The receive in (RXI) pin for this serial port
00027  * @param uint8_t buffer_size
00028  *   The desired size of the circular buffer
00029  */
00030 BufferedSerial::BufferedSerial(PinName tx, PinName rx, uint8_t buffer_size) :
00031   Serial(tx,  rx),
00032   has_callback_(false)
00033 {
00034   buffer_size_ = 0;
00035   content_start_ = 0;
00036   content_end_ = 0;
00037   available_bytes_ = 0;
00038     
00039   attach(this, &BufferedSerial::handleInterrupt);
00040     
00041   buffer_ = (uint8_t *) malloc(buffer_size + 1);
00042   if(buffer_ != NULL)
00043   {
00044     buffer_size_ = buffer_size + 1;
00045   }
00046 }
00047 
00048 BufferedSerial::~BufferedSerial()
00049 {
00050   if(buffer_)
00051     free(buffer_);
00052 }
00053 
00054 /**
00055  * Checks if there are bytes ready to be read
00056  *
00057  * @return bool
00058  *  true    if there are bytes ready to be read
00059  *  false   otherwise
00060  */
00061 bool BufferedSerial::readable()
00062 {
00063   return (content_start_ != content_end_);
00064 }
00065 
00066 /**
00067  * Checks how many bytes are ready to be read
00068  *
00069  * @return uint8_t
00070  *  The number of bytes ready to be read
00071  */
00072 uint8_t BufferedSerial::availableBytes()
00073 {
00074   return available_bytes_;
00075 }
00076 
00077 /**
00078  * Reads the next available byte without removing it from the buffer
00079  *
00080  * Reads a single byte from the front of the circular buffer (without
00081  * removing it from the buffer and returns its value.  This method
00082  * will block until a single byte is available.
00083  *
00084  * @return uint8_t
00085  *  The frontmost byte in the circular receive buffer
00086  */
00087 uint8_t BufferedSerial::peek()
00088 {
00089   //block until a byte is available
00090   while(content_start_ == content_end_) { wait_us(1); }
00091     
00092   return buffer_[content_start_];
00093 }
00094 
00095 /**
00096  * Reads the next available received byte
00097  *
00098  * Removes a single byte from the front of the circular buffer and
00099  * returns its value.  This method will block until a single byte
00100  * is available.
00101  *
00102  * @return uint8_t
00103  *  The frontmost byte in the circular receive buffer
00104  */
00105 uint8_t BufferedSerial::getc()
00106 {
00107   //block until a byte is available
00108   while(content_start_ == content_end_) { wait_us(1); }
00109 
00110   //read the byte and remove it from the buffer
00111   uint8_t result = buffer_[content_start_++];
00112   content_start_ =  content_start_ % buffer_size_;
00113   available_bytes_--;
00114    
00115   return result;
00116 }
00117 
00118 /**
00119  * Reads the next four bytes into a long data type
00120  * 
00121  * Reads the next four bytes and stores them into a signed long data
00122  * type.  This method will block until four bytes are available. The
00123  * first byte is considered to be the MSB, and the last byte is
00124  * considered to be the LSB.
00125  *
00126  * @return long
00127  *  The front most four bytes in the buffer as a long
00128  */
00129 long BufferedSerial::readLong()
00130 {
00131   long result = (getc() << 24) |
00132                 (getc() << 16) |
00133                 (getc() << 8 ) |
00134                 (getc()      );
00135   return result;
00136 }
00137 
00138 /**
00139  * Reads requested_bytes bytes into a provided buffer
00140  *
00141  * Reads a specified number of bytes into a caller-supplied buffer.
00142  * This method will block until requested_bytes bytes are available.
00143  * The reads are performed byte-wise and will remove the byte from
00144  * the circular buffer as it is added to the destination buffer.
00145  *
00146  * @param uint8_t* bytes
00147  *   The pre-allocated destination buffer
00148  * @param size_t requested_bytes
00149  *   The number of bytes to move into the buffer
00150  */
00151 void BufferedSerial::readBytes(uint8_t *bytes, size_t requested_bytes)
00152 {
00153     for (size_t index = 0; index < requested_bytes; index++)
00154       bytes[index] = getc();        
00155 }
00156 
00157 /**
00158  * Flushes the receive buffer
00159  */
00160 void BufferedSerial::flushBuffer()
00161 {
00162   content_end_ = content_start_;
00163   available_bytes_ = 0;
00164 }
00165 
00166 void BufferedSerial::writeLong(long data)
00167 {
00168   putc((data >> 24) & 0xFF);
00169   putc((data >> 16) & 0xFF);
00170   putc((data >>  8) & 0xFF);
00171   putc((data      ) & 0xFF);
00172 }
00173 
00174 /**
00175  * Serial receive interrupt handler
00176  *
00177  * On receipt of data, this method is run to empty
00178  * the hardware buffer and fill the circular buffer
00179  * with the received data.  If the circular buffer is
00180  * full, incoming data will be dropped.
00181  */
00182 void BufferedSerial::handleInterrupt()
00183 {
00184     while(Serial::readable())
00185     {
00186         if (content_start_ == (content_end_ + 1) % buffer_size_)
00187             Serial::getc();
00188         else
00189         {
00190             buffer_[content_end_++] = Serial::getc();
00191             content_end_ = content_end_ % buffer_size_;
00192             available_bytes_++;
00193         }
00194         //if the buffer is full, then callback the object
00195         if (has_callback_ && (content_start_ == (content_end_ + 1) % buffer_size_) )
00196             callback_.call();
00197     }
00198 }
Generated on Sun May 8 08:41:32 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3