• Main Page
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

/home/jgoppert/Projects/ap/libraries/FastSerial/FastSerial.cpp

Go to the documentation of this file.
00001 // -*- Mode: C++; c-basic-offset: 8; indent-tabs-mode: nil -*-
00002 //
00003 // Interrupt-driven serial transmit/receive library.
00004 //
00005 //      Copyright (c) 2010 Michael Smith. All rights reserved.
00006 //
00007 // Receive and baudrate calculations derived from the Arduino 
00008 // HardwareSerial driver:
00009 //
00010 //      Copyright (c) 2006 Nicholas Zambetti.  All right reserved.
00011 //
00012 // Transmit algorithm inspired by work:
00013 //
00014 //      Code Jose Julio and Jordi Munoz. DIYDrones.com
00015 //
00016 //      This library is free software; you can redistribute it and/or
00017 //      modify it under the terms of the GNU Lesser General Public
00018 //      License as published by the Free Software Foundation; either
00019 //      version 2.1 of the License, or (at your option) any later version.
00020 //
00021 //      This library is distributed in the hope that it will be useful,
00022 //      but WITHOUT ANY WARRANTY; without even the implied warranty of
00023 //      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00024 //      Lesser General Public License for more details.
00025 //
00026 //      You should have received a copy of the GNU Lesser General Public
00027 //      License along with this library; if not, write to the Free Software
00028 //      Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00029 //
00030 
00031 
00032 //#include "../AP_Common/AP_Common.h"
00033 #include "FastSerial.h"
00034 #include "WProgram.h"
00035 
00036 #if   defined(UDR3)
00037 # define FS_MAX_PORTS   4
00038 #elif defined(UDR2)
00039 # define FS_MAX_PORTS   3
00040 #elif defined(UDR1)
00041 # define FS_MAX_PORTS   2
00042 #else
00043 # define FS_MAX_PORTS   1
00044 #endif
00045 
00046 FastSerial::Buffer      __FastSerial__rxBuffer[FS_MAX_PORTS];
00047 FastSerial::Buffer      __FastSerial__txBuffer[FS_MAX_PORTS];
00048 
00049 // Default buffer sizes
00050 #define RX_BUFFER_SIZE  128
00051 #define TX_BUFFER_SIZE  64
00052 #define BUFFER_MAX      512
00053 
00054 // Constructor /////////////////////////////////////////////////////////////////
00055 
00056 FastSerial::FastSerial(const uint8_t portNumber,
00057                        volatile uint8_t *ubrrh,
00058                        volatile uint8_t *ubrrl,
00059                        volatile uint8_t *ucsra,
00060                        volatile uint8_t *ucsrb,
00061                        const uint8_t u2x,
00062                        const uint8_t portEnableBits,
00063                        const uint8_t portTxBits)
00064 {
00065         _ubrrh = ubrrh;
00066         _ubrrl = ubrrl;
00067         _ucsra = ucsra;
00068         _ucsrb = ucsrb;
00069         _u2x   = u2x;
00070         _portEnableBits = portEnableBits;
00071         _portTxBits     = portTxBits;
00072 
00073         // init buffers
00074         _rxBuffer = &__FastSerial__rxBuffer[portNumber];
00075         _txBuffer->head = _txBuffer->tail = 0;
00076         _txBuffer = &__FastSerial__txBuffer[portNumber];
00077         _rxBuffer->head = _rxBuffer->tail = 0;
00078 }
00079 
00080 // Public Methods //////////////////////////////////////////////////////////////
00081 
00082 void FastSerial::begin(long baud)
00083 {
00084         unsigned int    rxb, txb;
00085 
00086         // If we are re-configuring an already-open port, preserve the
00087         // existing buffer sizes.
00088         if (_open) {
00089                 rxb = _rxBuffer->mask + 1;
00090                 txb = _txBuffer->mask + 1;
00091         } else {
00092                 rxb = RX_BUFFER_SIZE;
00093                 txb = TX_BUFFER_SIZE;
00094         }
00095 
00096         begin(baud, RX_BUFFER_SIZE, TX_BUFFER_SIZE);
00097 }
00098 
00099 void FastSerial::begin(long baud, unsigned int rxSpace, unsigned int txSpace)
00100 {
00101         uint16_t        ubrr;
00102         bool            use_u2x = false;
00103         int             ureg, u2;
00104         long            breg, b2, dreg, d2;
00105        
00106         // if we are currently open, close and restart
00107         if (_open)
00108                 end();
00109 
00110         // allocate buffers
00111         if (!_allocBuffer(_rxBuffer, rxSpace ? : RX_BUFFER_SIZE) ||
00112             !_allocBuffer(_txBuffer, txSpace ? : TX_BUFFER_SIZE)) {
00113                 end();
00114                 return;                 // couldn't allocate buffers - fatal
00115         }
00116         _open = true;
00117 
00118         // U2X mode is needed for bitrates higher than (F_CPU / 16)
00119         if (baud > F_CPU / 16) {
00120                 use_u2x = true;
00121                 ubrr = F_CPU / (8 * baud) - 1;
00122         } else {
00123                 // Determine whether u2x mode would give a closer
00124                 // approximation of the desired speed.
00125     
00126                 // ubrr for non-2x mode, corresponding baudrate and delta
00127                 ureg = F_CPU / 16 / baud - 1;
00128                 breg = F_CPU / 16 / (ureg + 1);
00129                 dreg = abs(baud - breg);
00130                 
00131                 // ubrr for 2x mode, corresponding bitrate and delta
00132                 u2   = F_CPU / 8 / baud - 1;
00133                 b2   = F_CPU / 8 / (u2 + 1); 
00134                 d2   = abs(baud - b2);
00135 
00136                 // Pick the setting that gives the smallest rate
00137                 // error, preferring non-u2x mode if the delta is
00138                 // identical.
00139                 if (dreg <= d2) {
00140                         ubrr = ureg;
00141                 } else {
00142                         ubrr = u2;
00143                         use_u2x = true;
00144                 }                
00145         }
00146   
00147         *_ucsra = use_u2x ? _BV(_u2x) : 0;
00148         *_ubrrh = ubrr >> 8;
00149         *_ubrrl = ubrr;
00150         *_ucsrb |= _portEnableBits;
00151 }
00152 
00153 void FastSerial::end()
00154 {
00155         *_ucsrb &= ~(_portEnableBits | _portTxBits);
00156 
00157         _freeBuffer(_rxBuffer);
00158         _freeBuffer(_txBuffer);
00159         _open = false;
00160 }
00161 
00162 int
00163 FastSerial::available(void)
00164 {
00165         if (!_open)
00166                 return(-1);
00167         return((_rxBuffer->head - _rxBuffer->tail) & _rxBuffer->mask);
00168 }
00169 
00170 int
00171 FastSerial::read(void)
00172 {
00173         uint8_t         c;
00174 
00175         // if the head and tail are equal, the buffer is empty
00176         if (!_open || (_rxBuffer->head == _rxBuffer->tail))
00177                 return(-1);
00178 
00179         // pull character from tail
00180         c = _rxBuffer->bytes[_rxBuffer->tail];
00181         _rxBuffer->tail = (_rxBuffer->tail + 1) & _rxBuffer->mask;
00182 
00183         return(c);
00184 }
00185 
00186 int
00187 FastSerial::peek(void)
00188 {
00189 
00190         // if the head and tail are equal, the buffer is empty
00191         if (!_open || (_rxBuffer->head == _rxBuffer->tail))
00192                 return(-1);
00193 
00194         // pull character from tail
00195         return(_rxBuffer->bytes[_rxBuffer->tail]);
00196 }
00197 
00198 
00199 void
00200 FastSerial::flush(void)
00201 {
00202         // don't reverse this or there may be problems if the RX interrupt
00203         // occurs after reading the value of _rxBuffer->head but before writing
00204         // the value to _rxBuffer->tail; the previous value of head
00205         // may be written to tail, making it appear as if the buffer
00206         // don't reverse this or there may be problems if the RX interrupt
00207         // occurs after reading the value of head but before writing
00208         // the value to tail; the previous value of rx_buffer_head
00209         // may be written to tail, making it appear as if the buffer
00210         // were full, not empty.
00211         _rxBuffer->head = _rxBuffer->tail;
00212 
00213         // don't reverse this or there may be problems if the TX interrupt
00214         // occurs after reading the value of _txBuffer->tail but before writing
00215         // the value to _txBuffer->head.
00216         _txBuffer->tail = _rxBuffer->head;
00217 }
00218 
00219 void
00220 FastSerial::write(uint8_t c)
00221 {
00222         int16_t         i;
00223 
00224         if (!_open)                     // drop bytes if not open
00225                 return;
00226 
00227         // wait for room in the tx buffer
00228         i = (_txBuffer->head + 1) & _txBuffer->mask;
00229         while (i == _txBuffer->tail)
00230                 ;
00231 
00232         // add byte to the buffer
00233         _txBuffer->bytes[_txBuffer->head] = c;
00234         _txBuffer->head = i;
00235 
00236         // enable the data-ready interrupt, as it may be off if the buffer is empty
00237         *_ucsrb |= _portTxBits;
00238 }
00239 
00240 // Buffer management ///////////////////////////////////////////////////////////
00241 
00242 bool
00243 FastSerial::_allocBuffer(Buffer *buffer, unsigned int size)
00244 {
00245         uint8_t shift;
00246 
00247         // init buffer state
00248         buffer->head = buffer->tail = 0;
00249 
00250         // Compute the power of 2 greater or equal to the requested buffer size
00251         // and then a mask to simplify wrapping operations.  Using __builtin_clz
00252         // would seem to make sense, but it uses a 256(!) byte table.
00253         // Note that we ignore requests for more than BUFFER_MAX space.
00254         for (shift = 1; (1U << shift) < min(BUFFER_MAX, size); shift++)
00255                 ;
00256         buffer->mask = (1 << shift) - 1;
00257 
00258         // allocate memory for the buffer - if this fails, we fail
00259         buffer->bytes = (uint8_t *)malloc(buffer->mask + 1);
00260 
00261         return(buffer->bytes != NULL);
00262 }
00263 
00264 void
00265 FastSerial::_freeBuffer(Buffer *buffer)
00266 {
00267         buffer->head = buffer->tail = 0;
00268         buffer->mask = 0;
00269         if (NULL != buffer->bytes) {
00270                 free(buffer->bytes);
00271                 buffer->bytes = NULL;
00272         }
00273 }
00274 

Generated for ArduPilot Libraries by doxygen