Subversion Repositories Projects

Rev

Blame | Last modification | View Log | RSS feed

/*****************************************************************************
 *   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);
        }
}