206 lines
5.2 KiB
C
206 lines
5.2 KiB
C
/*
|
|
* c't-Bot
|
|
*
|
|
* This program is free software; you can redistribute it
|
|
* and/or modify it under the terms of the GNU General
|
|
* Public License as published by the Free Software
|
|
* Foundation; either version 2 of the License, or (at your
|
|
* option) any later version.
|
|
* This program 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 General Public License for more details.
|
|
* You should have received a copy of the GNU General Public
|
|
* License along with this program; if not, write to the Free
|
|
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
|
* MA 02111-1307, USA.
|
|
*
|
|
*/
|
|
|
|
/*! @file uart.c
|
|
* @brief Routinen zur seriellen Kommunikation
|
|
* @author Benjamin Benz (bbe@heise.de)
|
|
* @date 26.12.05
|
|
*/
|
|
|
|
#ifdef MCU
|
|
|
|
#include "ct-Bot.h"
|
|
|
|
#include <avr/io.h>
|
|
#include <avr/interrupt.h>
|
|
#ifndef NEW_AVR_LIB
|
|
#include <avr/signal.h>
|
|
#endif
|
|
#include "ct-Bot.h"
|
|
#include "uart.h"
|
|
#include "command.h"
|
|
#include "log.h"
|
|
|
|
#ifdef UART_AVAILABLE
|
|
|
|
#define BAUDRATE 57600
|
|
|
|
#define UART_RX_BUFFER_SIZE 16 /*!< Größe des UART-Puffers */
|
|
|
|
#define UART_RX_BUFFER_MASK ( UART_RX_BUFFER_SIZE - 1 )
|
|
#if ( UART_RX_BUFFER_SIZE & UART_RX_BUFFER_MASK )
|
|
#error RX buffer size is not a power of 2
|
|
#endif
|
|
|
|
//#define UART_TIMEOUT 20000 /*!< Timeout. Wartet UART_TIMEOUT CPU-Takte */
|
|
|
|
static uint8 UART_RxBuf[UART_RX_BUFFER_SIZE]; /*!< UART-Puffer */
|
|
static volatile uint8 UART_RxHead; /*!< Zeiger für UART-Puffer */
|
|
static volatile uint8 UART_RxTail; /*!< Zeiger für UART-Puffer */
|
|
|
|
//char uart_timeout; /*!< 0, wenn uart_read/uart_send erfolgreich 1, wenn timeout erreicht */
|
|
|
|
/*!
|
|
* Initialisiere UART
|
|
*/
|
|
void uart_init(void){
|
|
#ifdef __AVR_ATmega644__
|
|
/* Senden und Empfangen ermöglichen + RX Interrupt an */
|
|
UCSR0B= (1<<RXEN0) | (1<<TXEN0)|(1<<RXCIE0);
|
|
/* 8 Bit, 1 Stop, Keine Parity */
|
|
UCSR0C=0x86;
|
|
#else
|
|
/* Senden und Empfangen ermöglichen + RX Interrupt an */
|
|
UCSRB= (1<<RXEN) | (1<<TXEN)|(1<<RXCIE);
|
|
/* 8 Bit, 1 Stop, Keine Parity */
|
|
UCSRC=0x86;
|
|
#endif
|
|
|
|
/* UART auf 9600 baud */
|
|
// UBRRH=0;
|
|
// UBRRL= 103; /* Werte stehen im Datenblatt tabelarisch */
|
|
#ifdef __AVR_ATmega644__
|
|
UBRR0L = (uint8) (( ((uint32)F_CPU) / 16 / ((uint32)BAUDRATE) - 1) & 0xFF);
|
|
UBRR0H = (uint8) (( ((uint32)F_CPU) / 16 / ((uint32)BAUDRATE) - 1) >> 8);
|
|
#else
|
|
UBRRL = (uint8) (( ((uint32)F_CPU) / 16 / ((uint32)BAUDRATE) - 1) & 0xFF);
|
|
UBRRH = (uint8) (( ((uint32)F_CPU) / 16 / ((uint32)BAUDRATE) - 1) >> 8);
|
|
#endif
|
|
|
|
/* Puffer leeren */
|
|
UART_RxTail = 0;
|
|
UART_RxHead = 0;
|
|
}
|
|
|
|
/*!
|
|
* Interrupt Handler fuer den Datenempfang per UART
|
|
*/
|
|
#ifdef __AVR_ATmega644__
|
|
SIGNAL (USART0_RX_vect){
|
|
#else
|
|
SIGNAL (SIG_UART_RECV){
|
|
#endif
|
|
|
|
/* Pufferindex berechnen */
|
|
UART_RxHead++; /* erhoehen */
|
|
UART_RxHead %= UART_RX_BUFFER_MASK; /* Und bei Bedarf umklappen, da Ringpuffer */
|
|
|
|
if (UART_RxHead == UART_RxTail){
|
|
/* TODO Fehler behandeln !!
|
|
* ERROR! Receive buffer overflow */
|
|
}
|
|
#ifdef __AVR_ATmega644__
|
|
UART_RxBuf[UART_RxHead] = UDR0; /* Daten lesen und sichern*/
|
|
#else
|
|
UART_RxBuf[UART_RxHead] = UDR; /* Daten lesen und sichern*/
|
|
#endif
|
|
}
|
|
|
|
/*!
|
|
* Prüft, ob daten verfügbar
|
|
* @return Anzahl der verfuegbaren Bytes
|
|
*/
|
|
uint8 uart_data_available(void){
|
|
if (UART_RxHead == UART_RxTail) /* Puffer leer */
|
|
return 0;
|
|
else if (UART_RxHead > UART_RxTail) /* Schreibzeiger vor Lesezeiger */
|
|
return UART_RxHead - UART_RxTail;
|
|
else /* Schreibzeiger ist schon umgelaufen */
|
|
return UART_RxHead - UART_RxTail + UART_RX_BUFFER_SIZE;
|
|
}
|
|
|
|
|
|
/*!
|
|
* Überträgt ein Zeichen per UART
|
|
* Achtung ist noch blockierend!!!!
|
|
* TODO: umstellen auf nicht blockierend und mehr als ein Zeichen
|
|
* @param data Das Zeichen
|
|
*/
|
|
void uart_send_byte(uint8 data){ // Achtung ist noch blockierend!!!!
|
|
#ifdef __AVR_ATmega644__
|
|
while ((UCSR0A & _BV(UDRE0)) ==0){asm volatile("nop"); } // warten bis UART sendebereit
|
|
UDR0= data;
|
|
#else
|
|
while ((UCSRA & _BV(UDRE)) ==0){asm volatile("nop"); } // warten bis UART sendebereit
|
|
UDR= data;
|
|
#endif
|
|
}
|
|
|
|
/*!
|
|
* Sende Kommando per UART im Little Endian
|
|
* @param cmd Zeiger auf das Kommando
|
|
* @return Anzahl der gesendete Bytes
|
|
*/
|
|
//#define uart_send_cmd(cmd) uart_write(cmd,sizeof(command_t));
|
|
|
|
/*
|
|
int uart_send_cmd(command_t *cmd){
|
|
int i;
|
|
char * ptr = (char*) cmd;
|
|
for (i=0; i<sizeof(command_t); i++)
|
|
uart_send_byte(*ptr++);
|
|
|
|
return sizeof(command_t);
|
|
}
|
|
*/
|
|
|
|
/*!
|
|
* Sende Daten per UART im Little Endian
|
|
* @param data Datenpuffer
|
|
* @param length Groesse des Datenpuffers in bytes
|
|
* @return Anzahl der gesendete Bytes
|
|
*/
|
|
int uart_write(uint8 * data, int length){
|
|
int i;
|
|
char * ptr = (char*) data;
|
|
for (i=0; i<length; i++)
|
|
uart_send_byte(*ptr++);
|
|
|
|
return length;
|
|
}
|
|
|
|
/*!
|
|
* Liest Zeichen von der UART
|
|
* @param data Der Zeiger an die die gelesenen Zeichen kommen
|
|
* @param length Anzahl der zu lesenden Bytes
|
|
* @return Anzahl der tatsaechlich gelesenen Zeichen
|
|
*/
|
|
int uart_read(void* data, int length){
|
|
uint8 i;
|
|
char* ptr = data;
|
|
|
|
uint8 count= uart_data_available();
|
|
|
|
// LOG_DEBUG(("%d/%d av/sel",count,length));
|
|
|
|
if (count > length)
|
|
count=length;
|
|
|
|
for (i=0; i<count; i++){
|
|
UART_RxTail++;
|
|
UART_RxTail %= UART_RX_BUFFER_MASK;
|
|
*ptr++ = UART_RxBuf[UART_RxTail];
|
|
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
#endif
|
|
#endif
|