Subversion Repositories Projects

Rev

Rev 2136 | 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*
 *****************************************************************************/


//############################################################################
//# HISTORY  mksettings.c
//#
//# 14.05.2014 OG
//# - chg: include "mkbase.h" geaendert auf "../mk/mkbase.h"
//#
//# 11.05.2014 OG
//# - chg: MKSettings_Menu() umgestellt auf MenuCtrl_SetTitleFromParentItem()
//#        -> die Menues 'erben' damit ihren Titel vom aufrufenden Menuepunkt
//#
//# 29.03.2014 OG
//# - chg: versch. Funktionen: del: MenuCtrl_SetShowBatt() wegen Aenderung
//#        des Defaults auf true
//#
//# 26.03.2014 OG
//# - add: etliche Aenderungen in allen Bereichen fuer das erste Release
//#        der neuen MK-Settings
//#
//# 27.02.2014 OG
//# - chg: MKSettings_AskAction() Unterstuetzung von param_DUMMY
//#
//# 26.02.2014 OG
//# - chg: MKSettings_Copy() auf KEYLINE2 geaendert
//#
//# 23.02.2014 OG
//# - chg: MKSettings_Menu() Aufruf von MK_Parameters() geaendert
//#
//# 18.02.2014 OG - NEU
//############################################################################


#include "../cpu.h"
#include <avr/io.h>
#include <inttypes.h>
#include <stdlib.h>
#include <avr/pgmspace.h>
#include <avr/wdt.h>
#include <util/delay.h>
#include <avr/eeprom.h>
#include <util/delay.h>
#include <string.h>
#include <util/atomic.h>

//#include "../lipo/lipo.h"
#include "../main.h"
#include "../lipo/lipo.h"
#include "../lcd/lcd.h"
#include "../uart/usart.h"
#include "../utils/menuctrl.h"
#include "../utils/xutils.h"

#include "../uart/uart1.h"
#include "../mk-data-structs.h"
//#include "../menu.h"
#include "../timer/timer.h"
#include "../eeprom/eeprom.h"
#include "../messages.h"
#include "../pkt/pkt.h"
#include "../mk/mkbase.h"
#include "paramset.h"
#include "mkparameters.h"
#include "mksettings.h"

//---------------------------------------------------------------------------------------------

#define F_EXIT      0
#define F_REFRESH   1

char mksettings_menu_names[6][18];      // befuellt von: MKSettings_read_Names()


//-------------------------------------
//-------------------------------------
typedef struct
{
    unsigned char   paramsetRevision;       // Revision FC-Parameterset fuer die das Temp-Setting gueltig ist
    unsigned char   *paramset;              // malloc: Pointer auf kopierte Parameter-Daten
} MKSetting_TMP_t;


MKSetting_TMP_t     MKSetting_TMP;


#define ID_SETTING_COPY     10      // fuer MKSettings_Menu()
#define ID_EDIT             20      // fuer MKSettings_AskAction()
#define ID_ACTIVATE         21      // fuer MKSettings_AskAction()
#define ID_COPY             22      // fuer MKSettings_AskAction()

#define ID_SAVE             30      // fuer MKSettings_AskSaveSetting()
#define ID_DISCARD          31      // fuer MKSettings_AskSaveSetting()


//#############################################################################################
//#
//#############################################################################################


//--------------------------------------------------------------
// MKSettings_TMP_Init0()
//
// nur fuer main.c
//--------------------------------------------------------------
void MKSettings_TMP_Init0( void )
{
    memset( &MKSetting_TMP, 0, sizeof(MKSetting_TMP_t) );
    strcpy( mksettings_menu_names[5], "PKT: --empty--");
}



//--------------------------------------------------------------
// MKSettings_TMP_Init()
//
// loeschen / initialisieren vom PKT Temp-Setting
//--------------------------------------------------------------
void MKSettings_TMP_Init( void )
{
    if( MKSetting_TMP.paramset != NULL )
    {
        free( MKSetting_TMP.paramset );
    }
    MKSettings_TMP_Init0();
}



//--------------------------------------------------------------
// from_setting = 6 :  von TMP zu einem MK-Setting
// from_setting <= 5:  von MK-Setting zu TMP
//--------------------------------------------------------------
uint8_t MKSettings_TMP_copy( uint8_t to_setting, uint8_t timeout )
{
    uint8_t written;
    uint8_t size    = paramsetSize();

    if( MKSetting_TMP.paramset == NULL )
    {
        MKSetting_TMP.paramset = malloc( size+1 );                                  // +1 fuer das erste settings-byte
    }

    if( !MKSetting_TMP.paramset )
    {
        //PKT_Message_P( *text, error, timeout, beep, clearscreen )
        PKT_Message_P( PSTR("NO RAM!"), true, 800, true, true );                    // FEHLER!  (NO RAM)
        return 0;                                                                   // -> EXIT
    }

    // von MK-Setting 1..5 zu TMP
    if( to_setting == 6 )
    {
        MKSetting_TMP.paramsetRevision = MKVersion.paramsetRevision;
        memcpy( MKSetting_TMP.paramset, (unsigned char *)(pRxData), size+1 );       // memcpy( dst, src, size))
        return 6;
    }

    // von TMP zu MK-Setting 1..5
    memcpy( (unsigned char *)(pRxData), MKSetting_TMP.paramset , size+1 );          // memcpy( dst, src, size))
    written = MK_Setting_write( to_setting, timeout);
    return written;
}



//#############################################################################################
//#
//#############################################################################################

//--------------------------------------------------------------
//--------------------------------------------------------------
uint8_t MKSettings_read_Names( void )
{
    uint8_t setting;

    // die 5 Settings vom Kopter laden um die
    // Setting-Namen zu speichern
    for( setting=1; setting <= 5; setting++ )
    {
        if( !MK_Setting_load( setting, 20 ) )
            return(0);                                  // Fehler - setting konnte nicht geladen werden  (timeout = 20)
        xsnprintf( mksettings_menu_names[setting-1], 16, "%1d: %s", setting, paramGet_p(param_Name) );
    }

    // TMP-Setting
    if( MKSetting_TMP.paramset != NULL )
    {
        if( MKSetting_TMP.paramsetRevision != MKVersion.paramsetRevision )
        {
            // wenn die FC-Revision vom TMP-Setting abweicht vom zuletzt geladenen
            // dann wurde ggf. der Kopter gewechselt -> TMP-Setting verwerfen
            MKSettings_TMP_Init();
        }
        else
        {
            // den Namen aus dem TMP-Setting holen
            paramsetInit( MKSetting_TMP.paramset );
            xsnprintf( mksettings_menu_names[5], 16, "PKT: %s", paramGet_p(param_Name) );
        }
    }

    setting = MK_Setting_load( 0xff, 20);                               // aktuelles MK Setting ermitteln

    return setting;
}



//--------------------------------------------------------------
// wahl = MKSettings_AskAction( setting)
//
// Rueckgabe:
//  0 (==Ende), ID_EDIT, ID_ACTIVATE, ID_COPY
//--------------------------------------------------------------
uint8_t MKSettings_AskAction( uint8_t setting )
{
    uint8_t wahl = 0;

    //-----------------
    // Menue erstellen
    //-----------------
    MenuCtrl_Create();
    MenuCtrl_SetTitle( mksettings_menu_names[setting-1] );                          // Menuetitel ist der Settingname
    MenuCtrl_ShowLevel(false);
    MenuCtrl_SetTopSpace(1);                                                        // oben beim Menue eine Leerzeile einfuegen

    //-----------------
    // Menueeintraege
    //-----------------
    if( !paramExist(param_DUMMY) )                                                  // param_DUMMY -> das Parameterset wird nicht zum bearbeiten unterstuetzt
        MenuCtrl_Push_P( ID_EDIT    , MENU_ITEM, NOFUNC, strGet(EDIT_SETTING) );    // "Setting ändern"

    if( setting != 6)
        MenuCtrl_Push_P( ID_ACTIVATE, MENU_ITEM, NOFUNC, strGet(PARA_AKTIVI) );     // "aktivieren"

    MenuCtrl_Push_P( ID_COPY    , MENU_ITEM, NOFUNC, strGet(STR_COPY) );            // "kopieren"

    //-----------------
    // Menue Control
    //-----------------
    MenuCtrl_Control( MENUCTRL_EVENT );

    if( MenuCtrl_GetKey() != KEY_ESC )
        wahl = MenuCtrl_GetItemId();                                                // welcher Menu-Punkt (ID_CHANGE, ID_ACTIVATE)

    MenuCtrl_Destroy();
    MenuCtrl_ShowLevel(true);

    return wahl;            // 0=Ende; ID_EDIT; ID_ACTIVATE, ID_COPY
}



//--------------------------------------------------------------
// wahl = MKSettings_AskSaveSetting( setting)
//
// Rueckgabe:
//  0 (==Ende), ID_SAVE, ID_DISCARD
//--------------------------------------------------------------
uint8_t MKSettings_AskSaveSetting( uint8_t setting )
{
    uint8_t wahl = 0;

    //-----------------
    // Menue erstellen
    //-----------------
    MenuCtrl_Create();
    MenuCtrl_SetTitle( mksettings_menu_names[setting-1] );                          // Menuetitel ist der Settingname
    MenuCtrl_ShowLevel(false);
    MenuCtrl_SetTopSpace(1);                                                        // oben beim Menue eine Leerzeile einfuegen

    //-----------------
    // Menueeintraege
    //-----------------
    MenuCtrl_Push_P( ID_SAVE    , MENU_ITEM, NOFUNC, strGet(STR_SAVE) );            // "speichern"
    MenuCtrl_Push_P( ID_DISCARD , MENU_ITEM, NOFUNC, strGet(STR_DISCARD) );         // "verwerfen"


    //-----------------
    // Menue Control
    //-----------------
    MenuCtrl_Control( MENUCTRL_EVENT );

    if( MenuCtrl_GetKey() != KEY_ESC )
        wahl = MenuCtrl_GetItemId();                                                // welcher Menu-Punkt (ID_CHANGE, ID_ACTIVATE)

    MenuCtrl_Destroy();
    MenuCtrl_ShowLevel(true);

    return wahl;            // 0=Ende; ID_EDIT; ID_ACTIVATE, ID_COPY
}



//--------------------------------------------------------------
//--------------------------------------------------------------
uint8_t MKSettings_Copy( uint8_t from_setting )
{
    const char *mask = PSTR("%15s");
    uint8_t redraw      = true;
    uint8_t loaded      = 0;
    uint8_t to_setting;
    uint8_t written;
    uint8_t key;
    int8_t  yoffs;


    lcd_cls();

    to_setting = from_setting;

    while( true )
    {
        //------------------------
        // anzeigen
        //------------------------
        if( redraw )
        {
            lcd_frect( 0, 0, 127, 7, 1);                                        // Titel: Invers
            lcd_printp_at( 1, 0, strGet(PARA_COPY), MINVERS);

            yoffs = -1;
            lcdx_printp_at( 0, 2, strGet(STR_VON), MNORMAL,  0,yoffs);          // "von"
            lcdx_printf_at_P( 5, 2, MNORMAL, 3,yoffs, mask, mksettings_menu_names[from_setting-1] );

            yoffs = -7;
            lcd_frect( 5*6, 4*8+yoffs, 15*6, 7, 0);
            lcdx_printp_at( 0, 4, strGet(STR_NACH), MNORMAL,  0,yoffs);         // "nach"
            lcdx_printf_at_P( 5, 4, MNORMAL, 3,yoffs, mask, mksettings_menu_names[to_setting-1] );

            lcd_printp_at(0, 7, strGet(KEYLINE2), MNORMAL);                     // Keyline:  <-  ->  Ende  OK

            redraw = false;
        }

        //------------------------
        // Tasten abfragen
        //------------------------
        if( get_key_press(1 << KEY_ESC) )
        {
            return 99;  // nur "ENDE"
        }

        if( get_key_press(1 << KEY_PLUS) )
        {
            if( to_setting == 6 )   to_setting = 1;
            else                    to_setting++;
            redraw = true;
        }

        if( get_key_press(1 << KEY_MINUS) )
        {
            if( to_setting == 1 )   to_setting = 6;
            else                    to_setting--;
            redraw = true;
        }

        //-------------------------------
        // Taste: OK = Setting kopieren?
        //-------------------------------
        if( get_key_press(1 << KEY_ENTER) )
        {
            lcdx_printp_center( 5, strGet(PARA_COPYQ), MNORMAL, 0,1);           // "Wirklich kopieren?" (zentriert)
            lcd_rect_round( 0, 5*8-3, 127, 7+7, 1, R2);                         // Rahmen um die Frage

            lcd_frect( 0, 7*8, 127, 7, 0);                                      // Keyline loeschen
            lcd_printp_at(12, 7, strGet(NOYES), MNORMAL);                       // neue Keyline: "Nein   Ja"

            set_beep( 25, 0xffff, BeepNormal );                                 // kurzer Beep

            key = 0;
            while( !key )                                                       // Abfrage: Ja / Nein
            {
                key = get_key_press(1 << KEY_ENTER) ? KEY_ENTER : key;          // => "Ja" (=Setting kopieren)
                key = get_key_press(1 << KEY_ESC)   ? KEY_ESC   : key;          // => "Nein"
                PKT_CtrlHook();
            }

            //---------------------------
            // "Ja" -> Setting kopieren!
            //---------------------------
            if( key == KEY_ENTER )                                              // => "Ja" -> Setting kopieren!
            {
                if( from_setting != 6 )                                             // kein PKT TMP-Setting
                {
                    loaded = MK_Setting_load( from_setting, 20 );                   // timeout = 20

                    if( loaded != from_setting )                                        // Fehler beim laden - Datenverlust?
                    {
                        //PKT_Message_P( *text, error, timeout, beep, clearscreen )
                        PKT_Message_P( strGet(ERROR_NODATA), true, 800, true, true );   // "Datenverlust!" (max. 8 Sekunden anzeigen)
                        return 0;                                                       // 0 = Ende/Abbruch
                    }
                }

                if( to_setting == 6 )                                               // von Setting 1..5 nach TMP speichern
                {
                    MKSettings_TMP_copy( 6, 10 );
                    return loaded;
                }

                // Anzeige "speichern..."
                lcd_frect( 0, (8*4), 128, (8*4), 0);                            // Anzeigebereich löschen
                lcdx_printp_center( 4, strGet(STR_SAVING), MNORMAL, 0,9);       // Text zentriert; String in PROGMEM
                lcd_rect_round( 0, 37, 127, 14, 1, R2);                         // Rahmen


                if( from_setting == 6 )                                             // von TMP nach Setting 1..5
                {
                    written = MKSettings_TMP_copy( to_setting, 30 );
                    return written;
                }


                if( to_setting <= 5 )                                               // 'echtes' MK Setting speichern
                {
                    written = MK_Setting_write( to_setting, 30 );                   // Timeout = 40
                    return written;
                }
            }

            if( key == KEY_ESC )    // => "Nein" -> nicht kopieren
            {
                lcd_cls();
                redraw = true;
            }

        }  //end: if( get_key_press(1 << KEY_ENTER) )


        //------------------------------------------
        // Pruefe PKT-Update oder andere PKT-Aktion
        //------------------------------------------
        if( PKT_CtrlHook() )                                                // Update vom Updatetool angefordert?
        {
            lcd_cls();
            redraw = true;
        }

    }  // end: while( true )

    return 0;
}



//--------------------------------------------------------------
// ret = MKSettings_Menu()
//
// Rueckgabe:
//  0 = Ende/Fehler/Abbruch
//  1 = Refresh
//--------------------------------------------------------------
uint8_t MKSettings_Menu( void )
{
    uint8_t i;
    uint8_t active_setting;
    uint8_t setting;
    uint8_t wahl;
    uint8_t wahl2;
    uint8_t changed;


    //PKT_Message_P( *text, error, timeout, beep, clearscreen )
    PKT_Message_P( strGet(MSG_LOADSETTINGS), false, 0, true, true );                    // "lade Settings..."


    active_setting = MKSettings_read_Names();

    if( !active_setting )                                                               // Fehler: settings konnten nicht geladen werden...
    {
        //PKT_Message_P( *text, error, timeout, beep, clearscreen )
        PKT_Message_P( strGet(ERROR_NODATA), true, 800, true, true );                   // "Datenverlust!" (max. 8 Sekunden anzeigen)
        return F_EXIT;                                                                  // F_EXIT = Ende/Abbruch
    }


    //---------------
    // Create
    //---------------
    MenuCtrl_Create();

    //---------------
    // Einstellungen
    //---------------
    MenuCtrl_SetTitleFromParentItem();          // "MK Settings"
  //MenuCtrl_SetTitle_P( PSTR("MK Settings") );
  //MenuCtrl_SetCycle( false );
  //MenuCtrl_SetShowBatt( true );


    //---------------
    // Menue-Punkte
    //---------------
    for( i=0; i< ( MKSetting_TMP.paramset!=NULL ? 6 : 5); i++ )
    {
        MenuCtrl_Push( i+1, MENU_SUB, NOFUNC, mksettings_menu_names[i] );               // Setting 1..5
    }

    MenuCtrl_ItemSelect( active_setting );                                              // Menucursor auf aktives Setting setzen
    MenuCtrl_ItemMark( active_setting, true);                                           // aktives Setting markieren


    //---------------
    // Control
    //---------------
    while( true )
    {
        MenuCtrl_Control( MENUCTRL_EVENT );

        if( MenuCtrl_GetKey() == KEY_ESC )                                      // Ende?
        {
            break;                                                              // Ende
        }

        setting = MenuCtrl_GetItemId();                                          // welcher Menu-Punkt (ID)

        if( setting >=1 && setting <= 6 )
        {
            wahl = MKSettings_AskAction( setting );

            //--------------
            // bearbeiten
            //--------------
            if( wahl == ID_EDIT )
            {
                // TODO: Fehler abfangen!
                MK_Setting_load( setting, 25 );                                         // timeout = 25
                changed = MK_Parameters( setting, mksettings_menu_names[setting-1] );

                if( changed && (setting!=6) )
                {
                    wahl2 = MKSettings_AskSaveSetting( setting );
                    if( wahl2 == ID_SAVE )
                    {
                        lcd_frect( 0, (8*7), 128, 7, 0);                                // Keyline löschen
                        lcdx_printp_center( 4, strGet(STR_SAVING), MNORMAL, 0,9);      // Text zentriert; String in PROGMEM
                        lcd_rect_round( 0, 37, 127, 14, 1, R2);                         // Rahmen

                        setting = MK_Setting_write( setting, 50);

                        if( !setting )
                        {
                            //PKT_Message_P( *text, error, timeout, beep, clearscreen )
                            PKT_Message_P( strGet(ERROR_NODATA), true, 800, true, true );           // FEHLER! nodata (max. 8 Sekunden anzeigen)
                            //MenuCtrl_Destroy();
                            //return F_EXIT;                                                      // F_EXIT = Ende/Abbruch
                        }
                    }
                }
            }


            //--------------
            // aktivieren
            //--------------
            if( wahl == ID_ACTIVATE )
            {
                //PKT_Message_P( *text, error, timeout, beep, clearscreen )
                PKT_Message_P( strGet(MSG_ACTIVATESETTING), false, 0, true, true );     // "aktiviere Setting..."

                active_setting = MK_Setting_change( setting );

                if( !active_setting )
                {
                    //PKT_Message_P( *text, error, timeout, beep, clearscreen )
                    PKT_Message_P( strGet(ERROR_NODATA), true, 800, true, true );       // FEHLER! nodata (max. 8 Sekunden anzeigen)
                    //MenuCtrl_Destroy();
                    //return F_EXIT;                                                      // F_EXIT = Ende/Abbruch
                }
                else
                {
                    // neues Setting markieren
                    for( i=1; i<=5; i++ ) MenuCtrl_ItemMark( i, false);                     // Markierungen loeschen
                    MenuCtrl_ItemMark( active_setting, true);                               // aktives Setting markieren
                }

            }  // end: if( wahl == ID_ACTIVATE )


            //--------------
            // kopieren
            //--------------
            if( wahl == ID_COPY )
            {
                active_setting = MKSettings_Copy( setting );

                if( !active_setting )
                {
                    //PKT_Message_P( *text, error, timeout, beep, clearscreen )
                    PKT_Message_P( strGet(ERROR_NODATA), true, 800, true, true );       // FEHLER! nodata (max. 8 Sekunden anzeigen)
                    //MenuCtrl_Destroy();
                    //return F_EXIT;                                                      // F_EXIT = Ende/Abbruch
                }

                if( active_setting != 99 )                                              // =99 bedeutet: User hat die Funktion abgebrochen...
                {
                    MenuCtrl_Destroy();                                                 // ok, kein Abbruch durch den User -> Menue neu aufbauen
                    return F_REFRESH;                                                   // da sich ggf. Settings-Namen geaendert haben
                }
            }  // end: if( wahl == ID_COPY )

        }

    }  // end: while( true )


    //---------------
    // Destroy
    //---------------
    MenuCtrl_Destroy();

    return F_EXIT;
}



//#############################################################################################
//#
//#############################################################################################


//--------------------------------------------------------------
// das muss ueberarbeitet werden....
//--------------------------------------------------------------
static uint8_t check_motorOff(void)
{
    NaviData_t *naviData;

    if( hardware == NC )  // Prüfung funktioniert nur mit NC
    {
        SwitchToNC();
        SendOutData( 'o', ADDRESS_NC, 1,  10, 1);
        mode = 'O';
        rxd_buffer_locked = FALSE;
        timer = 200;

        while( !rxd_buffer_locked && timer>0 );

        if( rxd_buffer_locked )                                 // naviData Ok?
        {
            // timer = MK_TIMEOUT;
            Decode64();
            naviData = (NaviData_t *) pRxData;

            if( naviData->FCStatusFlags & FC_STATUS_MOTOR_RUN )
                return false;
            else
                return true;
        }

        return false;
    }

    return true;    // hmm, wenn man nur eine FC hat dann wird hier immer gemeldet "Motoren sind aus" ?
}



//--------------------------------------------------------------
//--------------------------------------------------------------
void MK_Settings( void )
{
    //MKSettings_TMP_Init();

    //if( true )
    if( !check_motorOff() )
    {
         //PKT_Message_P( *text, error, timeout, beep, clearscreen )
        PKT_Message_P( strGet(STR_SWITCHMOTOROFF), false, 400, true, true );        // "Motoren ausschalten!"
        return;
    }

    while( MKSettings_Menu() == F_REFRESH );
}