Files
SyncHome/trunk/Arduino/libraries/TVout/pollserial/pollserial.cpp

139 lines
3.6 KiB
C++
Raw Normal View History

2023-03-17 11:59:21 +00:00
/*
pollserial.cpp Heavily modified version of:
HardwareSerial.cpp - Hardware serial library for Wiring
Copyright (c) 2006 Nicholas Zambetti. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Modified 23 November 2006 by David A. Mellis
Modified July 2010 by Myles D. Metzler
*/
#include <avr/io.h>
#include <stdlib.h>
#include "pollserial.h"
#define BUFFER_SIZE 64
rbuffer rxbuffer = {0,0,0};
void USART_recieve() {
#if defined ( UDR0 )
if( UCSR0A & _BV(RXC0)) {
uint8_t i = (rxbuffer.head + 1) & (BUFFER_SIZE - 1);
if ( i != rxbuffer.tail) {
rxbuffer.buffer[rxbuffer.head] = UDR0;
rxbuffer.head = i;
}
}
#else
if( UCSRA & _BV(RXC)) {
uint8_t i = (rxbuffer.head + 1) & (BUFFER_SIZE - 1);
if ( i != rxbuffer.tail) {
rxbuffer.buffer[rxbuffer.head] = UDR;
rxbuffer.head = i;
}
}
#endif
}
pt2Funct pollserial::begin(long baud) {
uint16_t baud_setting;
bool use_u2x;
rxbuffer.buffer = (unsigned char*)malloc(BUFFER_SIZE*sizeof(unsigned char));
// U2X mode is needed for baud rates higher than (CPU Hz / 16)
if (baud > F_CPU / 16) {
use_u2x = true;
}
else {
// figure out if U2X mode would allow for a better connection
// calculate the percent difference between the baud-rate specified and
// the real baud rate for both U2X and non-U2X mode (0-255 error percent)
uint8_t nonu2x_baud_error = abs((int)(255-((F_CPU/(16*(((F_CPU/8/baud-1)/2)+1))*255)/baud)));
uint8_t u2x_baud_error = abs((int)(255-((F_CPU/(8*(((F_CPU/4/baud-1)/2)+1))*255)/baud)));
// prefer non-U2X mode because it handles clock skew better
use_u2x = (nonu2x_baud_error > u2x_baud_error);
}
if (use_u2x) {
#if defined ( UDR0 )
UCSR0A = _BV(U2X0);
#else
UCSRA = _BV(U2X);
#endif
baud_setting = (F_CPU / 4 / baud - 1) / 2;
}
else {
#if defined ( UDR0 )
UCSR0A = 0;
#else
UCSRA = 0;
#endif
baud_setting = (F_CPU / 8 / baud - 1) / 2;
}
// assign the baud_setting, a.k.a. (USART Baud Rate Register)
#if defined ( UDR0 )
UBRR0 = baud_setting;
UCSR0B = _BV(RXEN0) | _BV(TXEN0);
#else
UBRR = baud_setting;
UCSRB = _BV(RXEN) | _BV(TXEN);
#endif
return &USART_recieve;
}
void pollserial::end() {
UCSR0B &= ~(_BV(RXEN0) | _BV(TXEN0));
free(rxbuffer.buffer);
}
uint8_t pollserial::available() {
return (BUFFER_SIZE + rxbuffer.head - rxbuffer.tail) & (BUFFER_SIZE-1);
}
int pollserial::read() {
if (rxbuffer.head == rxbuffer.tail)
return -1;
else {
uint8_t c = rxbuffer.buffer[rxbuffer.tail];
//tail = (tail + 1) & 63;
if (rxbuffer.tail == BUFFER_SIZE)
rxbuffer.tail = 0;
else
rxbuffer.tail++;
return c;
}
}
void pollserial::flush() {
rxbuffer.head = rxbuffer.tail;
}
void pollserial::write(uint8_t c) {
#if defined ( UDR0 )
while (!((UCSR0A) & _BV(UDRE0)));
UDR0 = c;
#else
while (!((UCSRA) & _BV(UDRE)));
UDR = c;
#endif
}