Subversion Repositories Projects

Rev

Rev 2136 | Blame | Last modification | View Log | RSS feed

/*****************************************************************************
 *   Copyright (C) 2013 Oliver Gemesi                                        *
 *                                                                           *
 *   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.               *
 *****************************************************************************/


//############################################################################
//# HISTORY  scrollbox.c
//#
//# 31.05.2014 OG
//# - chg: ScrollBox_Refresh() - umgestellt auf PKT_KeylineUpDown()
//#
//# 29.03.2014 OG
//# - chg: ScrollBox_Show() umgestellt auf clear_key_all()
//#
//# 22.05.2013 OG
//# - fix: include pkt/pkt.h
//#
//# 19.05.2013 OG
//# - chg: ScrollBox_Show() erweitert um PKT_CtrlHook() um u.a. PKT-Updates
//#        zu ermoeglichen
//#
//# 04.05.2013 OG
//# - chg: angepasst auf xutils.c
//#
//# 28.04.2013 OG
//# - add: ScrollBox_Push() - Variante fuer 'format' im RAM
//# - chg: ScrollBox_Push_P() -> keine Rueckgabe mehr (void)
//# - chg: auf xprintf umgestellt (siehe utils/xstring.c)
//# - add: verschiedene Beschreibungen ueber Funktionen
//#
//# 20.04.2013 OG - NEU
//############################################################################

//#define USE_SCROLLBOX_DEBUG       // Debug-Funktionen einkompilieren/aktivieren (gesendet wird an uart1)

#include "../cpu.h"
#include <avr/pgmspace.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>

#include "../main.h"
#include "../lcd/lcd.h"
#include "../eeprom/eeprom.h"
#include "../messages.h"
#include "../pkt/pkt.h"
#include "../utils/xutils.h"        // xprintf
#include "scrollbox.h"

// Debug
#ifdef USE_SCROLLBOX_DEBUG
  #include "../uart/uart1.h"
  #include <util/delay.h>
#endif

#define SCROLLBOX_ALLOC_MEM         // dynamische RAM-Belegen (malloc) verwenden?   (Standardeinstellung: ja)

#define SCROLLBOX_LINESIZE  20+1    // Ausgabezeile der ScrollBox (20 Chars + 0x00)
#define SCROLLBOX_KEYSIZE   4+1     // Textlabel einer Taste (4 Chars + 0x00)

#define SCROLLBOX_W         20      // Textbreite
#define SCROLLBOX_H         7       // Textzeilen
#define MSBLINE             10      // drawmode-code fuer: Linie




//-----------------------------------------------------------
// statischer Speicher wenn nicht SCROLLBOX_ALLOC_MEM
// verwendet wird
//-----------------------------------------------------------
#ifndef SCROLLBOX_ALLOC_MEM
    #define SCROLLBOX_BUFFER_SIZE                   2048    // 2 KByte - ram-size in bytes
    char scrollbox_buffer[SCROLLBOX_BUFFER_SIZE];
#endif


//-----------------------------------------------------------
// typedef: scrollbox_key_t
//-----------------------------------------------------------
typedef struct
{
    uint8_t     active;                         // Taste aktiv? (true/false)
    char        text[SCROLLBOX_KEYSIZE];        // Tastentext
}  scrollbox_key_t;


//-----------------------------------------------------------
// typedef: scrollbox_line_t
//-----------------------------------------------------------
typedef struct
{
    uint8_t     mode;                           // drawmode: MNORMAL, MINVERSE oder MSBLINE
    char        line[SCROLLBOX_LINESIZE];       // malloc: lines * 21 bytes (20 chars + 0)
}  scrollbox_line_t;


//-----------------------------------------------------------
// typedef: scrollbox_t
//-----------------------------------------------------------
typedef struct
{
    scrollbox_line_t    *buffer;                // malloc: lines * 22 bytes (21 chars + 0)
    uint8_t             maxlines;               // max. reservierte Lines (malloc buffer)
    uint8_t             lines;                  // Anzahl gepushte lines
    uint8_t             display_pos;            // aktuelle obere Anzeigezeile
    scrollbox_key_t     key_enter;
    scrollbox_key_t     key_enter_long;
}  scrollbox_t;


//-----------------------------------------------------------
// Buffer & Co.
//-----------------------------------------------------------
scrollbox_t     scrollbox;
char            buffer_sbline[SCROLLBOX_LINESIZE];


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



//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
#ifdef USE_SCROLLBOX_DEBUG
//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
//--------------------------------------------------------------
// nur wenn define: USE_SCROLLBOX_DEBUG
//--------------------------------------------------------------
void ScrollBox_Debug( void )
{
    char s[33];
    uint8_t i,j;
    char *p;
    scrollbox_line_t *sboxp;
    uint32_t h;

    uart1_puts_p( PSTR("\r\nScrollBox_Debug: BEGIN\r\n\r\n") );

    ltoa( scrollbox.buffer, s, 16);
    uart1_puts_p( PSTR("address: buffer          = 0x") );
    uart1_puts( s );
    ltoa( scrollbox.buffer, s, 10);
    uart1_puts( " (" );
    uart1_puts( s );
    uart1_puts( ")\r\n" );

    ltoa( scrollbox_buffer, s, 16);
    uart1_puts_p( PSTR("address: scrollbox_buffer  = 0x") );
    uart1_puts( s );
    ltoa( scrollbox.buffer, s, 10);
    uart1_puts( " (" );
    uart1_puts( s );
    uart1_puts( ")\r\n" );


    itoa( sizeof(scrollbox_line_t), s, 10);
    uart1_puts_p( PSTR("sizeof(scrollbox_line_t) = ") );
    uart1_puts( s );
    uart1_puts( "\r\n" );

    uart1_puts( "\r\n" );

    itoa( scrollbox.lines, s, 10);
    uart1_puts_p( PSTR("scrollbox.lines = ") );
    uart1_puts( s );
    uart1_puts( "\r\n" );

    itoa( scrollbox.maxlines, s, 10);
    uart1_puts_p( PSTR("scrollbox.maxlines = ") );
    uart1_puts( s );
    uart1_puts( "\r\n" );

    itoa( scrollbox.display_pos, s, 10);
    uart1_puts_p( PSTR("scrollbox.display_pos = ") );
    uart1_puts( s );
    uart1_puts( "\r\n" );

    uart1_puts( "\r\n" );

    for(i=0; i<scrollbox.lines; i++)
    {
        itoa( i, s, 10);
        if( strlen(s)<2 ) uart1_puts( " " );
        uart1_puts( s );
        uart1_puts( ": " );

        //sboxp = scrollbox.buffer + sizeof(scrollbox_line_t)*i;
        sboxp = scrollbox.buffer + i;

        ltoa( sboxp, s, 16); // hex
        uart1_puts( "[0x" );
        uart1_puts( s );
        uart1_puts( "]" );

        ltoa( sboxp, s, 10); // dec
        uart1_puts( "[" );
        uart1_puts( s );
        uart1_puts( "] " );

        itoa( sboxp->mode, s, 10);
        if( strlen(s)<2 ) uart1_puts( " " );
        uart1_puts( s );
        uart1_puts( ": " );

        p = sboxp->line;

        if( sboxp->mode != 10 )
        {
            uart1_puts( p );
        }

        uart1_puts( "|\r\n" );
    }

    //--------------------------------------------------------------
    // Hier wird fuer eine gewisse Zeit (insgesamt 2500 mal) permanent die Zeile 23 ausgegeben.
    // Wenn ich das richtig sehe schreibe ich hierbei nicht ;-)
    // Aber was sagt das Empfangsterminal....
    //--------------------------------------------------------------
    sboxp = scrollbox.buffer + 23;
    for( h=0; h<10; h++)
    {
        itoa( h, s, 10);
        uart1_puts( s );
        uart1_puts( "# " );

        uart1_puts( sboxp->line );
        uart1_puts( "|\r\n" );
        _delay_ms(10);
    }
    //--------------------------------------------------------------

    uart1_puts_p( PSTR("\r\nScrollBox_Debug: END\r\n") );
    uart1_puts( "##########################################\r\n\r\n" );
}
//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
#endif // USER_SCROLLBOX_DEBUG
//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx



//--------------------------------------------------------------
// ok = ScrollBox_Create( uint8_t maxlines )
//
// Rueckgabe:
//   true  = ok
//   false = kein Speicher
//
// - reserviert speicher fuer max. maxlines
// - initialisiert scrollbox-Datenstruktur
//--------------------------------------------------------------
uint8_t ScrollBox_Create( uint8_t maxlines )
{
    scrollbox.buffer = 0;

    #ifdef SCROLLBOX_ALLOC_MEM
        scrollbox.buffer = malloc( maxlines * sizeof(scrollbox_line_t));
        //scrollbox.buffer = calloc( maxlines, sizeof(scrollbox_line_t) );
    #else
        scrollbox.buffer = (scrollbox_line_t *) scrollbox_buffer;
    #endif

    if( !scrollbox.buffer ) // kein RAM mehr
    {
        lcd_cls();
        lcd_printp_at( 1, 3, PSTR("Error: ScrollBox"), MNORMAL);
        lcd_printp_at( 1, 4, PSTR("No more RAM"), MNORMAL);
        set_beep ( 500, 0x3333, BeepNormal);
        while (!get_key_short (1 << KEY_ESC));
        return false;
    }

    scrollbox.maxlines      = maxlines;
    scrollbox.lines         = 0;
    scrollbox.display_pos   = 0;

    scrollbox.key_enter.active      = false;
    scrollbox.key_enter_long.active = false;
    return true;
}



//--------------------------------------------------------------
// ScrollBox_Destroy()
//
// gibt reservierten Speicher wieder frei
// Wichtig! Da malloc verwendet wird!
//--------------------------------------------------------------
void ScrollBox_Destroy( void )
{
    if( scrollbox.buffer )
    {
        #ifdef SCROLLBOX_ALLOC_MEM
        free( scrollbox.buffer );
        #endif
    }
    scrollbox.buffer = 0;
}


//--------------------------------------------------------------
// ScrollBox_PushLine()
//
// fuegt eine Trennlinie hinzu
//--------------------------------------------------------------
void ScrollBox_PushLine( void )
{
    scrollbox_line_t *sboxp;

    if( scrollbox.lines < scrollbox.maxlines )
    {
        sboxp = scrollbox.buffer + scrollbox.lines;
        sboxp->mode = MSBLINE;
        scrollbox.lines++;
    }
}



//--------------------------------------------------------------
// _scrollbox_push(...)
//
// intern fuer: ScrollBox_Push_P(), ScrollBox_Push()
// Beschreibung siehe dort
//--------------------------------------------------------------
void _scrollbox_push( uint8_t useprogmem, uint8_t mode, const char *format, va_list ap )
{
    scrollbox_line_t *sboxp;

    if( scrollbox.lines < scrollbox.maxlines )
    {
        sboxp = scrollbox.buffer + scrollbox.lines;

        _xvsnprintf( useprogmem, buffer_sbline, SCROLLBOX_LINESIZE, format, ap);

        strncpyfill( sboxp->line, buffer_sbline, SCROLLBOX_LINESIZE);   // copy: buffer_sbline zur scrollbox
        sboxp->mode  = mode;

        scrollbox.lines++;
    }
}



//--------------------------------------------------------------
// ScrollBox_Push_P( mode, format, ...)
//
// Textzeile hinzufuegen - 'format' ist im PROGMEM.
//
// Parameter:
//   mode   : MNORMAL, MINVERS
//   format : siehe xprint-Doku in utils/xstring.c
//   ...    : Parameterliste fuer 'format'
//--------------------------------------------------------------
void ScrollBox_Push_P( uint8_t mode, const char *format, ... )
{
    va_list ap;

    va_start(ap, format);
    _scrollbox_push( true, mode, format, ap);
    va_end(ap);
}


//--------------------------------------------------------------
// ScrollBox_Push( mode, format, ...)
//
// Textzeile hinzufuegen - 'format' ist im RAM.
//
// Parameter:
//   mode   : MNORMAL, MINVERS
//   format : siehe xprint-Doku in utils/xstring.c
//   ...    : Parameterliste fuer 'format'
//--------------------------------------------------------------
void ScrollBox_Push( uint8_t mode, const char *format, ... )
{
    va_list ap;

    va_start(ap, format);
    _scrollbox_push( false, mode, format, ap);
    va_end(ap);
}


//--------------------------------------------------------------
// key: KEY_ENTER, KEY_ENTER_LONG  (keine weiteren bisher!)
//--------------------------------------------------------------
void ScrollBox_SetKey( uint8_t key, const char *keytext )
{
    if( key == KEY_ENTER )
    {
        scrollbox.key_enter.active   = true;
        strncpyfill( scrollbox.key_enter.text, keytext, SCROLLBOX_KEYSIZE);
    }

    if( key == KEY_ENTER_LONG )
    {
        scrollbox.key_enter_long.active = true;
        strncpyfill( scrollbox.key_enter_long.text, keytext, SCROLLBOX_KEYSIZE);
    }
}



//--------------------------------------------------------------
// ScrollBox_Refresh()
//
// zeigt die ScrollBox - wird normalerweise von ScrollBox_Show()
// automatisch durchgefuehrt
//--------------------------------------------------------------
void ScrollBox_Refresh( void )
{
    uint8_t y;
    uint8_t sh;
    uint8_t sy;
    scrollbox_line_t *sboxp;

    //--------------------------
    // Text
    //--------------------------
    for( y=0; y<7; y++)
    {
        sboxp = scrollbox.buffer + (scrollbox.display_pos + y);

        if( y + scrollbox.display_pos < scrollbox.lines )
        {

            if( sboxp->mode == MSBLINE )
            {
                lcd_frect( (21-SCROLLBOX_W)*6, (y*8), (SCROLLBOX_W*6), 7, 0);   // clear
                lcd_line ( (21-SCROLLBOX_W)*6, (y*8)+3, 125, (y*8)+3, 1);       // line
            }
            else
            {
                lcd_puts_at( 21-SCROLLBOX_W, y, sboxp->line, sboxp->mode);
            }
            //p += sizeof(scrollbox_line_t);
        }
        else    // clear
        {
              lcd_frect( (21-SCROLLBOX_W)*6, (y*8), (SCROLLBOX_W*6), 7, 0); // clear
        }
    }


    //--------------------------
    // Slider
    //--------------------------
    #define SLIDERH   55                                                // Finetuning der Slider-Hoehe

    // Slider: 7 zeilen * 8 pixel = 56 pixel
    sh = (SLIDERH * 7) / scrollbox.lines;                               // Slider: Hoehe
    sh = (sh > SLIDERH) ? SLIDERH : sh;

    sy = (scrollbox.display_pos * (SLIDERH-sh)) / (scrollbox.lines-7);  // Slider: Position

    lcd_frect( 0,  0, 1, SLIDERH, 0);                                   // Slider: Clear
    lcd_frect( 0, sy, 1, sh, 1);    // Slider: draw                     // Slider: Draw


    //--------------------------
    // Keyline
    //--------------------------
    PKT_KeylineUpDown( 1, 7,  0,0);                                     // Keyline: Up / Down
    lcd_printp_at( 12, 7, strGet(ENDE), MNORMAL);                       // Keyline: Ende

    if( scrollbox.key_enter.active )            lcd_print_at (17, 7, (uint8_t *)scrollbox.key_enter.text     , MNORMAL);
    else if ( scrollbox.key_enter_long.active ) lcd_print_at (17, 7, (uint8_t *)scrollbox.key_enter_long.text, MNORMAL);
    else                                        lcd_printp_at(17, 7, PSTR("    ")  , MNORMAL);

    //ScrollBox_Debug();
}


//--------------------------------------------------------------
// key = ScrollBox_Show()
//
//--------------------------------------------------------------
uint8_t ScrollBox_Show( void )
{
    uint8_t keyexit = 0;

    clear_key_all();

    if( scrollbox.buffer )
    {
        ScrollBox_Refresh();

        do
        {
            //--------------------------
            // Pruefe auf PKT-Update und
            // andere interne PKT-Aktionen
            //--------------------------
            if( PKT_CtrlHook() )                  // Update vom Updatetool angefordert?
            {
                lcd_cls();
                ScrollBox_Refresh();
            }

            //--------------------------
            // scrollen: nach unten
            //--------------------------
            if( get_key_press(1 << KEY_PLUS) || get_key_long_rpt_sp( (1 << KEY_PLUS),2 ))       // down
            {
                if( scrollbox.display_pos < ( scrollbox.lines - SCROLLBOX_H) )
                {
                    scrollbox.display_pos++;
                    ScrollBox_Refresh();
                }
                else
                {
                    set_beep ( 25, 0xffff, BeepNormal);                                         // am unteren Ende angelangt
                }
            }

            //--------------------------
            // scrollen: nach oben
            //--------------------------
            if( get_key_press(1 << KEY_MINUS) || get_key_long_rpt_sp( (1 << KEY_MINUS),2 ))     // up
            {
                if( scrollbox.display_pos > 0 )
                {
                    scrollbox.display_pos--;
                    ScrollBox_Refresh();
                }
                else
                {
                    set_beep ( 25, 0xffff, BeepNormal);                                         // am oberen Ende angelangt
                }
            }

            //--------------------------
            //--------------------------
            if( scrollbox.key_enter.active && get_key_short(1 << KEY_ENTER) )
            {
                keyexit = KEY_ENTER;
            }

            //--------------------------
            //--------------------------
            if( scrollbox.key_enter_long.active && get_key_long(1 << KEY_ENTER) )
            {
                keyexit = KEY_ENTER_LONG;
            }

        } while( !get_key_press(1 << KEY_ESC) && (keyexit == 0) );
    }

    //get_key_press(KEY_ALL);   // ersetzt durch obiges clear_key_all()

    return keyexit;
}