MHVLib
20111011
An efficiency oriented runtime library for AVR microcontrollers
|
00001 /* 00002 * Copyright (c) 2011, Make, Hack, Void Inc 00003 * All rights reserved. 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions are met: 00007 * * Redistributions of source code must retain the above copyright 00008 * notice, this list of conditions and the following disclaimer. 00009 * * Redistributions in binary form must reproduce the above copyright 00010 * notice, this list of conditions and the following disclaimer in the 00011 * documentation and/or other materials provided with the distribution. 00012 * * Neither the name of the Make, Hack, Void nor the 00013 * names of its contributors may be used to endorse or promote products 00014 * derived from this software without specific prior written permission. 00015 * 00016 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 00017 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 00018 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 00019 * DISCLAIMED. IN NO EVENT SHALL MAKE, HACK, VOID BE LIABLE FOR ANY 00020 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 00021 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00022 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 00023 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00024 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00025 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00026 */ 00027 00028 00029 #include <stdio.h> 00030 #include <avr/sfr_defs.h> 00031 #include <avr/pgmspace.h> 00032 #include <stdlib.h> 00033 #include <string.h> 00034 #include <inttypes.h> 00035 00036 #include "MHV_HardwareSerial.h" 00037 00054 MHV_HardwareSerial::MHV_HardwareSerial(MHV_RingBuffer *rxBuffer, MHV_RingBuffer *txBuffer, 00055 volatile uint16_t *ubrr, volatile uint8_t *ucsra, volatile uint8_t *ucsrb, 00056 volatile uint8_t *udr, uint8_t rxen, uint8_t txen, uint8_t rxcie, 00057 uint8_t txcie, uint8_t udre, uint8_t u2x, unsigned long baud) : 00058 MHV_Device_TX(txBuffer), MHV_Device_RX(rxBuffer) { 00059 _echo = false; 00060 _ubrr = ubrr; 00061 _ucsra = ucsra; 00062 _ucsrb = ucsrb; 00063 _udr = udr; 00064 _rxen = rxen; 00065 _txen = txen; 00066 _rxcie = rxcie; 00067 _txcie = txcie; 00068 _udre = udre; 00069 _u2x = u2x; 00070 _tx = NULL; 00071 00072 setSpeed(baud); 00073 } 00074 00078 void MHV_HardwareSerial::rx() { 00079 char c = *_udr; 00080 _rxBuffer->append(c); 00081 00082 if (_echo && ((*_ucsra) & (1 << _udre))) { 00083 *_udr = c; 00084 } 00085 } 00086 00090 void MHV_HardwareSerial::tx() { 00091 int c = nextCharacter(); 00092 00093 if (-1 == c) { 00094 // Nothing more to send, disable the TX interrupt 00095 _tx = NULL; 00096 *_ucsrb &= ~_BV( _txcie); 00097 return; 00098 } 00099 00100 *_udr = (char)c; 00101 } 00102 00106 void MHV_HardwareSerial::runTxBuffers() { 00107 int c = nextCharacter(); 00108 if (-1 == c) { 00109 // This should never happen 00110 return; 00111 } 00112 00113 // Enable tx interrupt 00114 *_ucsrb |= _BV( _txcie); 00115 00116 // If the UART isn't already sending data, start sending 00117 while (!((*_ucsra) & (1 << _udre))) {} 00118 00119 *_udr = (char)c; 00120 } 00121 00126 void MHV_HardwareSerial::setSpeed(unsigned long baud) { 00127 /* Use U2X if the requested baud rate is higher than (F_CPU/16), 00128 * otherwise use whatever has the least error 00129 */ 00130 if (baud > F_CPU / 16 || 00131 abs((int)(255-((F_CPU/(8*(((F_CPU/4/baud-1)/2)+1))*255)/baud))) < abs((int)(255-((F_CPU/(16*(((F_CPU/8/baud-1)/2)+1))*255)/baud)))) { 00132 *_ucsra = _BV(_u2x); 00133 *_ubrr = (uint16_t)(F_CPU / 4 / baud - 1) / 2; 00134 } else { 00135 *_ucsra = 0; 00136 *_ubrr = (uint16_t)(F_CPU / 8 / baud - 1) / 2; 00137 } 00138 00139 *_ucsrb |= _BV( _rxen) | _BV( _txen) | _BV( _rxcie); 00140 } 00141 00145 void MHV_HardwareSerial::end() { 00146 *_ucsrb &= ~_BV( _rxen) & ~_BV( _txen) & ~_BV( _rxcie) & ~_BV( _txcie); 00147 } 00148 00155 void MHV_HardwareSerial::echo(bool echoOn) { 00156 _echo = echoOn; 00157 } 00158 00164 bool MHV_HardwareSerial::canSendBusy() { 00165 return ((NULL == _tx) && ((*_ucsra) & (1 << _udre))); 00166 } 00167 00173 void MHV_HardwareSerial::busyWrite(char c) { 00174 while (!canSendBusy()) {}; 00175 *_ucsrb &= ~_BV( _txcie); 00176 00177 while (!((*_ucsra) & (1 << _udre))) {} 00178 00179 *_udr = c; 00180 } 00181 00187 void MHV_HardwareSerial::busyWrite_P(PGM_P buffer) { 00188 const char *p; 00189 00190 while (!canSendBusy()) {}; 00191 *_ucsrb &= ~_BV( _txcie); 00192 00193 p = buffer; 00194 char c = pgm_read_byte(p++); 00195 while (c != '\0') { 00196 while (!((*_ucsra) & (1 << _udre))) {} 00197 00198 *_udr = c; 00199 c = pgm_read_byte(p++); 00200 } 00201 } 00202 00203 00209 void MHV_HardwareSerial::busyWrite(const char *buffer) { 00210 const char *p; 00211 00212 while (!canSendBusy()) {}; 00213 *_ucsrb &= ~_BV( _txcie); 00214 00215 for (p = buffer; *p != '\0';) { 00216 while (!((*_ucsra) & (1 << _udre))) {} 00217 00218 *_udr = *(p++); 00219 } 00220 } 00221 00227 void MHV_HardwareSerial::busyWrite_P(PGM_P buffer, uint16_t length) { 00228 uint16_t i; 00229 00230 while (!canSendBusy()) {}; 00231 *_ucsrb &= ~_BV( _txcie); 00232 00233 for (i = 0; i < length; i++) { 00234 /* Don't need to check return values as we have already checked up front 00235 * and async writes can't be initiated until we're done 00236 */ 00237 busyWrite(pgm_read_byte(buffer + i)); 00238 } 00239 } 00240 00246 void MHV_HardwareSerial::busyWrite(const char *buffer, uint16_t length) { 00247 uint16_t i; 00248 00249 while (!canSendBusy()) {}; 00250 *_ucsrb &= ~_BV( _txcie); 00251 00252 for (i = 0; i < length; i++) { 00253 /* Don't need to check return values as we have already checked up front 00254 * and async writes can't be initiated until we're done 00255 */ 00256 busyWrite(buffer[i]); 00257 } 00258 } 00259 00266 bool MHV_HardwareSerial::busy(void) { 00267 return !((*_ucsra) & (1 << _udre)); 00268 } 00269 00278 void MHV_HardwareSerial::debug(const char *file, int line, const char *function, 00279 PGM_P format, ...) { 00280 char debugBuffer[80]; 00281 va_list ap; 00282 va_start(ap, format); 00283 00284 while (!canSendBusy()) {} 00285 00286 snprintf_P(debugBuffer, sizeof(debugBuffer), PSTR("%s:%d\t%s():\t\t"), 00287 file, line, function); 00288 busyWrite(debugBuffer); 00289 00290 vsnprintf_P(debugBuffer, sizeof(debugBuffer), format, ap); 00291 busyWrite(debugBuffer); 00292 busyWrite_P(PSTR("\r\n")); 00293 }