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                  *
 *   based on the key handling by Peter Dannegger                            *
 *     see www.mikrocontroller.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 <string.h>
#include <util/delay.h>
#include <inttypes.h>


#include "main.h"
#include "timer.h"
#include "eeprom.h"
#include "lcd.h"
#include "uart1.h"
#include "bluetooth.h"
#include "setup.h"


#if defined HWVERSION1_2W || defined HWVERSION1_2
#include "HAL_HW1_2.h"
#endif

#if defined HWVERSION1_3W || defined HWVERSION1_3
#include "HAL_HW1_3.h"
#endif

#ifdef HWVERSION3_9
#include "HAL_HW3_9.h"
#endif

volatile uint16_t timer;
volatile uint16_t abo_timer;
volatile static unsigned int tim_main;

uint8_t key_state = 0;          // debounced and inverted key state:
                                                        // bit = 1: key pressed
uint8_t key_press = 0;          // key press detect
uint8_t key_long = 0;           // key long press
uint8_t key_rpt = 0;            // key repeat
uint8_t key_lrpt = 0;           // key long press and repeat
uint8_t key_rpts = 0;           // key long press and speed repeat
uint8_t repeat_speed = 0;

uint16_t DisplayTime = 0;       // Leuchtdauer
volatile uint16_t IdleTimer = 0;                // InaktivitätsTimer

uint16_t WarnCount = 0;         // Zähler der LIPO Warnzeit
uint16_t WarnToggle = 0;        // Togglezähler zum blinken
uint16_t WarnTime = 10;         // Länge der LIPO Warnzeit 10 Sek.
uint16_t PoffTime = 30;         // Länge der Wartezeit vor Abschalten 30 Sek.
//uint8_t       servo = 0;



volatile uint8_t Display_on;// Flag Display on/off

unsigned int BeepTime = 0;
unsigned int BeepMuster = 0xffff;
unsigned int BeepPrio = 0;

volatile unsigned int CountMilliseconds = 0;

// Size of Buffer for Converting unsigned int Value to ASCII
#define STRING_BUFFER_SIZE 5

// Buffer for Converting unsigned int Value to ASCII
char String_Buffer[STRING_BUFFER_SIZE];


//--------------------------------------------------------------
//
void Timer1_Init (void) // Timer 1-A
{
        // löschen
        TCCR1A = 0;
        TCCR1B = 0;
        TIMSK1 = 0;

        // setzen
        TCCR1A |=   (1 << COM1A1) | (1 << WGM11);
        TCCR1B |=   (1 << CS11)   | (1 << CS10)   | (1 << WGM13)  | (1 << WGM12);

        ICR1 = (F_CPU / 64) * 20 / 1000;

        OCR1A = 470;  // ca. Servomitte
}


//--------------------------------------------------------------
void Timer2_Init (void) // Displayhelligkeit
{
        DDRD   |= (1 << DDD7);                                                                          // PD7 output
        TCCR2A |= (1 << WGM21)  | (1 << WGM20)  | (1 << COM2A1);        // non invers
        TCCR2B |= (1 << CS20);                                                                          // Prescaler 1/1
        TIMSK2 |= (1 << OCIE2A) | (1 << OCIE2B);

        OCR2A = 255;
}


#if defined HWVERSION1_2 || defined HWVERSION1_2W
//--------------------------------------------------------------
ISR(TIMER2_COMPA_vect)
{
        PORTD &= ~(1 << PD7);
        PORTC &= ~(1 << PC0);
        PORTC &= ~(1 << PC1);
}
ISR(TIMER2_COMPB_vect)
{
        PORTD |= (1 << PD7);
        PORTC |= (1 << PC0);
        PORTC |= (1 << PC1);
}
#endif
#if defined HWVERSION1_3 || defined HWVERSION1_3W
//--------------------------------------------------------------
ISR(TIMER2_COMPA_vect)
{
        PORTD &= ~(1 << PD7);
        PORTD &= ~(1 << PD6);
        PORTC &= ~(1 << PC2);
}
ISR(TIMER2_COMPB_vect)
{
        PORTD |= (1 << PD7);
        PORTD |= (1 << PD6);
        PORTC |= (1 << PC2);
}
#endif
#ifdef HWVERSION3_9
//--------------------------------------------------------------
ISR(TIMER2_COMPA_vect)
{
        PORTD |= (1 << PIND7); // MartinR: von PD auf PIND geändert
}
ISR(TIMER2_COMPB_vect)
{
        PORTD &= ~(1 << PIND7); // MartinR: von PD auf PIND geändert
}
#endif


//--------------------------------------------------------------
void Timer0_Init (void)  // System (100Hz)
{
        timer = 0;

        TCCR0A = (1 << WGM01);
        TCCR0B = (1 << CS02) | (1 << CS00);
        OCR0A = (F_CPU / (100L * 1024L)) ;

        TIMSK0 |= (1 << OCIE0A);        // enable interrupt for OCR
}


//--------------------------------------------------------------
ISR(TIMER0_COMPA_vect)  // Timer-Interrupt (100 Hz)
{
        static uint8_t ct0 = 0;
        static uint8_t ct1 = 0;
        static uint8_t k_time_l = 0;
        static uint8_t k_time_r = 0;
        static uint8_t k_time_lr = 0;
        static uint8_t k_time_rs = 0;
        uint8_t i;

        static unsigned char cnt_1ms = 1,cnt = 0;
        unsigned char beeper_ein = 0;
//      unsigned char pieper_ein = 0;

        // Key handling by Peter Dannegger
        // see www.mikrocontroller.net

        i = key_state ^ ~KEY_PIN;               // key changed ?
        ct0 = ~(ct0 & i);                               // reset or count ct0
        ct1 = ct0 ^ (ct1 & i);                  // reset or count ct1
        i &= (ct0 & ct1);                               // count until roll over ?
        key_state ^= i;                                 // then toggle debounced state
        key_press |= (key_state & i);   // 0->1: key press detect

        if (PKT_IdleBeep == 1)
        {
                IdleTimer ++;                                   // nix zu tun? Timer hochzählen
                if (IdleTimer == 12000)                 // Warnhinweis
                {
                        set_beep ( 200, 0x0080, BeepNormal);
                        IdleTimer = 0;
                }
        }

        if (!cnt--)
        {
                cnt = 9;
                CountMilliseconds++;
                cnt_1ms++;
        }

        if (i!=0)
        {                                               // Displaylicht einschalten, und bzw. Timeoutzählerreset wenn Taste gedrückt wurde
                if (Display_on == 0)
                  set_D_LIGHT();


                Display_on = 1;         // Flag Display on
                DisplayTime = 0;        // Timer Reset
                IdleTimer = 0;          // Idletimeout Reset

        }

        if (DisplayTimeout > 0)
        {
                if (Display_on == 1)
                {
                        DisplayTime++;
                        if ((DisplayTime / 100) == DisplayTimeout)      // ISR läuft mit 100Hz
                        {                                                                                       // Displaylicht ausschalten
                            clr_D_LIGHT();
                            Display_on = 0;                                                     // Flag Display off

                        }
                }
        }

//--------------------------------------------------------------
#ifdef HWVERSION3_9
        if (ADCSRA & ADIE) LipoCheck(); // Lipo prüfen // MartinR nicht wenn Stick aktiv
        //LipoCheck();  // Lipo prüfen // MartinR: soe war es
#endif

//--------------------------------------------------------------
        if (BeepTime)
        {
                if (BeepTime > 10)
                        BeepTime -= 10;
                else
                  {
                        BeepTime = 0;

                  }

                if (BeepTime & BeepMuster)
                        beeper_ein = 1;
                else    beeper_ein = 0;


        }
        else
        {
                beeper_ein = 0;
                BeepMuster = 0xffff;
                BeepPrio = BeepNormal;
        }

        if (beeper_ein==1)
                set_BEEP();
        else
                clr_BEEP();


//--------------------------------------------------------------
        if ((key_state & LONG_MASK) == 0)                       // check long key function
                k_time_l = REPEAT_START;                                // start delay

        if (--k_time_l == 0)                                            // long countdown
                key_long |= (key_state & LONG_MASK);

//--------------------------------------------------------------
        if ((key_state & REPEAT_MASK) == 0)                     // check repeat function
                k_time_r = 1;                                                   // kein delay

        if (--k_time_r == 0)
        {
                k_time_r = REPEAT_NEXT;                                 // repeat delay
                key_rpt |= (key_state & REPEAT_MASK);
        }

//--------------------------------------------------------------
        if ((key_state & LONG_REPEAT_MASK) == 0)        // check repeat function
                k_time_lr = REPEAT_START;                               // start delay

        if (--k_time_lr == 0)
        {
                k_time_lr = REPEAT_NEXT;                                // repeat delay
                key_lrpt |= (key_state & LONG_REPEAT_MASK);
        }

//--------------------------------------------------------------
        if ((key_state & LONG_REPEAT_SP_MASK) == 0)     // check repeatX function
                k_time_rs = REPEAT_START;                               // start delay

        if (--k_time_rs == 0)                                           // repeat countdown
        {
                if (repeat_speed == 1)
                {
                        k_time_rs = REPEAT_SPEED_1;
                        key_rpts |= (key_state & LONG_REPEAT_SP_MASK);
                }
                else if (repeat_speed == 2)
                {
                        k_time_rs = REPEAT_SPEED_2;
                        key_rpts |= (key_state & LONG_REPEAT_SP_MASK);
                }
                else if (repeat_speed == 3)
                {
                        k_time_rs = REPEAT_SPEED_3;
                        key_rpts |= (key_state & LONG_REPEAT_SP_MASK);
                }
        }

        if (timer > 0)
                timer --;

        if (abo_timer > 0)
                abo_timer --;

//      if (receiveNMEA==true)
//        {
//          if (bt_receiveNMEA()) Tracking_NMEA();
//
//        }


}


//--------------------------------------------------------------
#ifdef HWVERSION3_9

void LipoCheck (void)   // Lowbatpin des Spannungswandlers prüfen
                        // LBO des LT1308 wechselt zum Ende der Batterielaufzeit häufig seinen Zustand in der Übergangsphase zum LowBat
                        // Die Akkuspannung schwankt auch abhängig vom momentanen Stromverbrauch
{
        if (WarnToggle == 1)    // Beim ersten Auftreten Warnung ausgeben, Rythmus 5/10 Sekunden
        {

                set_beep ( 1000, 0x0020, BeepNormal);
                lcd_printp_at (0, 0, PSTR("  LIPO  !!Warnung!!  "), 2);
        }

        if (WarnToggle == WarnTime * 100)
                WarnToggle = 0;  // erstmal bis hier warnen

        if (WarnToggle > 0)
                WarnToggle++;  // weiter hochzählen

        if (PINC & (1 << LowBat))       // Kurzzeitige Unterspannung bearbeiten und Warnung ausgeben
        {
                WarnCount = 0;
//              if (WarnCount > 0)
//                      WarnCount--;  // Bei LIPO OK erstmal runterzählen, LT1308 überlegt sich noch genauer ob nun ok oder nicht
        }

        if (!(PINC & (1 << LowBat)) )  // LT1308 hat Unterspannung erkannt
        {
                WarnCount++;  // solange LBO low ist Zähler hochzählen
                if (WarnCount == 10 && WarnToggle == 0)  // mit "10" etwas unempfindlicher gegen kurze Impulse machen
                        WarnToggle = 1;  // Warnhinweis starten
        }

        if ((WarnCount) == PoffTime * 100)
                clr_V_On();  // Spannung abschalten
}

#endif


//--------------------------------------------------------------
unsigned int SetDelay (unsigned int t)
{
        return(CountMilliseconds + t + 1);
}


//--------------------------------------------------------------
char CheckDelay(unsigned int t)
{
        return(((t - CountMilliseconds) & 0x8000) >> 9);
}


//--------------------------------------------------------------
void Delay_ms(unsigned int w)
{
        unsigned int akt;
        akt = SetDelay(w);
        while (!CheckDelay(akt));
}


//--------------------------------------------------------------
//
uint8_t get_key_press (uint8_t key_mask)
{
        uint8_t sreg = SREG;

        // disable all interrupts
        cli();

        key_mask &= key_press;  // read key(s)
        key_press ^= key_mask;  // clear key(s)

        SREG = sreg;    // restore status register

        return key_mask;
}


//--------------------------------------------------------------
//
uint8_t get_key_short (uint8_t key_mask)
{
        uint8_t ret;
        uint8_t sreg = SREG;

        // disable all interrupts
        cli();

        ret = get_key_press (~key_state & key_mask);

        SREG = sreg;    // restore status register

        return ret;
}


//--------------------------------------------------------------
//
uint8_t get_key_long (uint8_t key_mask)
{
        uint8_t sreg = SREG;

        // disable all interrupts
        cli();

        key_mask &= key_long;   // read key(s)
        key_long ^= key_mask;   // clear key(s)

        SREG = sreg;    // restore status register

  return get_key_press (get_key_rpt (key_mask));
}


//--------------------------------------------------------------
//
uint8_t get_key_rpt (uint8_t key_mask)
{
        uint8_t sreg = SREG;

        // disable all interrupts
        cli();

        key_mask &= key_rpt;    // read key(s)
        key_rpt ^= key_mask;    // clear key(s)

        SREG = sreg;    // restore status register

        return key_mask;
}


//--------------------------------------------------------------
//
uint8_t get_key_long_rpt (uint8_t key_mask)
{
        uint8_t sreg = SREG;

        // disable all interrupts
        cli();

        key_mask &= key_lrpt;   // read key(s)
        key_lrpt ^= key_mask;   // clear key(s)

        SREG = sreg;    // restore status register

        return get_key_rpt (~key_press^key_mask);
}


//--------------------------------------------------------------
//
uint8_t get_key_long_rpt_sp (uint8_t key_mask, uint8_t key_speed)
{
        uint8_t sreg = SREG;

        // disable all interrupts
        cli();

        key_mask &= key_rpts;   // read key(s)
        key_rpts ^= key_mask;   // clear key(s)

        repeat_speed = key_speed;

        SREG = sreg;    // restore status register

        return key_mask;
}

void set_beep ( uint16_t Time, uint16_t Muster, uint8_t Prio)
{

  if (Prio == BeepNormal)
    {
      if (BeepPrio == BeepNormal)        // nur setzen wenn keine hohe Prio schon aktiv ist
        {
        BeepTime = Time;
        BeepMuster = Muster;
        }
    }

  if (Prio == BeepSevere)
    {
      if (!BeepPrio == BeepSevere)
        {
          BeepPrio = BeepSevere;             // hohe Prio setzen
          BeepTime = Time;
          BeepMuster = Muster;
        }
    }

  if (Prio == BeepOff)
    {
      BeepPrio = BeepNormal;             // Beep hohe Prio aus
      BeepTime = 0;
      BeepMuster = 0;
    }


}