Subversion Repositories Projects

Compare Revisions

Ignore whitespace Rev 1469 → Rev 1470

/Transportables_Koptertool/branch/GPL_PKT_V3_5_8a_FC086/usart.c
0,0 → 1,634
/*****************************************************************************
* Copyright (C) 2008 Thomas Kaiser, thomas@ft-fanpage.de *
* Copyright (C) 2009 Peter "woggle" Mack, mac@denich.net *
* Copyright (C) 2011 Christian "Cebra" Brandtner, brandtner@brandtner.net *
* Copyright (C) 2011 Harald Bongartz *
* *
* 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. *
* *
* 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. *
* *
* *
* Credits to: *
* Holger Buss & Ingo Busker from mikrokopter.de for the MK project + SVN *
* http://www.mikrokopter.de *
* Gregor "killagreg" Stobrawa for his version of the MK code *
* Thomas Kaiser "thkais" for the original project. See *
* http://www.ft-fanpage.de/mikrokopter/ *
* http://forum.mikrokopter.de/topic-4061-1.html *
* Claas Anders "CaScAdE" Rathje for providing the font and his C-OSD code *
* http://www.mylifesucks.de/oss/c-osd/ *
* Harald Bongartz "HaraldB" for providing his Ideas and Code for usibility*
*****************************************************************************/
 
 
#include "cpu.h"
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <avr/wdt.h>
#include <util/delay.h>
#include <stdarg.h>
 
#include "main.h"
#include "usart.h"
#include "lcd.h"
#include "timer.h"
 
uint8_t buffer[30];
 
volatile uint8_t txd_buffer[TXD_BUFFER_LEN];
volatile uint8_t txd_complete = TRUE;
 
volatile uint8_t rxd_buffer[RXD_BUFFER_LEN];
volatile uint8_t rxd_buffer_locked = FALSE;
volatile uint8_t ReceivedBytes = 0;
volatile uint8_t *pRxData = 0;
volatile uint8_t RxDataLen = 0;
 
volatile uint16_t stat_crc_error = 0;
volatile uint16_t stat_overflow_error = 0;
 
volatile uint8_t rx_byte;
volatile uint8_t rxFlag = 0;
 
 
#define UART_RXBUFSIZE 64
#define UART_NO_DATA 0x0100 /* no receive data available */
 
volatile static uint8_t rxbuf[UART_RXBUFSIZE];
volatile static uint8_t *volatile rxhead, *volatile rxtail;
 
 
/*
 
//-----------------------------------------------------------------------------
// USART1 transmitter ISR
ISR (USART1_TX_vect)
{
static uint16_t ptr_txd1_buffer = 0;
uint8_t tmp_tx1;
 
if(!txd1_complete) // transmission not completed
{
ptr_txd1_buffer++; // [0] was already sent
tmp_tx1 = txd1_buffer[ptr_txd1_buffer];
// if terminating character or end of txd buffer was reached
if((tmp_tx1 == '\r') || (ptr_txd1_buffer == TXD_BUFFER_LEN))
{
ptr_txd1_buffer = 0; // reset txd pointer
txd1_complete = TRUE; // stop transmission
}
UDR1 = tmp_tx1; // send current byte will trigger this ISR again
}
// transmission completed
else ptr_txd1_buffer = 0;
}
 
*/
 
 
#ifdef USART_INT
//-----------------------------------------------------------------------------
// USART0 transmitter ISR
ISR (USART_TX_vect)
{
static uint16_t ptr_txd_buffer = 0;
uint8_t tmp_tx;
 
if(!txd_complete) // transmission not completed
{
ptr_txd_buffer++; // [0] was already sent
tmp_tx = txd_buffer[ptr_txd_buffer];
// if terminating character or end of txd buffer was reached
if((tmp_tx == '\r') || (ptr_txd_buffer == TXD_BUFFER_LEN))
{
ptr_txd_buffer = 0; // reset txd pointer
txd_complete = TRUE; // stop transmission
}
UDR = tmp_tx; // send current byte will trigger this ISR again
}
// transmission completed
else ptr_txd_buffer = 0;
}
#endif
 
 
 
 
 
//-----------------------------------------------------------------------------
//
 
//
//uint8_t uart_getc_nb(uint8_t *c)
//{
// if (rxhead==rxtail) return 0;
// *c = *rxtail;
// if (++rxtail == (rxbuf + UART_RXBUFSIZE)) rxtail = rxbuf;
// return 1;
//}
 
 
 
 
ISR (USART0_RX_vect)
{
static uint16_t crc;
static uint8_t ptr_rxd_buffer = 0;
uint8_t crc1, crc2;
uint8_t c;
// IdleTimer = 0;
if (current_hardware == Wi232)
{
// rx_byte = c;
// rxFlag = 1;
int diff;
uint8_t c;
c=UDR;
diff = rxhead - rxtail;
if (diff < 0) diff += UART_RXBUFSIZE;
if (diff < UART_RXBUFSIZE -1)
{
*rxhead = c;
++rxhead;
if (rxhead == (rxbuf + UART_RXBUFSIZE)) rxhead = rxbuf;
};
// USART_putc (c);
return;
}
 
 
if (current_hardware == MKGPS)
{
// rx_byte = c;
// rxFlag = 1;
int diff;
uint8_t c;
c=UDR;
diff = rxhead - rxtail;
if (diff < 0) diff += UART_RXBUFSIZE;
if (diff < UART_RXBUFSIZE -1)
{
*rxhead = c;
++rxhead;
if (rxhead == (rxbuf + UART_RXBUFSIZE)) rxhead = rxbuf;
};
 
return;
}
 
c = UDR; // catch the received byte
 
 
if (rxd_buffer_locked)
return; // if rxd buffer is locked immediately return
 
// the rxd buffer is unlocked
if ((ptr_rxd_buffer == 0) && (c == '#')) // if rxd buffer is empty and syncronisation character is received
{
rxd_buffer[ptr_rxd_buffer++] = c; // copy 1st byte to buffer
crc = c; // init crc
}
else if (ptr_rxd_buffer < RXD_BUFFER_LEN) // collect incomming bytes
{
if(c != '\r') // no termination character
{
rxd_buffer[ptr_rxd_buffer++] = c; // copy byte to rxd buffer
crc += c; // update crc
}
else // termination character was received
{
// the last 2 bytes are no subject for checksum calculation
// they are the checksum itself
crc -= rxd_buffer[ptr_rxd_buffer-2];
crc -= rxd_buffer[ptr_rxd_buffer-1];
// calculate checksum from transmitted data
crc %= 4096;
crc1 = '=' + crc / 64;
crc2 = '=' + crc % 64;
// compare checksum to transmitted checksum bytes
if((crc1 == rxd_buffer[ptr_rxd_buffer-2]) && (crc2 == rxd_buffer[ptr_rxd_buffer-1]))
{ // checksum valid
rxd_buffer[ptr_rxd_buffer] = '\r'; // set termination character
ReceivedBytes = ptr_rxd_buffer + 1;// store number of received bytes
if (mode == rxd_buffer[2])
{
rxd_buffer_locked = TRUE; // lock the rxd buffer
// if 2nd byte is an 'R' enable watchdog that will result in an reset
if(rxd_buffer[2] == 'R') {wdt_enable(WDTO_250MS);} // Reset-Commando
}
}
else
{ // checksum invalid
stat_crc_error++;
rxd_buffer_locked = FALSE; // unlock rxd buffer
}
ptr_rxd_buffer = 0; // reset rxd buffer pointer
}
}
else // rxd buffer overrun
{
stat_overflow_error++;
ptr_rxd_buffer = 0; // reset rxd buffer
rxd_buffer_locked = FALSE; // unlock rxd buffer
}
}
 
 
//-----------------------------------------------------------------------------
// Function: uart0_getc()
// Purpose: return byte from ringbuffer
// Returns: lower byte: received byte from ringbuffer
// higher byte: last receive error
//-----------------------------------------------------------------------------
char USART_getc(void)
{
char val;
 
// while(rxhead==rxtail) ;
if (rxhead==rxtail)
return val=0;
// IdleTimer = 0;
val = *rxtail;
if (++rxtail == (rxbuf + UART_RXBUFSIZE))
rxtail = rxbuf;
 
return val;
}
 
 
uint8_t uart_getc_nb(uint8_t *c)
{
if (rxhead==rxtail)
return 0;
// IdleTimer = 0;
*c = *rxtail;
if (++rxtail == (rxbuf + UART_RXBUFSIZE))
rxtail = rxbuf;
return 1;
}
//-----------------------------------------------------------------------------
//
 
 
 
 
 
//-----------------------------------------------------------------------------
//
void USART_Init (unsigned int baudrate)
{
// set clock divider
// #undef BAUD
// #define BAUD baudrate
// #include <util/setbaud.h>
// UBRRH = UBRRH_VALUE;
// UBRRL = UBRRL_VALUE;
 
UBRRH = (unsigned char)(baudrate>>8);
UBRRL = (unsigned char) baudrate;
 
#if USE_2X
UCSRA |= (1 << U2X); // enable double speed operation
#else
UCSRA &= ~(1 << U2X); // disable double speed operation
#endif
 
// set 8N1
#if defined (__AVR_ATmega8__) || defined (__AVR_ATmega32__)
UCSRC = (1 << URSEL) | (1 << UCSZ1) | (1 << UCSZ0);
#else
UCSRC = (1 << UCSZ1) | (1 << UCSZ0);
#endif
UCSRB &= ~(1 << UCSZ2);
 
// flush receive buffer
while ( UCSRA & (1 << RXC) ) UDR;
 
UCSRB |= (1 << RXEN) | (1 << TXEN);
#ifdef USART_INT
UCSRB |= (1 << RXCIE) | (1 << TXCIE);
#else
UCSRB |= (1 << RXCIE);
#endif
 
rxhead = rxtail = rxbuf;
 
}
 
 
 
 
 
//-----------------------------------------------------------------------------
// disable the txd pin of usart
void USART_DisableTXD (void)
{
#ifdef USART_INT
UCSRB &= ~(1 << TXCIE); // disable TX-Interrupt
#endif
UCSRB &= ~(1 << TXEN); // disable TX in USART
DDRB &= ~(1 << DDB3); // set TXD pin as input
PORTB &= ~(1 << PORTB3); // disable pullup on TXD pin
}
 
//-----------------------------------------------------------------------------
// enable the txd pin of usart
void USART_EnableTXD (void)
{
DDRB |= (1 << DDB3); // set TXD pin as output
PORTB &= ~(1 << PORTB3); // disable pullup on TXD pin
UCSRB |= (1 << TXEN); // enable TX in USART
#ifdef USART_INT
UCSRB |= (1 << TXCIE); // enable TX-Interrupt
#endif
}
 
//-----------------------------------------------------------------------------
// short script to directly send a request thorugh usart including en- and disabling it
// where <address> is the address of the receipient, <label> is which data set to request
// and <ms> represents the milliseconds delay between data
void USART_request_mk_data (uint8_t cmd, uint8_t addr, uint8_t ms)
{
USART_EnableTXD (); // re-enable TXD pin
 
unsigned char mstenth = ms/10;
SendOutData(cmd, addr, 1, &mstenth, 1);
// wait until command transmitted
while (txd_complete == FALSE);
 
USART_DisableTXD (); // disable TXD pin again
}
 
//-----------------------------------------------------------------------------
//
void USART_putc (char c)
{
#ifdef USART_INT
#else
loop_until_bit_is_set(UCSRA, UDRE);
UDR = c;
#endif
}
 
 
 
//-----------------------------------------------------------------------------
//
void USART_puts (char *s)
{
#ifdef USART_INT
#else
while (*s)
{
USART_putc (*s);
s++;
}
#endif
}
 
//-----------------------------------------------------------------------------
//
void USART_puts_p (const char *s)
{
#ifdef USART_INT
#else
while (pgm_read_byte(s))
{
USART_putc (pgm_read_byte(s));
s++;
}
#endif
}
 
//-----------------------------------------------------------------------------
//
void SendOutData(uint8_t cmd, uint8_t addr, uint8_t numofbuffers, ...) // uint8_t *pdata, uint8_t len, ...
{
va_list ap;
uint16_t pt = 0;
uint8_t a,b,c;
uint8_t ptr = 0;
uint16_t tmpCRC = 0;
 
uint8_t *pdata = 0;
int len = 0;
 
txd_buffer[pt++] = '#'; // Start character
txd_buffer[pt++] = 'a' + addr; // Address (a=0; b=1,...)
txd_buffer[pt++] = cmd; // Command
 
va_start(ap, numofbuffers);
if(numofbuffers)
{
pdata = va_arg (ap, uint8_t*);
len = va_arg (ap, int);
ptr = 0;
numofbuffers--;
}
 
while(len)
{
if(len)
{
a = pdata[ptr++];
len--;
if((!len) && numofbuffers)
{
pdata = va_arg(ap, uint8_t*);
len = va_arg(ap, int);
ptr = 0;
numofbuffers--;
}
}
else
a = 0;
 
if(len)
{
b = pdata[ptr++];
len--;
if((!len) && numofbuffers)
{
pdata = va_arg(ap, uint8_t*);
len = va_arg(ap, int);
ptr = 0;
numofbuffers--;
}
}
else
b = 0;
 
if(len)
{
c = pdata[ptr++];
len--;
if((!len) && numofbuffers)
{
pdata = va_arg(ap, uint8_t*);
len = va_arg(ap, int);
ptr = 0;
numofbuffers--;
}
}
else
c = 0;
 
txd_buffer[pt++] = '=' + (a >> 2);
txd_buffer[pt++] = '=' + (((a & 0x03) << 4) | ((b & 0xf0) >> 4));
txd_buffer[pt++] = '=' + (((b & 0x0f) << 2) | ((c & 0xc0) >> 6));
txd_buffer[pt++] = '=' + ( c & 0x3f);
}
va_end(ap);
 
for(a = 0; a < pt; a++)
{
tmpCRC += txd_buffer[a];
}
tmpCRC %= 4096;
txd_buffer[pt++] = '=' + tmpCRC / 64;
txd_buffer[pt++] = '=' + tmpCRC % 64;
txd_buffer[pt++] = '\r';
 
txd_complete = FALSE;
#ifdef USART_INT
UDR = txd_buffer[0]; // initiates the transmittion (continued in the TXD ISR)
#else
for(a = 0; a < pt; a++)
{
loop_until_bit_is_set(UCSRA, UDRE);
UDR = txd_buffer[a];
}
txd_complete = TRUE;
#endif
}
 
//-----------------------------------------------------------------------------
//
void Decode64 (void)
{
uint8_t a,b,c,d;
uint8_t ptrIn = 3;
uint8_t ptrOut = 3;
uint8_t len = ReceivedBytes - 6;
 
while (len)
{
a = rxd_buffer[ptrIn++] - '=';
b = rxd_buffer[ptrIn++] - '=';
c = rxd_buffer[ptrIn++] - '=';
d = rxd_buffer[ptrIn++] - '=';
//if(ptrIn > ReceivedBytes - 3) break;
 
if (len--)
rxd_buffer[ptrOut++] = (a << 2) | (b >> 4);
else
break;
 
if (len--)
rxd_buffer[ptrOut++] = ((b & 0x0f) << 4) | (c >> 2);
else
break;
 
if (len--)
rxd_buffer[ptrOut++] = ((c & 0x03) << 6) | d;
else
break;
}
pRxData = &rxd_buffer[3];
RxDataLen = ptrOut - 3;
}
 
 
//-----------------------------------------------------------------------------
//
void SwitchToNC (void)
{
 
if(hardware == NC)
{
// switch to NC
USART_putc (0x1b);
USART_putc (0x1b);
USART_putc (0x55);
USART_putc (0xaa);
USART_putc (0x00);
current_hardware = NC;
_delay_ms (50);
}
}
 
//-----------------------------------------------------------------------------
//
 
 
//-----------------------------------------------------------------------------
//
void SwitchToWi232 (void)
{
 
// if(hardware == NC)
{
// switch to Wi232
current_hardware = Wi232;
_delay_ms (50);
}
}
 
//-----------------------------------------------------------------------------
//
void SwitchToFC (void)
{
uint8_t cmd;
 
if (current_hardware == NC)
{
// switch to FC
cmd = 0x00; // 0 = FC, 1 = MK3MAG, 2 = MKGPS
SendOutData('u', ADDRESS_NC, 1, &cmd, 1);
current_hardware = FC;
_delay_ms (50);
}
}
 
//-----------------------------------------------------------------------------
//
void SwitchToMAG (void)
{
uint8_t cmd;
 
if (current_hardware == NC)
{
// switch to MK3MAG
cmd = 0x01; // 0 = FC, 1 = MK3MAG, 2 = MKGPS
SendOutData('u', ADDRESS_NC, 1, &cmd, 1);
current_hardware = MK3MAG;
_delay_ms (50);
}
}
 
//-----------------------------------------------------------------------------
//
void SwitchToGPS (void)
{
uint8_t cmd;
if (current_hardware == NC)
{
// switch to MKGPS
cmd = 0x02; // 0 = FC, 1 = MK3MAG, 2 = MKGPS
SendOutData('u', ADDRESS_NC, 1, &cmd, 1);
current_hardware = MKGPS;
_delay_ms (50);
}
}