Subversion Repositories Projects

Compare Revisions

Ignore whitespace Rev 2194 → Rev 2203

/Transportables_Koptertool/PKT/branches/branch_FollowMeStep2/utils/i2cmaster.h
0,0 → 1,178
#ifndef _I2CMASTER_H
#define _I2CMASTER_H 1
/*************************************************************************
* Title: C include file for the I2C master interface
* (i2cmaster.S or twimaster.c)
* Author: Peter Fleury <pfleury@gmx.ch> http://jump.to/fleury
* File: $Id: i2cmaster.h,v 1.10 2005/03/06 22:39:57 Peter Exp $
* Software: AVR-GCC 3.4.3 / avr-libc 1.2.3
* Target: any AVR device
* Usage: see Doxygen manual
**************************************************************************/
 
#ifdef DOXYGEN
/**
@defgroup pfleury_ic2master I2C Master library
@code #include <i2cmaster.h> @endcode
@brief I2C (TWI) Master Software Library
 
Basic routines for communicating with I2C slave devices. This single master
implementation is limited to one bus master on the I2C bus.
 
This I2c library is implemented as a compact assembler software implementation of the I2C protocol
which runs on any AVR (i2cmaster.S) and as a TWI hardware interface for all AVR with built-in TWI hardware (twimaster.c).
Since the API for these two implementations is exactly the same, an application can be linked either against the
software I2C implementation or the hardware I2C implementation.
 
Use 4.7k pull-up resistor on the SDA and SCL pin.
Adapt the SCL and SDA port and pin definitions and eventually the delay routine in the module
i2cmaster.S to your target when using the software I2C implementation !
Adjust the CPU clock frequence F_CPU in twimaster.c or in the Makfile when using the TWI hardware implementaion.
 
@note
The module i2cmaster.S is based on the Atmel Application Note AVR300, corrected and adapted
to GNU assembler and AVR-GCC C call interface.
Replaced the incorrect quarter period delays found in AVR300 with
half period delays.
@author Peter Fleury pfleury@gmx.ch http://jump.to/fleury
 
@par API Usage Example
The following code shows typical usage of this library, see example test_i2cmaster.c
 
@code
 
#include <i2cmaster.h>
 
 
#define Dev24C02 0xA2 // device address of EEPROM 24C02, see datasheet
 
int main(void)
{
unsigned char ret;
 
i2c_init(); // initialize I2C library
 
// write 0x75 to EEPROM address 5 (Byte Write)
i2c_start_wait(Dev24C02+I2C_WRITE); // set device address and write mode
i2c_write(0x05); // write address = 5
i2c_write(0x75); // write value 0x75 to EEPROM
i2c_stop(); // set stop conditon = release bus
 
 
// read previously written value back from EEPROM address 5
i2c_start_wait(Dev24C02+I2C_WRITE); // set device address and write mode
 
i2c_write(0x05); // write address = 5
i2c_rep_start(Dev24C02+I2C_READ); // set device address and read mode
 
ret = i2c_readNak(); // read one byte from EEPROM
i2c_stop();
 
for(;;);
}
@endcode
 
*/
#endif /* DOXYGEN */
 
/**@{*/
 
#if (__GNUC__ * 100 + __GNUC_MINOR__) < 304
#error "This library requires AVR-GCC 3.4 or later, update to newer AVR-GCC compiler !"
#endif
 
#include <avr/io.h>
 
/** defines the data direction (reading from I2C device) in i2c_start(),i2c_rep_start() */
#define I2C_READ 1
 
/** defines the data direction (writing to I2C device) in i2c_start(),i2c_rep_start() */
#define I2C_WRITE 0
 
 
/**
@brief initialize the I2C master interace. Need to be called only once
@param void
@return none
*/
extern void i2c_init(void);
 
 
/**
@brief Terminates the data transfer and releases the I2C bus
@param void
@return none
*/
extern void i2c_stop(void);
 
 
/**
@brief Issues a start condition and sends address and transfer direction
@param addr address and transfer direction of I2C device
@retval 0 device accessible
@retval 1 failed to access device
*/
extern unsigned char i2c_start(unsigned char addr);
 
 
/**
@brief Issues a repeated start condition and sends address and transfer direction
 
@param addr address and transfer direction of I2C device
@retval 0 device accessible
@retval 1 failed to access device
*/
extern unsigned char i2c_rep_start(unsigned char addr);
 
 
/**
@brief Issues a start condition and sends address and transfer direction
If device is busy, use ack polling to wait until device ready
@param addr address and transfer direction of I2C device
@return none
*/
extern void i2c_start_wait(unsigned char addr);
 
/**
@brief Send one byte to I2C device
@param data byte to be transfered
@retval 0 write successful
@retval 1 write failed
*/
extern unsigned char i2c_write(unsigned char data);
 
 
/**
@brief read one byte from the I2C device, request more data from device
@return byte read from I2C device
*/
extern unsigned char i2c_readAck(void);
 
/**
@brief read one byte from the I2C device, read is followed by a stop condition
@return byte read from I2C device
*/
extern unsigned char i2c_readNak(void);
 
/**
@brief read one byte from the I2C device
Implemented as a macro, which calls either i2c_readAck or i2c_readNak
@param ack 1 send ack, request more data from device<br>
0 send nak, read is followed by a stop condition
@return byte read from I2C device
*/
extern unsigned char i2c_read(unsigned char ack);
#define i2c_read(ack) (ack) ? i2c_readAck() : i2c_readNak();
 
 
/**@}*/
#endif
Property changes:
Added: svn:mime-type
+text/plain
\ No newline at end of property
/Transportables_Koptertool/PKT/branches/branch_FollowMeStep2/utils/menuctrl.c
0,0 → 1,1501
/*****************************************************************************
* 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 menuctrl.c
//#
//# 11.06.2014 OG
//# - add: MenuCtrl_GetMenuIndex()
//#
//# 31.05.2014 OG
//# - chg: MenuCtrl_Refresh() - umgestellt auf PKT_KeylineUpDown()
//#
//# 14.05.2014 OG
//# - chg: include "../mk/paramset.h" geaendert auf "../mksettings/paramset.h"
//# - chg: include "../mk/mkparameters.h" geaendert auf "../mksettings/mkparameters.h"
//#
//# 11.05.2014 OG
//# - add: MenuCtrl_SetTitleFromParentItem()
//# - add: MenuCtrl_GetItemText(), MenuCtrl_IsItemTextPGM()
//# - chg: _MenuCtrl_Error() - auf PKT_Popup_P() umgestellt, Layout geaendert und
//# einen neuen Fehler (NOPARENTMENU) hinzugefuegt
//#
//# 09.05.2014 OG
//# - fix: MenuCtrl_Refresh() Anzeige von deaktivierten MK-Parametern (Favoriten)
//# Wenn MK-Paramketer-Menueeintraege deaktiviert sind werden sie vom
//# aktuellen MK-Parameterset nicht unterstuetzt - dennoch wurde der
//# aktuelle Wert des MK-Parameters im Menuepunkt (ganz rechts) angezeigt.
//# Das ist jetzt behoben - es wird kein Wert angezeigt (stattdessen "***")
//# und auch keine entsprechende editParam-Funktionen aufgerufen.
//#
//# 07.05.2014 OG
//# - add: MenuCtrl_PushSeparatorID()
//#
//# 06.05.2014 OG
//# - chg: MenuCtrl_Refresh() Keyline leicht angepasst
//# - chg: 'not possible' Anzeige (bei deaktiviertem Item) umgestellt auf
//# PKT_Popup_P()
//# - add: MenuCtrl_GetItemIdByIndex(), MenuCtrl_GetItemCount()
//#
//# 05.05.2014 OG
//# - chg: MenuCtrl_Control()
//# -> Unterstuetzung fuer: MenuCtrl_SetMove() - Menueeintraege verschieben
//# - chg: MenuCtrl_Refresh() - Anpassung Slider fuer MenuCtrl_SetDelete()
//# - add: MenuCtrl_SetDelete(), MenuCtrl_SetMove()
//# - add: _MenuCtrl_SwapItem()
//# - add: die Datenstruktur vom Menue wurde erweitert um die Eigenschaften
//# canMove und canDelete
//#
//# 17.04.2014 OG
//# - chg: MENUCTRL_MAXITEMS von 22 auf 28 erhoeht
//#
//# 30.03.2014 OG
//# - del: MenuCtrl_PushML_P(), MenuCtrl_PushML() (Umstellung Sprachen abgeschlossen)
//# - add: MenuCtrl_PushML2(), MenuCtrl_PushML2_P() fuer Umstellung von 3 auf 2 Sprachen
//#
//# 29.03.2014 OG
//# - chg: default MENUDEFAULT_SHOWBATT auf true umgestellt (=PKT-Batterie anzeigen)
//# - chg: MenuCtrl_Control() umgestellt auf clear_key_all()
//#
//# 24.03.2014 OG
//# - add: MenuCtrl_PushSeparator() - fuegt eine Trennlinie im Menue ein
//# - chg: MenuCtrl_Refresh() Codeoptimierung bzgl. topspace/Zeile loeschen/Slider
//# - fix: MenuCtrl_Control() es wurde zuoft ein Screen-Refresh durchgefuehrt
//#
//# 23.03.2014 OG
//# - add: Unterstuetzung fuer MK-Parameter-Edit (mkparameters.c)
//# - chg: MenuCtrl_Refresh() Unterstuetzung fuer MENU_PARAMEDIT
//# - add: MenuCtrl_PushParamEdit()
//# - add: paramset.h und mkparameters.h
//#
//# 04.03.2014 OG
//# - fix: MenuCtrl_Refresh() bei einem blauen Display (das ist wohl schneller
//# in der Anzeige als das S/W-Display) flackerte der Menue-Slider
//#
//# 17.02.2014 OG
//# - add: MenuCtrl_SetTopSpace()
//# - chg: MenuCtrl_Refresh() angepasst auf MenuCtrl_SetTopSpace()
//#
//# 15.02.2014 OG
//# - add: MenuCtrl_ItemSelect()
//#
//# 01.02.2014 OG
//# - chg: MENUCTRL_MAXITEMS von 16 auf 22 fuer MK_parameters
//# - fix: _MenuCtrl_Error() Anzeigezeit von Menu-Errors auf 8 Sekunden verlaengert
//# und Anzeige von "menuctrl.c"
//#
//# 07.07.2013 OG
//# - add: MenuCtrl_ItemMarkR() - Markiert einen Menueeintrag mit einem Haken am ENDE (Rechts)
//#
//# 24.05.2013 OG
//# - chg: MenuCtrl_Push... Funktionen vereinheitlicht mit internen Aenderungen
//# betrifft externe Funktionsaufrufe die geƤndert wurden
//# - chg: MenuCtrl_Refresh() Anpassungen und Optimierung
//# - add: MenuCtrl_ItemMark()
//# - del: MenuCtrl_PushSimple_P(), MenuCtrl_PushSimple()
//#
//# 23.05.2013 OG
//# - add: MenuCtrl_PushSimple_P(), MenuCtrl_PushSimple()
//# - fix: MenuCtrl_Control() Eventcode Rueckgabe bei KEY_ENTER
//#
//# 22.05.2013 OG
//# - fix: nach Aufruf einer Menuefunktion in MenuCtrl_Control() jetzt
//# get_key_press(KEY_ALL)
//#
//# 21.05.2013 OG
//# - add: MenuCtrl_ShowLevel()
//#
//# 20.05.2013 OG
//# - chg: MenuCtrl_Control() wieder mit get_key_press(KEY_ALL) ergaenzt
//# wenn aufgerufen mit MENUCTRL_EVENT oder erster Aufruf mit RETURN
//#
//# 20.05.2013 OG
//# - chg: Space am Anfang der Titelanzeige
//#
//# 19.05.2013 OG
//# - add: define MENU_SHOWLEVEL mit dem der aktuelle Menuelevel in der
//# Titelzeile angezeigt werden kann
//# - fix: Redraw-Logik bei MENUCTRL_RETURN
//# - chg: MenuCtrl_Control() erweitert um PKT_Update()
//#
//# 18.05.2013 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 <string.h> // memset
#include <stdarg.h>
 
#include "../main.h"
#include "../lcd/lcd.h"
#include "../eeprom/eeprom.h"
#include "../messages.h"
#include "../lipo/lipo.h"
#include "../menu.h"
#include "../pkt/pkt.h"
#include "../mksettings/paramset.h"
#include "../mksettings/mkparameters.h"
#include "menuctrl.h"
 
 
//#############################################################################################
//# internal defines & structs
//#############################################################################################
 
#define MENU_SHOWLEVEL false // Anzeige der Menue-Verschachtelungstiefe in der Titelzeile
// zeigt dem Benutzer wie weit er wieder zurueckspringen muss
// um in das Hauptmenue zu kommen
 
#define MENUDEFAULT_CYCLE false // cycle: wenn Menue am Ende dann wieder zum Anfang
#define MENUDEFAULT_SHOWBATT true // showbatt: zeigt PKT-Batterie im Menuetitel ganz rechts
#define MENUDEFAULT_BEEP true // beep: wenn Cursor ueber Ende/Anfang
 
 
#define MENUCTRL_MAXMENUES 6 // Anzahl max. verschachlteter Menues
//#define MENUCTRL_MAXITEMS 22 // Anzahl max. Menu-Items pro Menue (verbraucht Speicher)
//#define MENUCTRL_MAXITEMS 28 // Anzahl max. Menu-Items pro Menue (verbraucht Speicher)
#define MENUCTRL_MAXITEMS 34 // Anzahl max. Menu-Items pro Menue (verbraucht Speicher)
#define ERROR_NOMENU 1 // Errorcode
#define ERROR_MAXMENU 2 // Errorcode
#define ERROR_MAXITEM 3 // Errorcode
#define ERROR_NOITEM 4 // Errorcode
#define ERROR_NOPARENTMENU 5 // Errorcode
 
//-----------------------------------------------------------
// typedef: scrollbox_key_t
//-----------------------------------------------------------
typedef struct
{
uint8_t active; // Taste aktiv? (true/false)
const char *text; // Tastentext
void (*func)(void); // ggf. Funktions-Pointer (0=keine Funktion)
} menue_key_t;
 
 
//---------------------------
// typedef: einzelnes Menueitem
//---------------------------
typedef struct
{
uint8_t id;
uint8_t type; // MENU_ITEM, MENU_SUB, MENU_PARAMEDIT
uint8_t disabled; // true / false (deaktiviert einen Menuepunkt)
uint8_t mark; // true / false (markiert einen Menuepunkt Links '*')
uint8_t markR; // true / false (markiert einen Menuepunkt Rechts)
uint8_t textPGM; // true / false (true = text in PROGMEN; false = text im RAM)
uint8_t textcount; // 1 .. NUM_LANG
const char *text[NUM_LANG]; // de, en, nl (NUM_LANG aus messages.h)
void (*func)(void);
} menue_item_t;
 
 
//---------------------------
// typedef: Menueitem Liste
//---------------------------
typedef struct
{
uint8_t active; // aktives item
uint8_t itemcount; // Anzahl Items
uint8_t scroll_pos; // aktuelle obere Anzeigezeile
uint8_t display_pos; // aktuelle obere Anzeigezeile
uint8_t topspace; // obere Leerzeilen - default=0 (Vorsicht! ggf. nur bedingt einsetzbar bei Menues die ohne scrollen auskommen!)
uint8_t firstredraw; // true / false (flag fuer ein erstes redraw bei MENUCTRL_RETURN)
uint8_t cycle; // true / false
uint8_t showbatt; // true / false
uint8_t beep; // true / false
uint8_t canMove; // true / false
uint8_t canDelete; // false/0 = kein entfernen; true/1 = entfernen mit Nachfrage; 2 = entfernen ohne Nachfrage
uint8_t titlePGM; // true / false
const char *title; // Menuetitel (oberste Zeile) (ggf. Multisprache machen?)
uint8_t lastkey; // verwendet von GetKey()
menue_key_t key_enter;
menue_key_t key_enter_long;
menue_key_t key_esc;
menue_key_t key_esc_long;
menue_item_t item[MENUCTRL_MAXITEMS];
} menue_t;
 
uint8_t showlevel = MENU_SHOWLEVEL; // Anzeige Menulevel in der Titelanzeige
int8_t midx = -1; // aktives Menue; -1 = kein Menue
menue_t menu[MENUCTRL_MAXMENUES]; // Stack fuer n geschachltete Menues
 
 
 
//#############################################################################################
//# PRIVAT funcs
//#############################################################################################
 
 
//--------------------------------------------------------------
// INTERN
//--------------------------------------------------------------
void _MenuCtrl_Error( uint8_t error )
{
const char *pStr = NULL;
 
switch( error )
{
case ERROR_NOMENU: pStr = PSTR("NOMENU"); break;
case ERROR_MAXMENU: pStr = PSTR("MAXMENU"); break;
case ERROR_MAXITEM: pStr = PSTR("MAXITEM"); break;
case ERROR_NOITEM: pStr = PSTR("NOITEM"); break;
case ERROR_NOPARENTMENU: pStr = PSTR("NOPARENTMENU"); break;
}
 
set_beep( 1000, 0x000f, BeepNormal); // Beep Error
PKT_Popup_P( 10000, PSTR("menuctrl.c"), 0, PSTR("* ERROR *"), pStr ); // 10000 = max. 100 Sekunden anzeigen
}
 
 
//--------------------------------------------------------------
// INTERN
//--------------------------------------------------------------
int8_t _MenuCtrl_FindItem( uint8_t itemid )
{
int8_t i;
 
if( midx < 0) { _MenuCtrl_Error( ERROR_NOMENU ); return -1; }
 
for( i=0; i<menu[midx].itemcount; i++)
{
if( itemid == menu[midx].item[i].id )
{
return i; // found: return index
}
}
return -1; // not found
}
 
 
//--------------------------------------------------------------
// INTERN
//--------------------------------------------------------------
void _MenuCtrl_CalcDisplayPos( void )
{
int8_t i;
 
i = menu[midx].active - menu[midx].display_pos;
 
if( i < 0 )
menu[midx].display_pos = menu[midx].active;
else if( i > 5 )
menu[midx].display_pos = (menu[midx].active - 5);
}
 
 
//--------------------------------------------------------------
// INTERN
//--------------------------------------------------------------
void _MenuCtrl_Beep( void )
{
if( menu[midx].beep )
set_beep( 25, 0xffff, BeepNormal );
}
 
 
//--------------------------------------------------------------
// INTERN
// Dreieckstausch von zwei Menuepunkten.
// Wird verwendet um Menueitems zu verschieben.
//--------------------------------------------------------------
void _MenuCtrl_SwapItem( uint8_t itemindex_1, uint8_t itemindex_2 )
{
menue_item_t tmpItem;
 
memcpy( &tmpItem , &menu[midx].item[itemindex_1], sizeof(menue_item_t) );
memcpy( &menu[midx].item[itemindex_1] , &menu[midx].item[itemindex_2], sizeof(menue_item_t) );
memcpy( &menu[midx].item[itemindex_2] , &tmpItem, sizeof(menue_item_t) );
}
 
 
 
//#############################################################################################
//# PUBLIC funcs
//#############################################################################################
 
 
//--------------------------------------------------------------
// MenuCtrl_Create()
//--------------------------------------------------------------
void MenuCtrl_Create( void )
{
if( midx >= MENUCTRL_MAXMENUES) { _MenuCtrl_Error( ERROR_MAXMENU ); return; }
 
midx++;
memset( &menu[midx], 0, sizeof(menue_t) );
menu[midx].cycle = MENUDEFAULT_CYCLE;
menu[midx].showbatt = MENUDEFAULT_SHOWBATT;
menu[midx].beep = MENUDEFAULT_BEEP;
}
 
 
//--------------------------------------------------------------
// MenuCtrl_Destroy()
//--------------------------------------------------------------
void MenuCtrl_Destroy( void )
{
if( midx < 0) { _MenuCtrl_Error( ERROR_NOMENU ); return; }
 
midx--;
}
 
 
//--------------------------------------------------------------
// MenuCtrl_ShowLevel( value )
//
// Diese Einstellung ist Global und wirkt sich direkt auf alle
// Menues aus!
// Man kann das also nicht fuer einzelne Menues ein-/ausschalten.
//
// Parameter:
// value: true / false
//--------------------------------------------------------------
void MenuCtrl_ShowLevel( uint8_t value )
{
showlevel = value;
}
 
 
//--------------------------------------------------------------
// MenuCtrl_SetTitle_P( *title )
//
// Parameter:
// title: Menuetitel; Zeiger auf String PROGMEM
//--------------------------------------------------------------
void MenuCtrl_SetTitle_P( const char *title )
{
if( midx < 0) { _MenuCtrl_Error( ERROR_NOMENU ); return; }
 
menu[midx].title = title;
menu[midx].titlePGM = true;
}
 
 
//--------------------------------------------------------------
// MenuCtrl_SetTitle( *title )
//
// Parameter:
// title: Menuetitel; Zeiger auf String im RAM
//--------------------------------------------------------------
void MenuCtrl_SetTitle( const char *title )
{
if( midx < 0) { _MenuCtrl_Error( ERROR_NOMENU ); return; }
 
menu[midx].title = title;
menu[midx].titlePGM = false;
}
 
 
 
//--------------------------------------------------------------
// MenuCtrl_SetTitleFromParentItem()
//
// setzte anhand des uebergeordneten Menuepunktes (dem aufrufenden
// Menuepunkt) den Titel des neuen Menues
//
// wird u.a. verwendet in setup.c
//--------------------------------------------------------------
void MenuCtrl_SetTitleFromParentItem( void )
{
uint8_t lang;
const char *pStr;
uint8_t mparent;
 
if( midx < 0) { _MenuCtrl_Error( ERROR_NOMENU ); return; }
if( midx < 1) { _MenuCtrl_Error( ERROR_NOPARENTMENU ); return; }
 
mparent = midx-1;
 
//--------------------------
// Sprache: Multilanguage oder 0 wenn wenn nur ein Text
//--------------------------
lang = (menu[mparent].item[ menu[mparent].active ].textcount == 1) ? 0 : Config.DisplayLanguage;
 
//--------------------------
// Text vom uebergeordneten Menuepunkt
//--------------------------
pStr = menu[mparent].item[ menu[mparent].active ].text[lang];
 
//--------------------------
// Titel setzen
//--------------------------
if( menu[mparent].item[ menu[mparent].active ].textPGM )
{
MenuCtrl_SetTitle_P( pStr );
}
else
{
MenuCtrl_SetTitle( pStr );
}
}
 
 
 
//--------------------------------------------------------------
// MenuCtrl_SetCycle( value )
//
// Parameter:
// value: true / false
//--------------------------------------------------------------
void MenuCtrl_SetCycle( uint8_t value )
{
if( midx < 0) { _MenuCtrl_Error( ERROR_NOMENU ); return; }
 
menu[midx].cycle = value;
}
 
 
 
//--------------------------------------------------------------
// MenuCtrl_SetBeep( value )
//
// Parameter:
// value: true / false
//--------------------------------------------------------------
void MenuCtrl_SetBeep( uint8_t value )
{
if( midx < 0) { _MenuCtrl_Error( ERROR_NOMENU ); return; }
 
menu[midx].beep = value;
}
 
 
 
//--------------------------------------------------------------
// MenuCtrl_SetMove( value )
//
// Schaltet in einem Menue die Moeglichkeit ein Menueeintraege nach
// oben oder nach unten zu verschieben.
// Zum verschieden eines Menueeintrages muessen die PLUS/MINUS Tasten
// lange gedrueckt werden.
//
// Parameter:
// value: true / false (Default: false)
//--------------------------------------------------------------
void MenuCtrl_SetMove( uint8_t value )
{
if( midx < 0) { _MenuCtrl_Error( ERROR_NOMENU ); return; }
 
menu[midx].canMove = value;
}
 
 
//--------------------------------------------------------------
// MenuCtrl_SetDelete( value )
//
// Schaltet in einem Menue die Moeglichkeit ein Menueeintraege zu loeschen.
// Zum loeschen eines Menueeintrages muss dann die ganz rechte 'OK' Taste
// lange gedrueckt werden.
//
// Parameter:
// value: true / false (Default: false)
//--------------------------------------------------------------
void MenuCtrl_SetDelete( uint8_t value )
{
if( midx < 0) { _MenuCtrl_Error( ERROR_NOMENU ); return; }
 
menu[midx].canDelete = value;
}
 
 
//--------------------------------------------------------------
// MenuCtrl_SetShowBatt( value )
//
// Parameter:
// value: true / false
//--------------------------------------------------------------
void MenuCtrl_SetShowBatt( uint8_t value )
{
if( midx < 0) { _MenuCtrl_Error( ERROR_NOMENU ); return; }
 
menu[midx].showbatt = value;
}
 
 
 
//--------------------------------------------------------------
// MenuCtrl_SetTopSpace( n )
//
// fuegt oben im Menue n Leerzeichen ein um Abstand vom Menuetitel
// zu erhalten
//
// ACHTUNG! Das funktioniert nur mit Menues die nicht Scrollen!
// -> also weniger als 6 Eintraege haben (je nach Anzahl von TopSpace)
//
// ACHTUNG! Keine Absicherung bzgl. obigem Warnpunkt! Das kann man
// zwar machen - ist aber aktuell nicht so!
//
// Parameter:
// value: 0..n Anzahl der Leerzeilen ueber dem Menue
//--------------------------------------------------------------
void MenuCtrl_SetTopSpace( uint8_t n )
{
if( midx < 0) { _MenuCtrl_Error( ERROR_NOMENU ); return; }
 
menu[midx].topspace = n;
}
 
 
 
//--------------------------------------------------------------
// MenuCtrl_SetKey( key, *keytext, *keyfunc )
//
// Parameter:
// key : KEY_ENTER, KEY_ENTER_LONG, KEY_ESC, KEY_ESC_LONG
// keytext: Pointer auf Text PROGMEM oder NOTEXT (=0)
// keyfunc: Pointer auf Funktion oder NOFUNC (=0)
//--------------------------------------------------------------
void MenuCtrl_SetKey( uint8_t key, const char *keytext, void (*keyfunc)(void) )
{
if( midx < 0) { _MenuCtrl_Error( ERROR_NOMENU ); return; } // kein aktives Menue
 
if( key == KEY_ENTER )
{
menu[midx].key_enter.active = true;
menu[midx].key_enter.text = keytext;
menu[midx].key_enter.func = keyfunc;
}
 
if( key == KEY_ENTER_LONG )
{
menu[midx].key_enter_long.active = true;
menu[midx].key_enter_long.text = keytext;
menu[midx].key_enter_long.func = keyfunc;
}
 
if( key == KEY_ESC )
{
menu[midx].key_esc.active = true;
menu[midx].key_esc.text = keytext;
menu[midx].key_esc.func = keyfunc;
}
 
if( key == KEY_ESC_LONG )
{
menu[midx].key_esc_long.active = true;
menu[midx].key_esc_long.text = keytext;
menu[midx].key_esc_long.func = keyfunc;
}
}
 
 
//--------------------------------------------------------------
// key = MenuCtrl_GetKey()
//
// Rueckgabe:
// key: z.B. KEY_ENTER oder KEY_ENTER_LONG
//--------------------------------------------------------------
uint8_t MenuCtrl_GetKey( void )
{
if( midx < 0) { _MenuCtrl_Error( ERROR_NOMENU ); return 0; } // kein aktives Menue
 
return menu[midx].lastkey;
}
 
 
 
//--------------------------------------------------------------
// menuindex = MenuCtrl_GetMenuIndex()
//
// gibt den aktuellen Menuindex zurueck
//
// Rueckgabe:
// menuindex: <0 = keine Menue (-1)
// =0 = Hauptmenue (Toplevel)
// >0 = Untermenue Level
//--------------------------------------------------------------
int8_t MenuCtrl_GetMenuIndex( void )
{
return midx;
}
 
 
 
//--------------------------------------------------------------
// itemid = MenuCtrl_GetItemId()
//
// gibt die itemID des aktuell angewaehlten Menuepunktes zurueck
//
// Rueckgabe:
// itemid:
//--------------------------------------------------------------
uint8_t MenuCtrl_GetItemId( void )
{
if( midx < 0) { _MenuCtrl_Error( ERROR_NOMENU ); return 0; } // kein aktives Menue
 
return menu[midx].item[ menu[midx].active ].id;
}
 
 
 
//--------------------------------------------------------------
// itemid = MenuCtrl_GetItemIdByIndex( index )
//
// damit koennen die aktuell vorhanden itemID's der Menuepunkte
// ermittelt wenn im Menue via SetMove oder SetDelete Menuepunkte
// durch den Benutzer verschoben oder geloescht wurden.
//
// Parameter:
// index: von 0..itemcount-1
//--------------------------------------------------------------
uint8_t MenuCtrl_GetItemIdByIndex( uint8_t index )
{
if( midx < 0) { _MenuCtrl_Error( ERROR_NOMENU ); return 0; } // kein aktives Menue
 
if( (menu[midx].itemcount == 0) || (index > menu[midx].itemcount-1) ) return 0; // index ausserhalb aktiver Menuepunkte
 
return menu[midx].item[ index ].id;
}
 
 
 
//--------------------------------------------------------------
// num = MenuCtrl_GetItemCount()
//
// gibt die Anzahl der Menuepunkte zurueck
//
// Rueckgabe:
// num: Anzahl der Menuepunkte
//--------------------------------------------------------------
uint8_t MenuCtrl_GetItemCount( void )
{
if( midx < 0) { _MenuCtrl_Error( ERROR_NOMENU ); return 0; } // kein aktives Menue
 
return menu[midx].itemcount;
}
 
 
//--------------------------------------------------------------
// textPtr = MenuCtrl_GetItemText()
//
// gibt einen Pointer auf den Text des aktuellen Menuepunktes zurueck
//
// ACHTUNG! Der Pointer kann auf RAM oder auch auf PGM zeigen!
//
// Um herauszufinden auf welchen Bereich der Pointer zeigt kann
// MenuCtrl_IsItemTextPGM() verwendet werden.
//
// Rueckgabe:
// textPtr: in RAM oder PGM
//--------------------------------------------------------------
const char * MenuCtrl_GetItemText( void )
{
uint8_t lang;
 
if( midx < 0) { _MenuCtrl_Error( ERROR_NOMENU ); return 0; } // kein aktives Menue
 
//--------------------------
// Sprache: Multilanguage oder 0 wenn wenn nur ein Text
//--------------------------
lang = (menu[midx].item[ menu[midx].active ].textcount == 1) ? 0 : Config.DisplayLanguage;
 
return menu[midx].item[ menu[midx].active ].text[lang];
}
 
 
 
//--------------------------------------------------------------
// isPGM = MenuCtrl_IsItemTextPGM()
//
// gibt true/false zurueck je nachdem der Text von MenuCtrl_GetItemText()
// im Progmem (=true) oder im RAM (=false) ist
//
// Rueckgabe:
// isPGM: true / false (true = text in PROGMEN; false = text im RAM)
//--------------------------------------------------------------
uint8_t MenuCtrl_IsItemTextPGM( void )
{
if( midx < 0) { _MenuCtrl_Error( ERROR_NOMENU ); return 0; } // kein aktives Menue
 
return menu[midx].item[ menu[midx].active ].textPGM;
}
 
 
 
//--------------------------------------------------------------
// MenuCtrl_ItemSelect( itemid )
//
// aktiviert einen Menuepunkt / setzt den Menue-Cursor darauf
//
// die Funktion ist nicht durchgetestet, funktioniert aber
// in MKSettings_Menu() / mkparameters.c
//
// es kann sein das es zu Problemen kommt wenn das Menue
// scrollt (mehr als 6 Menueeintraege)
//
// Parameter:
// itemid: ID des Menuitems
//--------------------------------------------------------------
void MenuCtrl_ItemSelect( uint8_t itemid )
{
int8_t i;
 
i = _MenuCtrl_FindItem( itemid );
 
if( i >= 0 )
{
menu[midx].active = i;
}
}
 
 
//--------------------------------------------------------------
// MenuCtrl_ItemActive( itemid, value )
//
// Parameter:
// itemid: ID des Menuitems
// value : true / false
//--------------------------------------------------------------
void MenuCtrl_ItemActive( uint8_t itemid, uint8_t value )
{
int8_t i;
 
i = _MenuCtrl_FindItem( itemid );
 
if( i >= 0 )
{
menu[midx].item[i].disabled = !value;
}
}
 
 
//--------------------------------------------------------------
// MenuCtrl_ItemMark( itemid, value )
//
// Markiert einen Menueeintrag mit einem '*' am Anfang (Links).
// Wird u.a. von BT_SelectDevice() (setup.c) verwendet
//
// Parameter:
// itemid: ID des Menuitems
// value : true / false
//--------------------------------------------------------------
void MenuCtrl_ItemMark( uint8_t itemid, uint8_t value )
{
int8_t i;
 
i = _MenuCtrl_FindItem( itemid );
 
if( i >= 0 )
{
menu[midx].item[i].mark = value;
}
}
 
 
//--------------------------------------------------------------
// MenuCtrl_ItemMarkR( itemid, value )
//
// Markiert einen Menueeintrag mit einem Haken am ENDE (Rechts).
// Wird u.a. von ... (setup.c) verwendet
//
// Parameter:
// itemid: ID des Menuitems
// value : true / false
//--------------------------------------------------------------
void MenuCtrl_ItemMarkR( uint8_t itemid, uint8_t value )
{
int8_t i;
 
i = _MenuCtrl_FindItem( itemid );
 
if( i >= 0 )
{
menu[midx].item[i].markR = value;
}
}
 
 
//--------------------------------------------------------------
// INTERN
//
// fuer: MenuCtrl_PushML_P(), MenuCtrl_Push()
//--------------------------------------------------------------
void _MenuCtrl_Push( uint8_t useprogmem, uint8_t numlang, uint8_t itemid, uint8_t itemtype, void (*menufunc)(void), ... )
{
va_list ap;
uint8_t idx;
uint8_t i;
 
if( midx < 0 ) { _MenuCtrl_Error( ERROR_NOMENU ); return; }
if( menu[midx].itemcount >= MENUCTRL_MAXITEMS ) { _MenuCtrl_Error( ERROR_MAXITEM ); return; }
//if( numlang > NUM_LANG ) { _MenuCtrl_Error( ERROR_MAXLANG ); return; }
 
idx = menu[midx].itemcount;
 
menu[midx].item[idx].id = itemid;
menu[midx].item[idx].type = itemtype; // MENU_ITEM, MENU_SUB
menu[midx].item[idx].mark = false;
menu[midx].item[idx].func = menufunc;
menu[midx].item[idx].textPGM = useprogmem;
menu[midx].item[idx].textcount= numlang;
 
va_start(ap, menufunc);
 
for( i=0; i<numlang; i++)
{
menu[midx].item[idx].text[i] = va_arg( ap, const char *);
}
 
va_end(ap);
 
menu[midx].itemcount++;
}
 
 
//--------------------------------------------------------------
// MenuCtrl_PushML2_P( itemid, itemtype, *menufunc, *text_de, *text_en, *text_nl )
//
// MultiLanguage Texte fuer 2 Sprachen (DE, EN)
// PROGMEN Version
//
// Parameter:
// itemid : ID des Menueitems
// itemtype: MENU_ITEM oder MENU_SUB (bei MENU_SUB wird noch ein ">" angezeigt)
// menufunc: Pointer auf Funktion oder NOFUNC (=0) wenn keine Funktion
// texte : alles Zeiger auf PROGMEM
//--------------------------------------------------------------
void MenuCtrl_PushML2_P( uint8_t itemid, uint8_t itemtype, void (*menufunc)(void), const char *text_de, const char *text_en )
{
//_MenuCtrl_Push( useprogmem, numlang, itemid, itemtype, void (*menufunc)(void), ... )
_MenuCtrl_Push( true, NUM_LANG, itemid, itemtype, menufunc, text_de, text_en );
}
 
 
//--------------------------------------------------------------
// MenuCtrl_PushML2( itemid, itemtype, *menufunc, *text_de, *text_en, *text_nl )
//
// MultiLanguage Texte fuer 2 Sprachen (DE, EN)
// RAM Version
//
// Parameter:
// itemid : ID des Menueitems
// itemtype: MENU_ITEM oder MENU_SUB (bei MENU_SUB wird noch ein ">" angezeigt)
// menufunc: Pointer auf Funktion oder NOFUNC (=0) wenn keine Funktion
// texte : alles Zeiger auf RAM
//--------------------------------------------------------------
void MenuCtrl_PushML2( uint8_t itemid, uint8_t itemtype, void (*menufunc)(void), const char *text_de, const char *text_en )
{
//_MenuCtrl_Push( useprogmem, numlang, itemid, itemtype, void (*menufunc)(void), ... )
_MenuCtrl_Push( false, NUM_LANG, itemid, itemtype, menufunc, text_de, text_en );
}
 
 
//--------------------------------------------------------------
//--------------------------------------------------------------
void MenuCtrl_Push_P( uint8_t itemid, uint8_t itemtype, void (*menufunc)(void), const char *text )
{
//_MenuCtrl_Push( useprogmem, numlang, itemid, itemtype, void (*menufunc)(void), ... )
_MenuCtrl_Push( true, 1, itemid, itemtype, menufunc, text );
}
 
 
//--------------------------------------------------------------
//--------------------------------------------------------------
void MenuCtrl_Push( uint8_t itemid, uint8_t itemtype, void (*menufunc)(void), const char *text )
{
//_MenuCtrl_Push( useprogmem, numlang, itemid, itemtype, void (*menufunc)(void), ... )
_MenuCtrl_Push( false, 1, itemid, itemtype, menufunc, text );
}
 
 
//--------------------------------------------------------------
// Spezialfunktion fuer mkparameters.c !
//
// -> siehe: mkparameters.c / Menu_EditCategory()
//
// ACHTUNG!
// Die externe Variable paramEditItem muss in mkparameters.c
// vor Aufruf dieser Funktion richtig initialisiert sein!
// Ich habe darauf verzichtet hier nochmal ein find_paramEditItem()
// aufzurufen um Speicherplatz zu sparen.
//--------------------------------------------------------------
void MenuCtrl_PushParamEdit( uint8_t paramID )
{
//_MenuCtrl_Push( useprogmem, numlang, itemid, itemtype, void (*menufunc)(void), ... )
_MenuCtrl_Push( true, 2, paramID, MENU_PARAMEDIT, NOFUNC, paramEditItem.title_de, paramEditItem.title_en );
}
 
 
 
//--------------------------------------------------------------
// MenuCtrl_PushSeparator()
//
// fuegt eine Trennlinie im Menue ein
// (die itemID ist dabei 0)
//--------------------------------------------------------------
void MenuCtrl_PushSeparator( void )
{
//_MenuCtrl_Push( useprogmem, numlang, itemid, itemtype, void (*menufunc)(void), ... )
_MenuCtrl_Push( true, 0, 0, MENU_SEPARATOR, NOFUNC );
}
 
 
 
//--------------------------------------------------------------
// MenuCtrl_PushSeparatorID( itemId )
//
// fuegt eine Trennlinie im Menue ein mit einer eigenen itemID
//--------------------------------------------------------------
void MenuCtrl_PushSeparatorID( uint8_t itemid )
{
//_MenuCtrl_Push( useprogmem, numlang, itemid, itemtype, void (*menufunc)(void), ... )
_MenuCtrl_Push( true, 0, itemid, MENU_SEPARATOR, NOFUNC );
}
 
 
 
//--------------------------------------------------------------
// MenuCtrl_Refresh( mode )
//
// Parameter:
// mode: MENU_REDRAW || MENU_REFRESH
//--------------------------------------------------------------
void MenuCtrl_Refresh( uint8_t mode )
{
uint8_t y;
uint8_t item;
uint8_t sh;
uint8_t sy;
uint8_t actchar;
uint8_t markchar;
uint8_t markcharR;
uint8_t lang;
 
if( midx < 0) { _MenuCtrl_Error( ERROR_NOMENU ); return; } // kein Menue vorhanden
 
if( mode == MENU_REDRAW )
{
//--------------------------
// Clear
//--------------------------
lcd_frect( 0, 8, 6, 47, 0); // Clear: ganz linke Spalte des Sliders
lcd_frect( 127-2, 0, 2, 63, 0); // Clear: ganz rechts 2 Pixel
 
//--------------------------
// Titel
//--------------------------
if( menu[midx].title != 0 )
{
if( showlevel )
{
if( menu[midx].titlePGM )
lcdx_printf_at_P( 0, 0, MINVERS, 0,0 , PSTR(" %19S"), menu[midx].title );
else
lcdx_printf_at_P( 0, 0, MINVERS, 0,0 , PSTR(" %19s"), menu[midx].title );
 
writex_ndigit_number_u( 0, 0, midx, 1, 0, MINVERS, 1,0); // Menuelevel zeigen
}
else
{
if( menu[midx].titlePGM )
lcdx_printf_at_P( 0, 0, MINVERS, 0,0 , PSTR(" %20S"), menu[midx].title );
else
lcdx_printf_at_P( 0, 0, MINVERS, 0,0 , PSTR(" %20s"), menu[midx].title );
}
}
else
lcd_frect( 0, 0, 128, 7, 1); // Titel: Leerzeile
 
 
//--------------------------
// Keyline Beschriftung
//--------------------------
lcdx_cls_row( 7, MNORMAL, 0);
PKT_KeylineUpDown( 1, 7, 0,0);
lcd_printp_at( 12, 7, strGet(KEYLINE4), MNORMAL);
 
 
// Taste: KEY_ENTER
if( menu[midx].key_enter.active && menu[midx].key_enter.text != 0 )
{
lcdx_printf_at_P( 17, 7, MNORMAL, 0,0 , PSTR("%4S"), menu[midx].key_enter.text );
}
 
// Taste: KEY_ESC
if( menu[midx].key_esc.active && menu[midx].key_esc.text != 0 )
{
lcdx_printf_at_P( 12, 7, MNORMAL, 0,0 , PSTR("%5S"), menu[midx].key_esc.text );
}
}
 
 
//--------------------------
// PKT Batterie Anzeige
//--------------------------
if( menu[midx].showbatt )
{
show_Lipo();
}
 
 
//--------------------------
// Zeilen
//--------------------------
for( y=0; y<6; y++)
{
item = y + menu[midx].display_pos;
 
if( item < menu[midx].itemcount )
{
//--------------------------
// char: aktuelle Auswahl
//--------------------------
actchar = ' ';
if( item == menu[midx].active )
{
if( menu[midx].item[item].disabled ) actchar = 0x15; // aktuelle Auswahl: Pfeil disabled
else actchar = 0x1d; // aktuelle Auswahl: Pfeil
}
 
//--------------------------
// char: markiert
//--------------------------
markchar = ' ';
if( menu[midx].item[item].mark ) markchar = '*';
 
//--------------------------
// char: markiert RECHTS
//--------------------------
markcharR = ' ';
if( menu[midx].item[item].type == MENU_SUB ) markcharR = 0x1d;
if( menu[midx].item[item].markR ) markcharR = SYMBOL_CHECK;
 
//--------------------------
// Sprache: Multilanguage oder 0 wenn wenn nur ein Text
//--------------------------
lang = (menu[midx].item[item].textcount == 1) ? 0 : Config.DisplayLanguage;
 
//--------------------------
// Ausgabe: RAM oder PROGMEM
//--------------------------
if( MENU_SEPARATOR == menu[midx].item[item].type )
{
lcdx_printf_at_P( 1, y+1+menu[midx].topspace, MNORMAL, 0,0 , PSTR("%c%c%18S") , actchar, markchar, PSTR("") );
lcd_frect( 6*3, ((y+1)*8)+3, 124-(6*3), 0, 1); // Trennlinie
}
else if( MENU_PARAMEDIT == menu[midx].item[item].type )
{
// SPEZIELL fuer mkparameters.c - zeigt die paramID-Bezeichnung inkl. dem aktuellen WERT an!
strcpy_P( mkparam_strValueBuffer, PSTR("***")); // Vorbelegung von mkparam_strValueBuffer
if( !menu[midx].item[item].disabled ) // nur wenn Menuepunkt nicht deaktiviert (disabled = paramID nicht vorhanden)
{ // -> ermittle den aktuellen Wert der paramID fuer Anzeige
find_paramEditItem( menu[midx].item[item].id ); // paramID suchen (Ergebnis in Variable 'paramEditItem')
paramEditItem.editfunc( paramEditItem.paramID, MKPARAM_SHORTVALUE ); // Wert von paramID in mkparam_strValueBuffer darstellen
}
lcdx_printf_at_P( 1, y+1+menu[midx].topspace, MNORMAL, 0,0 , PSTR("%c%c%14S %3s") , actchar, markchar, menu[midx].item[item].text[lang], mkparam_strValueBuffer );
}
else
{
// Anmerkung zu menu[midx].topspace: NUR fuer Menues OHNE scrollen!!
if( menu[midx].item[item].textPGM )
{
// String im PGM
if( menu[midx].item[item].type == MENU_SUB || menu[midx].item[item].markR )
lcdx_printf_at_P( 1, y+1+menu[midx].topspace, MNORMAL, 0,0 , PSTR("%c%c%16S%c "), actchar, markchar, menu[midx].item[item].text[lang], markcharR );
else
lcdx_printf_at_P( 1, y+1+menu[midx].topspace, MNORMAL, 0,0 , PSTR("%c%c%17S ") , actchar, markchar, menu[midx].item[item].text[lang] );
}
else
{
// String im RAM
if( menu[midx].item[item].type == MENU_SUB || menu[midx].item[item].markR )
lcdx_printf_at_P( 1, y+1+menu[midx].topspace, MNORMAL, 0,0 , PSTR("%c%c%16s%c "), actchar, markchar, menu[midx].item[item].text[lang], markcharR );
else
lcdx_printf_at_P( 1, y+1+menu[midx].topspace, MNORMAL, 0,0 , PSTR("%c%c%17s ") , actchar, markchar, menu[midx].item[item].text[lang] );
}
}
 
} // end: if( item < menu[midx].itemcount )
 
 
//--------------------------
// evtl. Leerzeile loeschen
//--------------------------
if( (y < menu[midx].topspace) || (item >= menu[midx].itemcount+menu[midx].topspace) )
{
lcd_frect( 6, (y+1)*8, 128-6, 7, 0); // Zeile loeschen
}
 
}
 
 
//--------------------------
// Slider
//--------------------------
#define SLIDERH 45 // Finetuning der Slider-Hoehe
 
lcd_frect( 0, 8+1, 1, SLIDERH, 0); // Slider: full Clear
 
if( menu[midx].itemcount > 6 ) // Slider nur bei mehr als 6 Menueitems
{
// Slider: 7 zeilen * 8 pixel = 56 pixel
sh = (SLIDERH * 6) / menu[midx].itemcount; // Slider: Hoehe
sh = (sh > SLIDERH) ? SLIDERH : sh;
 
sy = 8+(menu[midx].display_pos * (SLIDERH-sh)) / (menu[midx].itemcount-6); // Slider: Position
 
//lcd_frect( 0, 8+1, 1, SLIDERH, 0); // Slider: full Clear (flackert auf blauen Display!)
//lcd_frect( 0, 8+1, 1, sy-(8), 0); // Slider: Clear / oben (nicht mehr notwendig da Aenderung am Refresh)
//lcd_frect( 0, sy+1+sh+1, 1, SLIDERH-(sh-sy+1), 0); // Slider: Clear / unten (nicht mehr notwendig da Aenderung am Refresh)
lcd_frect( 0, sy+1, 1, sh, 1); // Slider: Draw
}
}
 
 
 
//--------------------------------------------------------------
// event = MenuCtrl_Control( ctrlmode )
//
// Parameter:
// ctrlmode: MENUCTRL_EVENT || MENUCTRL_RETURN
//
// Rueckgabe:
// event: MENUEVENT_NONE || MENUEVENT_ITEM || MENUEVENT_KEY
//--------------------------------------------------------------
uint8_t MenuCtrl_Control( uint8_t ctrlmode )
{
uint8_t menu_event;
uint8_t refreshmode;
uint8_t item;
uint8_t wahl;
uint8_t i;
uint8_t goUp = false;
uint8_t goDown = false;
 
if( midx < 0) { _MenuCtrl_Error( ERROR_NOMENU ); return 0; } // kein Menue vorhanden
if( menu[midx].itemcount == 0) { _MenuCtrl_Error( ERROR_NOITEM ); return 0; } // kein Menueitem vorhanden
 
 
// bei MENUCTRL_RETURN muss man ggf. selber fuer ein Redraw sorgen
// (beim ersten Aufruf wird es jedoch dennoch erzwungen)
if( ctrlmode == MENUCTRL_EVENT || !menu[midx].firstredraw )
{
MenuCtrl_Refresh( MENU_REDRAW );
menu[midx].firstredraw = true;
}
 
clear_key_all();
 
do
{
menu_event = MENUEVENT_NONE;
menu[midx].lastkey = KEY_NONE;
refreshmode = false;
 
//--------------------------
// Pruefe PKT Update oder
// andere PKT-Aktion
//--------------------------
if( PKT_CtrlHook() ) // Update vom Updatetool angefordert?
{
refreshmode = MENU_REDRAW;
}
 
//--------------------------
// PKT Batterie Anzeige
//--------------------------
if( menu[midx].showbatt )
{
show_Lipo();
}
 
 
//--------------------------
// Cursor: nach oben (UP)
//--------------------------
//+++++
// UP - Verschiebemodus AKTIV
//+++++
if( menu[midx].canMove )
{
if( get_key_long(1 << KEY_MINUS) )
{
if( (menu[midx].active > 0) && (menu[midx].itemcount > 0) )
{
_MenuCtrl_SwapItem( menu[midx].active, menu[midx].active-1 );
goUp = true;
}
else _MenuCtrl_Beep(); // am oberen Ende angelangt
}
 
if( get_key_short(1 << KEY_MINUS) ) // up
{
goUp = true;
}
} // end: UP - Verschiebemodus AKTIV
 
 
//+++++
// UP - Verschiebemodus NICHT aktiv
//+++++
if( !menu[midx].canMove ) // up
{
if( get_key_press(1 << KEY_MINUS) || get_key_long_rpt_sp((1 << KEY_MINUS),2) ) // up
{
goUp = true;
}
} // end: UP - Verschiebemodus NICHT aktiv
 
 
//+++++
// UP - goUp
//+++++
if( goUp ) // up
{
refreshmode = MENU_REFRESH;
if( (menu[midx].active > 0) && (menu[midx].itemcount > 0) )
{
menu[midx].active--;
}
else if( menu[midx].cycle )
{
menu[midx].active = menu[midx].itemcount-1;
}
else
{
_MenuCtrl_Beep(); // am oberen Ende angelangt
}
_MenuCtrl_CalcDisplayPos();
}
 
 
//--------------------------
// Cursor: nach unten (DOWN)
//--------------------------
//+++++
// DOWN - Verschiebemodus AKTIV
//+++++
if( menu[midx].canMove )
{
if( get_key_long(1 << KEY_PLUS) )
{
if( menu[midx].active < menu[midx].itemcount-1 )
{
_MenuCtrl_SwapItem( menu[midx].active, menu[midx].active+1 );
goDown = true;
}
else _MenuCtrl_Beep(); // am unteren Ende angelangt
}
 
if( get_key_short(1 << KEY_PLUS) ) // up
{
goDown = true;
}
} // end: DOWN - Verschiebemodus AKTIV
 
 
//+++++
// DOWN - Verschiebemodus NICHT aktiv
//+++++
if( !menu[midx].canMove ) // up
{
if( get_key_press(1 << KEY_PLUS) || get_key_long_rpt_sp((1 << KEY_PLUS),2) ) // up
{
goDown = true;
}
} // end: DOWN - Verschiebemodus NICHT aktiv
 
 
//+++++
// DOWN - goDown
//+++++
if( goDown ) // down
{
refreshmode = MENU_REFRESH;
if( menu[midx].active < menu[midx].itemcount-1 )
{
menu[midx].active++;
}
else if( menu[midx].cycle )
{
menu[midx].active = 0;
}
else
{
_MenuCtrl_Beep(); // am unteren Ende angelangt
}
_MenuCtrl_CalcDisplayPos();
}
 
 
//--------------------------
//--------------------------
item = menu[midx].active;
goUp = false;
goDown = false;
 
 
//--------------------------
// KEY_ENTER
//--------------------------
if( get_key_short(1 << KEY_ENTER) )
{
refreshmode = MENU_REFRESH;
// todo: keyfunc
if( menu[midx].item[item].type == MENU_SEPARATOR )
{
// do nothing
}
else if( menu[midx].item[item].disabled )
{
set_beep( 200, 0x00ff, BeepNormal); // Beep
PKT_Popup_P( 200, strGet(STR_MENUCTRL_NOTPOSSIBLE),0,0,0); // "nicht mƶglich!"
refreshmode = MENU_REDRAW;
}
else if( menu[midx].item[item].func != NOFUNC )
{
menu[midx].item[item].func();
refreshmode = MENU_REDRAW;
}
else if( menu[midx].key_enter.func != NOFUNC )
{
menu[midx].key_enter.func();
refreshmode = MENU_REDRAW;
}
else
{
menu[midx].lastkey = KEY_ENTER;
menu_event = MENUEVENT_ITEM;
}
}
 
 
//--------------------------
// KEY_ENTER_LONG (Deletemodus AKTIV)
//
// loescht einen Menueeintrag
//--------------------------
if( menu[midx].canDelete && get_key_long(1 << KEY_ENTER) && (menu[midx].itemcount > 0) )
{
wahl = 1;
if( menu[midx].canDelete == 1 ) // ==1 -> mit Nachfrage
{
set_beep( 200, 0xffff, BeepNormal); // Beep
PKT_Popup_P( 0, strGet(STR_MENUCTRL_DELASK),PSTR(""),0,0); // "Eintrag entfernen?"
lcd_printp_at( 12, 7, strGet(YESNO), MINVERS);
 
wahl = 0;
while( !wahl )
{
if( get_key_short(1<<KEY_ESC) ) wahl = 1; // "Ja"
if( get_key_short(1<<KEY_ENTER) ) wahl = 2; // "Nein"
}
refreshmode = MENU_REDRAW;
}
 
if( wahl==1 )
{
for( i=menu[midx].active; i<menu[midx].itemcount-1; i++)
{
_MenuCtrl_SwapItem( i, i+1 );
}
menu[midx].itemcount--;
 
if( (menu[midx].display_pos > 0) && (menu[midx].display_pos+6 > menu[midx].itemcount) )
{
menu[midx].display_pos--;
menu[midx].active--;
}
 
if( menu[midx].active >= menu[midx].itemcount )
menu[midx].active = menu[midx].itemcount-1;
 
_MenuCtrl_CalcDisplayPos();
refreshmode = MENU_REDRAW;
 
if( menu[midx].canDelete == 2 ) // ==2 -> direkt loeschen, ohne Nachfrage
{
set_beep( 200, 0xffff, BeepNormal); // Beep
PKT_Popup_P( 200, strGet(STR_MENUCTRL_DELITEM),0,0,0); // "Eintrag entfernt!"
}
}
}
 
 
//--------------------------
// KEY_ENTER_LONG (NICHT Deletemodus)
//--------------------------
if( !menu[midx].canDelete && menu[midx].key_enter_long.active && get_key_long(1 << KEY_ENTER) )
{
refreshmode = MENU_REFRESH;
if( menu[midx].key_enter_long.func != NOFUNC )
{
menu[midx].key_enter_long.func();
refreshmode = MENU_REDRAW;
}
else
{
menu_event = MENUEVENT_KEY;
menu[midx].lastkey = KEY_ENTER_LONG;
}
}
 
 
//--------------------------
// KEY_ESC_LONG
//--------------------------
if( menu[midx].key_esc_long.active && get_key_long(1 << KEY_ESC) )
{
refreshmode = MENU_REFRESH;
if( menu[midx].key_esc_long.func != NOFUNC )
{
menu[midx].key_esc_long.func();
refreshmode = MENU_REDRAW;
}
else
{
menu_event = MENUEVENT_KEY;
menu[midx].lastkey = KEY_ESC_LONG;
}
}
 
 
//--------------------------
// KEY_ESC
//--------------------------
if( get_key_short(1 << KEY_ESC) )
{
refreshmode = MENU_REFRESH;
if( menu[midx].key_esc.func != NOFUNC )
{
menu[midx].key_esc.func();
refreshmode = MENU_REDRAW;
}
else
{
menu_event = MENUEVENT_KEY;
menu[midx].lastkey = KEY_ESC;
}
}
 
if( refreshmode )
{
MenuCtrl_Refresh( refreshmode );
clear_key_all();
}
}
while ( menu_event == MENUEVENT_NONE && ctrlmode == MENUCTRL_EVENT );
 
return menu_event;
}
 
Property changes:
Added: svn:mime-type
+text/plain
\ No newline at end of property
/Transportables_Koptertool/PKT/branches/branch_FollowMeStep2/utils/menuctrl.h
0,0 → 1,138
/*****************************************************************************
* 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 menuctrl.h
//#
//# 11.06.2014 OG
//# - add: MenuCtrl_GetMenuIndex()
//#
//# 11.05.2014 OG
//# - add: MenuCtrl_SetTitleFromParentItem()
//# - add: MenuCtrl_GetItemText(), MenuCtrl_IsItemTextPGM()
//#
//# 07.05.2014 OG
//# - add: MenuCtrl_PushSeparatorID()
//#
//# 06.05.2014 OG
//# - add: MenuCtrl_GetItemIdByIndex(), MenuCtrl_GetItemCount()
//#
//# 05.05.2014 OG
//# - add: MenuCtrl_SetDelete(), MenuCtrl_SetMove()
//#
//# 30.03.2014 OG
//# - del: MenuCtrl_PushML_P(), MenuCtrl_PushML() (Umstellung Sprachen abgeschlossen)
//# - add: MenuCtrl_PushML2(), MenuCtrl_PushML2_P() fuer Umstellung von 3 auf 2 Sprachen
//#
//# 24.03.2014 OG
//# - add: MenuCtrl_PushSeparator()
//# - add: MENU_SEPARATOR
//# - chg: Wert von MENU_REFRESH und MENU_REDRAW
//#
//# 23.03.2014 OG
//# - add: Unterstuetzung fuer MK-Parameter-Edit (mkparameters.c)
//# - add: MenuCtrl_PushParamEdit()
//# - add: define MENU_PARAMEDIT
//#
//# 17.02.2014 OG
//# - add: MenuCtrl_SetTopSpace()
//#
//# 15.02.2014 OG
//# - add: MenuCtrl_ItemSelect()
//#
//# 07.07.2013 OG
//# - add: MenuCtrl_ItemMarkR()
//#
//# 24.05.2013 OG
//# - chg: MenuCtrl_Push... Funktionen vereinheitlicht mit internen Aenderungen
//# betrifft externe Funktionsaufrufe die geƤndert wurden
//# - del: MenuCtrl_PushSimple_P(), MenuCtrl_PushSimple()
//# - add: MenuCtrl_ItemMark()
//#
//# 23.05.2013 OG
//# - add: MenuCtrl_PushSimple_P(), MenuCtrl_PushSimple()
//#
//# 21.05.2013 OG
//# - add: MenuCtrl_ShowLevel()
//#
//# 17.05.2013 OG - NEU
//############################################################################
 
#ifndef MENUCTRL_H
#define MENUCTRL_H
 
#define MENU_ITEM 1 // Typ des Menueitems: normaler Eintrag ohne ">" am Ende
#define MENU_SUB 2 // Typ des Menueitems: Submenue - es wird noch ein ">" angezeigt
#define MENU_SEPARATOR 3 // nur fuer MenuCtrl_PushSeparator() fuer (verwendet von mkparameters.c)
#define MENU_PARAMEDIT 4 // nur fuer MenuCtrl_PushParamEdit() fuer (verwendet von mkparameters.c)
 
#define NOFUNC 0 // keine Funktion uebergeben
#define NOTEXT 0 // kein Text uebergeben
 
#define MENUEVENT_NONE 0 // wird von MenuCtrl_Ctrl() zurueckgegeben
#define MENUEVENT_ITEM 1 // wird von MenuCtrl_Ctrl() zurueckgegeben
#define MENUEVENT_KEY 2 // wird von MenuCtrl_Ctrl() zurueckgegeben
 
#define MENUCTRL_EVENT 0 // Parameter fuer MenuCtrl_Ctrl() - Ruecksprung nur bei einem Event
#define MENUCTRL_RETURN 1 // Parameter fuer MenuCtrl_Ctrl() - Ruecksprung immer
 
 
#define MENU_REFRESH 1 // MenuCtrl_Refresh()
#define MENU_REDRAW 2 // MenuCtrl_Refresh()
 
 
void MenuCtrl_Create( void );
void MenuCtrl_Destroy( void );
void MenuCtrl_ShowLevel( uint8_t value );
 
void MenuCtrl_SetTitle( const char *title );
void MenuCtrl_SetTitle_P( const char *title );
void MenuCtrl_SetTitleFromParentItem( void );
void MenuCtrl_SetCycle( uint8_t value );
void MenuCtrl_SetShowBatt( uint8_t value );
void MenuCtrl_SetBeep( uint8_t value );
void MenuCtrl_SetKey( uint8_t key, const char *keytext, void (*keyfunc)(void) );
void MenuCtrl_SetTopSpace( uint8_t value );
void MenuCtrl_SetMove( uint8_t value );
void MenuCtrl_SetDelete( uint8_t value );
 
int8_t MenuCtrl_GetMenuIndex( void );
uint8_t MenuCtrl_GetItemId( void );
uint8_t MenuCtrl_GetKey( void );
uint8_t MenuCtrl_GetItemIdByIndex( uint8_t index );
uint8_t MenuCtrl_GetItemCount( void );
const char * MenuCtrl_GetItemText( void );
uint8_t MenuCtrl_IsItemTextPGM( void );
 
void MenuCtrl_ItemSelect( uint8_t itemid );
void MenuCtrl_ItemActive( uint8_t itemid, uint8_t value );
void MenuCtrl_ItemMark( uint8_t itemid, uint8_t value );
void MenuCtrl_ItemMarkR( uint8_t itemid, uint8_t value );
 
void MenuCtrl_PushML2_P( uint8_t itemid, uint8_t itemtype, void (*menufunc)(void), const char *text_de, const char *text_en );
void MenuCtrl_PushML2( uint8_t itemid, uint8_t itemtype, void (*menufunc)(void), const char *text_de, const char *text_en );
void MenuCtrl_Push_P( uint8_t itemid, uint8_t itemtype, void (*menufunc)(void), const char *text );
void MenuCtrl_Push( uint8_t itemid, uint8_t itemtype, void (*menufunc)(void), const char *text );
void MenuCtrl_PushParamEdit( uint8_t itemid );
void MenuCtrl_PushSeparator( void );
void MenuCtrl_PushSeparatorID( uint8_t itemid );
 
void MenuCtrl_Refresh( uint8_t mode );
uint8_t MenuCtrl_Control( uint8_t ctrlmode );
 
#endif // MENUCTRL_H
Property changes:
Added: svn:mime-type
+text/plain
\ No newline at end of property
/Transportables_Koptertool/PKT/branches/branch_FollowMeStep2/utils/scrollbox.c
0,0 → 1,570
/*****************************************************************************
* 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;
}
 
Property changes:
Added: svn:mime-type
+text/plain
\ No newline at end of property
/Transportables_Koptertool/PKT/branches/branch_FollowMeStep2/utils/scrollbox.h
0,0 → 1,49
/*****************************************************************************
* 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.h
//#
//# 17.05.2013 OG
//# - del: defines KEY_xyz_LONG verschoben nach HAL_HW3_9.h
//#
//# 28.04.2013 OG
//# - add: ScrollBox_Push()
//# - chg: ScrollBox_Push_P() (keine Rueckgabe mehr)
//# - add: include <stdarg.h>
//#
//# 20.04.2013 OG - NEU
//############################################################################
 
#ifndef _SCROLLBOX_H
#define _SCROLLBOX_H
 
#include <stdarg.h> // Notwendig! (OG)
 
 
uint8_t ScrollBox_Create( uint8_t maxlines );
void ScrollBox_Destroy( void );
void ScrollBox_PushLine( void );
void ScrollBox_Push_P( uint8_t mode, const char *format, ... );
void ScrollBox_Push( uint8_t mode, const char *format, ... );
void ScrollBox_SetKey( uint8_t key, const char *keytext );
void ScrollBox_Refresh( void );
uint8_t ScrollBox_Show( void );
//void ScrollBox_Debug( void );
 
#endif
Property changes:
Added: svn:mime-type
+text/plain
\ No newline at end of property
/Transportables_Koptertool/PKT/branches/branch_FollowMeStep2/utils/twi_slave.c
0,0 → 1,373
/*****************************************************************************
*
* Atmel Corporation
*
* File : TWI_Slave.c
* Compiler : IAR EWAAVR 2.28a/3.10c
* Revision : $Revision: 2475 $
* Date : $Date: 2007-09-20 12:00:43 +0200 (to, 20 sep 2007) $
* Updated by : $Author: mlarsson $
*
* Support mail : avr@atmel.com
*
* Supported devices : All devices with a TWI module can be used.
* The example is written for the ATmega16
*
* AppNote : AVR311 - TWI Slave Implementation
*
* Description : This is sample driver to AVRs TWI module.
* It is interupt driveren. All functionality is controlled through
* passing information to and from functions. Se main.c for samples
* of how to use the driver.
*
****************************************************************************/
/*! \page MISRA
*
* General disabling of MISRA rules:
* * (MISRA C rule 1) compiler is configured to allow extensions
* * (MISRA C rule 111) bit fields shall only be defined to be of type unsigned int or signed int
* * (MISRA C rule 37) bitwise operations shall not be performed on signed integer types
* As it does not work well with 8bit architecture and/or IAR
 
* Other disabled MISRA rules
* * (MISRA C rule 109) use of union - overlapping storage shall not be used
* * (MISRA C rule 61) every non-empty case clause in a switch statement shall be terminated with a break statement
*/
 
#if defined(__ICCAVR__)
#include "ioavr.h"
#include "inavr.h"
#else
#include <avr/io.h>
#include <avr/interrupt.h>
#endif
#include "twi_slave.h"
 
// Emulate GCC ISR() statement in IAR
#if defined(__ICCAVR__)
#define PRAGMA(x) _Pragma( #x )
#define ISR(vec) PRAGMA( vector=vec ) __interrupt void handler_##vec(void)
#endif
 
static unsigned char TWI_buf[TWI_BUFFER_SIZE]; // Transceiver buffer. Set the size in the header file
static unsigned char TWI_msgSize = 0; // Number of bytes to be transmitted.
static unsigned char TWI_state = TWI_NO_STATE; // State byte. Default set to TWI_NO_STATE.
 
// This is true when the TWI is in the middle of a transfer
// and set to false when all bytes have been transmitted/received
// Also used to determine how deep we can sleep.
static volatile unsigned char TWI_busy = 0;
 
union TWI_statusReg_t TWI_statusReg = {0}; // TWI_statusReg is defined in TWI_Slave.h
 
/****************************************************************************
Call this function to set up the TWI slave to its initial standby state.
Remember to enable interrupts from the main application after initializing the TWI.
Pass both the slave address and the requrements for triggering on a general call in the
same byte. Use e.g. this notation when calling this function:
TWI_Slave_Initialise( (TWI_slaveAddress<<TWI_ADR_BITS) | (TRUE<<TWI_GEN_BIT) );
The TWI module is configured to NACK on any requests. Use a TWI_Start_Transceiver function to
start the TWI.
****************************************************************************/
void twi_slave_init( unsigned char TWI_ownAddress )
{
TWAR = TWI_ownAddress; // Set own TWI slave address. Accept TWI General Calls.
TWCR = (1<<TWEN)| // Enable TWI-interface and release TWI pins.
(0<<TWIE)|(0<<TWINT)| // Disable TWI Interupt.
(0<<TWEA)|(0<<TWSTA)|(0<<TWSTO)| // Do not ACK on any requests, yet.
(0<<TWWC); //
TWI_busy = 0;
}
/****************************************************************************
Call this function to test if the TWI_ISR is busy transmitting.
****************************************************************************/
unsigned char twi_slave_busy( void )
{
return TWI_busy;
}
 
/****************************************************************************
Call this function to fetch the state information of the previous operation. The function will hold execution (loop)
until the TWI_ISR has completed with the previous operation. If there was an error, then the function
will return the TWI State code.
****************************************************************************/
unsigned char twi_slave_get_status( void )
{
while ( twi_slave_busy() ) {} // Wait until TWI has completed the transmission.
return ( TWI_state ); // Return error state.
}
 
/****************************************************************************
Call this function to send a prepared message, or start the Transceiver for reception. Include
a pointer to the data to be sent if a SLA+W is received. The data will be copied to the TWI buffer.
Also include how many bytes that should be sent. Note that unlike the similar Master function, the
Address byte is not included in the message buffers.
The function will hold execution (loop) until the TWI_ISR has completed with the previous operation,
then initialize the next operation and return.
****************************************************************************/
void twi_slave_start_with_data( unsigned char *msg, unsigned char msgSize )
{
unsigned char temp;
 
while ( twi_slave_busy() ) {} // Wait until TWI is ready for next transmission.
 
TWI_msgSize = msgSize; // Number of data to transmit.
for ( temp = 0; temp < msgSize; temp++ ) // Copy data that may be transmitted if the TWI Master requests data.
{
TWI_buf[ temp ] = msg[ temp ];
}
TWI_statusReg.all = 0;
TWI_state = TWI_NO_STATE ;
TWCR = (1<<TWEN)| // TWI Interface enabled.
(1<<TWIE)|(1<<TWINT)| // Enable TWI Interupt and clear the flag.
(1<<TWEA)|(0<<TWSTA)|(0<<TWSTO)| // Prepare to ACK next time the Slave is addressed.
(0<<TWWC); //
TWI_busy = 1;
}
 
/****************************************************************************
Call this function to start the Transceiver without specifing new transmission data. Useful for restarting
a transmission, or just starting the transceiver for reception. The driver will reuse the data previously put
in the transceiver buffers. The function will hold execution (loop) until the TWI_ISR has completed with the
previous operation, then initialize the next operation and return.
****************************************************************************/
void twi_slave_start( void )
{
while ( twi_slave_busy() ) {} // Wait until TWI is ready for next transmission.
TWI_statusReg.all = 0;
TWI_state = TWI_NO_STATE ;
TWCR = (1<<TWEN)| // TWI Interface enabled.
(1<<TWIE)|(1<<TWINT)| // Enable TWI Interupt and clear the flag.
(1<<TWEA)|(0<<TWSTA)|(0<<TWSTO)| // Prepare to ACK next time the Slave is addressed.
(0<<TWWC); //
TWI_busy = 0;
}
/****************************************************************************
Call this function to read out the received data from the TWI transceiver buffer. I.e. first call
TWI_Start_Transceiver to get the TWI Transceiver to fetch data. Then Run this function to collect the
data when they have arrived. Include a pointer to where to place the data and the number of bytes
to fetch in the function call. The function will hold execution (loop) until the TWI_ISR has completed
with the previous operation, before reading out the data and returning.
If there was an error in the previous transmission the function will return the TWI State code.
****************************************************************************/
unsigned char twi_slave_get_data( unsigned char *msg, unsigned char msgSize )
{
unsigned char i;
 
while ( twi_slave_busy() ) {} // Wait until TWI is ready for next transmission.
 
if( TWI_statusReg.lastTransOK ) // Last transmission completed successfully.
{
for ( i=0; i<msgSize; i++ ) // Copy data from Transceiver buffer.
{
msg[ i ] = TWI_buf[ i ];
}
TWI_statusReg.RxDataInBuf = FALSE; // Slave Receive data has been read from buffer.
}
return( TWI_statusReg.lastTransOK );
}
 
 
// ********** Interrupt Handlers ********** //
/****************************************************************************
This function is the Interrupt Service Routine (ISR), and called when the TWI interrupt is triggered;
that is whenever a TWI event has occurred. This function should not be called directly from the main
application.
****************************************************************************/
ISR(TWI_vect)
{
static unsigned char TWI_bufPtr;
switch (TWSR)
{
case TWI_STX_ADR_ACK: // Own SLA+R has been received; ACK has been returned
// case TWI_STX_ADR_ACK_M_ARB_LOST: // Arbitration lost in SLA+R/W as Master; own SLA+R has been received; ACK has been returned
TWI_bufPtr = 0; // Set buffer pointer to first data location
case TWI_STX_DATA_ACK: // Data byte in TWDR has been transmitted; ACK has been received
TWDR = TWI_buf[TWI_bufPtr++];
TWCR = (1<<TWEN)| // TWI Interface enabled
(1<<TWIE)|(1<<TWINT)| // Enable TWI Interupt and clear the flag to send byte
(1<<TWEA)|(0<<TWSTA)|(0<<TWSTO)| //
(0<<TWWC); //
TWI_busy = 1;
break;
case TWI_STX_DATA_NACK: // Data byte in TWDR has been transmitted; NACK has been received.
// I.e. this could be the end of the transmission.
if (TWI_bufPtr == TWI_msgSize) // Have we transceived all expected data?
{
TWI_statusReg.lastTransOK = TRUE; // Set status bits to completed successfully.
}
else // Master has sent a NACK before all data where sent.
{
TWI_state = TWSR; // Store TWI State as errormessage.
}
TWCR = (1<<TWEN)| // Enable TWI-interface and release TWI pins
(1<<TWIE)|(1<<TWINT)| // Keep interrupt enabled and clear the flag
(1<<TWEA)|(0<<TWSTA)|(0<<TWSTO)| // Answer on next address match
(0<<TWWC); //
TWI_busy = 0; // Transmit is finished, we are not busy anymore
break;
case TWI_SRX_GEN_ACK: // General call address has been received; ACK has been returned
// case TWI_SRX_GEN_ACK_M_ARB_LOST: // Arbitration lost in SLA+R/W as Master; General call address has been received; ACK has been returned
TWI_statusReg.genAddressCall = TRUE;
case TWI_SRX_ADR_ACK: // Own SLA+W has been received ACK has been returned
// case TWI_SRX_ADR_ACK_M_ARB_LOST: // Arbitration lost in SLA+R/W as Master; own SLA+W has been received; ACK has been returned
// Dont need to clear TWI_S_statusRegister.generalAddressCall due to that it is the default state.
TWI_statusReg.RxDataInBuf = TRUE;
TWI_bufPtr = 0; // Set buffer pointer to first data location
// Reset the TWI Interupt to wait for a new event.
TWCR = (1<<TWEN)| // TWI Interface enabled
(1<<TWIE)|(1<<TWINT)| // Enable TWI Interupt and clear the flag to send byte
(1<<TWEA)|(0<<TWSTA)|(0<<TWSTO)| // Expect ACK on this transmission
(0<<TWWC);
TWI_busy = 1;
break;
case TWI_SRX_ADR_DATA_ACK: // Previously addressed with own SLA+W; data has been received; ACK has been returned
case TWI_SRX_GEN_DATA_ACK: // Previously addressed with general call; data has been received; ACK has been returned
// TODO: What is this? Seems to be no bounds checking!
TWI_buf[TWI_bufPtr++] = TWDR;
TWI_statusReg.lastTransOK = TRUE; // Set flag transmission successfull.
// Reset the TWI Interupt to wait for a new event.
TWCR = (1<<TWEN)| // TWI Interface enabled
(1<<TWIE)|(1<<TWINT)| // Enable TWI Interupt and clear the flag to send byte
(1<<TWEA)|(0<<TWSTA)|(0<<TWSTO)| // Send ACK after next reception
(0<<TWWC); //
TWI_busy = 1;
break;
case TWI_SRX_STOP_RESTART: // A STOP condition or repeated START condition has been received while still addressed as Slave
// Enter not addressed mode and listen to address match
TWCR = (1<<TWEN)| // Enable TWI-interface and release TWI pins
(1<<TWIE)|(1<<TWINT)| // Enable interrupt and clear the flag
(1<<TWEA)|(0<<TWSTA)|(0<<TWSTO)| // Wait for new address match
(0<<TWWC); //
TWI_busy = 0; // We are waiting for a new address match, so we are not busy
break;
case TWI_SRX_ADR_DATA_NACK: // Previously addressed with own SLA+W; data has been received; NOT ACK has been returned
case TWI_SRX_GEN_DATA_NACK: // Previously addressed with general call; data has been received; NOT ACK has been returned
case TWI_STX_DATA_ACK_LAST_BYTE: // Last data byte in TWDR has been transmitted (TWEA = ļæ½0ļæ½); ACK has been received
// case TWI_NO_STATE // No relevant state information available; TWINT = ļæ½0ļæ½
case TWI_BUS_ERROR: // Bus error due to an illegal START or STOP condition
TWI_state = TWSR; //Store TWI State as errormessage, operation also clears noErrors bit
TWCR = (1<<TWSTO)|(1<<TWINT); //Recover from TWI_BUS_ERROR, this will release the SDA and SCL pins thus enabling other devices to use the bus
break;
default:
TWI_state = TWSR; // Store TWI State as errormessage, operation also clears the Success bit.
TWCR = (1<<TWEN)| // Enable TWI-interface and release TWI pins
(1<<TWIE)|(1<<TWINT)| // Keep interrupt enabled and clear the flag
(1<<TWEA)|(0<<TWSTA)|(0<<TWSTO)| // Acknowledge on any new requests.
(0<<TWWC); //
TWI_busy = 0; // Unknown status, so we wait for a new address match that might be something we can handle
}
}
 
/*
void example(){
unsigned char messageBuf[TWI_BUFFER_SIZE];
unsigned char TWI_slaveAddress;
// LED feedback port - connect port B to the STK500 LEDS
DDRB = 0xFF; // Set to ouput
PORTB = 0x55; // Startup pattern
// Own TWI slave address
TWI_slaveAddress = 0x10;
 
// Initialise TWI module for slave operation. Include address and/or enable General Call.
TWI_Slave_Initialise( (unsigned char)((TWI_slaveAddress<<TWI_ADR_BITS) | (TRUE<<TWI_GEN_BIT) ));
SEI();
 
// Start the TWI transceiver to enable reseption of the first command from the TWI Master.
TWI_Start_Transceiver();
 
// This example is made to work together with the AVR315 TWI Master application note. In adition to connecting the TWI
// pins, also connect PORTB to the LEDS. The code reads a message as a TWI slave and acts according to if it is a
// general call, or an address call. If it is an address call, then the first byte is considered a command byte and
// it then responds differently according to the commands.
 
// This loop runs forever. If the TWI is busy the execution will just continue doing other operations.
for(;;)
{
#ifdef POWER_MANAGEMENT_ENABLED
// Sleep while waiting for TWI transceiver to complete or waiting for new commands.
// If we have data in the buffer, we can't enter sleep because we have to take care
// of it first.
// If the transceiver is busy, we enter idle mode because it will wake up by all TWI
// interrupts.
// If the transceiver not is busy, we can enter power-down mode because next receive
// should be a TWI address match and it wakes the device up from all sleep modes.
if( ! TWI_statusReg.RxDataInBuf ) {
if(TWI_Transceiver_Busy()) {
MCUCR = (1<<SE)|(0<<SM2)|(0<<SM1)|(0<<SM0); // Enable sleep with idle mode
} else {
MCUCR = (1<<SE)|(0<<SM2)|(1<<SM1)|(0<<SM0); // Enable sleep with power-down mode
}
SLEEP();
} else {
NOP(); // There is data in the buffer, code below takes care of it.
}
#else // No power management
// Here you can add your own code that should be run while waiting for the TWI to finish
NOP(); // Put own code here.
#endif
// Check if the TWI Transceiver has completed an operation.
if ( ! TWI_Transceiver_Busy() )
{
// Check if the last operation was successful
if ( TWI_statusReg.lastTransOK )
{
// Check if the last operation was a reception
if ( TWI_statusReg.RxDataInBuf )
{
TWI_Get_Data_From_Transceiver(messageBuf, 2);
// Check if the last operation was a reception as General Call
if ( TWI_statusReg.genAddressCall )
{
// Put data received out to PORTB as an example.
PORTB = messageBuf[0];
}
else // Ends up here if the last operation was a reception as Slave Address Match
{
// Example of how to interpret a command and respond.
// TWI_CMD_MASTER_WRITE stores the data to PORTB
if (messageBuf[0] == TWI_CMD_MASTER_WRITE)
{
PORTB = messageBuf[1];
}
// TWI_CMD_MASTER_READ prepares the data from PINB in the transceiver buffer for the TWI master to fetch.
if (messageBuf[0] == TWI_CMD_MASTER_READ)
{
messageBuf[0] = PINB;
TWI_Start_Transceiver_With_Data( messageBuf, 1 );
}
}
}
else // Ends up here if the last operation was a transmission
{
NOP(); // Put own code here.
}
// Check if the TWI Transceiver has already been started.
// If not then restart it to prepare it for new receptions.
if ( ! TWI_Transceiver_Busy() )
{
TWI_Start_Transceiver();
}
}
else // Ends up here if the last operation completed unsuccessfully
{
TWI_Act_On_Failure_In_Last_Transmission( TWI_Get_State_Info() );
}
}
}
}*/
Property changes:
Added: svn:mime-type
+text/plain
\ No newline at end of property
/Transportables_Koptertool/PKT/branches/branch_FollowMeStep2/utils/twi_slave.h
0,0 → 1,121
/*****************************************************************************
*
* Atmel Corporation
*
* File : TWI_Slave.h
* Compiler : IAR EWAAVR 2.28a/3.10c
* Revision : $Revision: 2475 $
* Date : $Date: 2007-09-20 12:00:43 +0200 (to, 20 sep 2007) $
* Updated by : $Author: mlarsson $
*
* Support mail : avr@atmel.com
*
* Supported devices : All devices with a TWI module can be used.
* The example is written for the ATmega16
*
* AppNote : AVR311 - TWI Slave Implementation
*
* Description : Header file for TWI_slave.c
* Include this file in the application.
*
****************************************************************************/
/*! \page MISRA
*
* General disabling of MISRA rules:
* * (MISRA C rule 1) compiler is configured to allow extensions
* * (MISRA C rule 111) bit fields shall only be defined to be of type unsigned int or signed int
* * (MISRA C rule 37) bitwise operations shall not be performed on signed integer types
* As it does not work well with 8bit architecture and/or IAR
 
* Other disabled MISRA rules
* * (MISRA C rule 109) use of union - overlapping storage shall not be used
* * (MISRA C rule 61) every non-empty case clause in a switch statement shall be terminated with a break statement
*/
 
/****************************************************************************
TWI Status/Control register definitions
****************************************************************************/
 
#define TWI_BUFFER_SIZE 4 // Reserves memory for the drivers transceiver buffer.
// Set this to the largest message size that will be sent including address byte.
 
/****************************************************************************
Global definitions
****************************************************************************/
union TWI_statusReg_t // Status byte holding flags.
{
unsigned char all;
struct
{
unsigned char lastTransOK:1;
unsigned char RxDataInBuf:1;
unsigned char genAddressCall:1; // TRUE = General call, FALSE = TWI Address;
unsigned char unusedBits:5;
};
};
 
extern union TWI_statusReg_t TWI_statusReg;
 
 
/****************************************************************************
Function definitions
****************************************************************************/
void twi_slave_init( unsigned char );
unsigned char twi_slave_busy( void );
unsigned char twi_slave_get_status( void );
void twi_slave_start_with_data( unsigned char * , unsigned char );
void twi_slave_start( void );
unsigned char twi_slave_get_data( unsigned char *, unsigned char );
 
/****************************************************************************
Bit and byte definitions
****************************************************************************/
#define TWI_READ_BIT 0 // Bit position for R/W bit in "address byte".
#define TWI_ADR_BITS 1 // Bit position for LSB of the slave address bits in the init byte.
#define TWI_GEN_BIT 0 // Bit position for LSB of the general call bit in the init byte.
 
#define TRUE 1
#define FALSE 0
 
/****************************************************************************
TWI State codes
****************************************************************************/
// General TWI Master staus codes
#define TWI_START 0x08 // START has been transmitted
#define TWI_REP_START 0x10 // Repeated START has been transmitted
#define TWI_ARB_LOST 0x38 // Arbitration lost
 
// TWI Master Transmitter staus codes
#define TWI_MTX_ADR_ACK 0x18 // SLA+W has been tramsmitted and ACK received
#define TWI_MTX_ADR_NACK 0x20 // SLA+W has been tramsmitted and NACK received
#define TWI_MTX_DATA_ACK 0x28 // Data byte has been tramsmitted and ACK received
#define TWI_MTX_DATA_NACK 0x30 // Data byte has been tramsmitted and NACK received
 
// TWI Master Receiver staus codes
#define TWI_MRX_ADR_ACK 0x40 // SLA+R has been tramsmitted and ACK received
#define TWI_MRX_ADR_NACK 0x48 // SLA+R has been tramsmitted and NACK received
#define TWI_MRX_DATA_ACK 0x50 // Data byte has been received and ACK tramsmitted
#define TWI_MRX_DATA_NACK 0x58 // Data byte has been received and NACK tramsmitted
 
// TWI Slave Transmitter staus codes
#define TWI_STX_ADR_ACK 0xA8 // Own SLA+R has been received; ACK has been returned
#define TWI_STX_ADR_ACK_M_ARB_LOST 0xB0 // Arbitration lost in SLA+R/W as Master; own SLA+R has been received; ACK has been returned
#define TWI_STX_DATA_ACK 0xB8 // Data byte in TWDR has been transmitted; ACK has been received
#define TWI_STX_DATA_NACK 0xC0 // Data byte in TWDR has been transmitted; NOT ACK has been received
#define TWI_STX_DATA_ACK_LAST_BYTE 0xC8 // Last data byte in TWDR has been transmitted (TWEA = ļæ½0ļæ½); ACK has been received
 
// TWI Slave Receiver staus codes
#define TWI_SRX_ADR_ACK 0x60 // Own SLA+W has been received ACK has been returned
#define TWI_SRX_ADR_ACK_M_ARB_LOST 0x68 // Arbitration lost in SLA+R/W as Master; own SLA+W has been received; ACK has been returned
#define TWI_SRX_GEN_ACK 0x70 // General call address has been received; ACK has been returned
#define TWI_SRX_GEN_ACK_M_ARB_LOST 0x78 // Arbitration lost in SLA+R/W as Master; General call address has been received; ACK has been returned
#define TWI_SRX_ADR_DATA_ACK 0x80 // Previously addressed with own SLA+W; data has been received; ACK has been returned
#define TWI_SRX_ADR_DATA_NACK 0x88 // Previously addressed with own SLA+W; data has been received; NOT ACK has been returned
#define TWI_SRX_GEN_DATA_ACK 0x90 // Previously addressed with general call; data has been received; ACK has been returned
#define TWI_SRX_GEN_DATA_NACK 0x98 // Previously addressed with general call; data has been received; NOT ACK has been returned
#define TWI_SRX_STOP_RESTART 0xA0 // A STOP condition or repeated START condition has been received while still addressed as Slave
 
// TWI Miscellaneous status codes
#define TWI_NO_STATE 0xF8 // No relevant state information available; TWINT = ļæ½0ļæ½
#define TWI_BUS_ERROR 0x00 // Bus error due to an illegal START or STOP condition
Property changes:
Added: svn:mime-type
+text/plain
\ No newline at end of property
/Transportables_Koptertool/PKT/branches/branch_FollowMeStep2/utils/twimaster.c
0,0 → 1,202
/*************************************************************************
* Title: I2C master library using hardware TWI interface
* Author: Peter Fleury <pfleury@gmx.ch> http://jump.to/fleury
* File: $Id: twimaster.c,v 1.3 2005/07/02 11:14:21 Peter Exp $
* Software: AVR-GCC 3.4.3 / avr-libc 1.2.3
* Target: any AVR device with hardware TWI
* Usage: API compatible with I2C Software Library i2cmaster.h
**************************************************************************/
#include <inttypes.h>
#include <compat/twi.h>
 
#include <i2cmaster.h>
 
 
/* define CPU frequency in Mhz here if not defined in Makefile */
#ifndef F_CPU
#define F_CPU 16000000UL
#endif
 
/* I2C clock in Hz */
#define SCL_CLOCK 400000L
 
 
/*************************************************************************
Initialization of the I2C bus interface. Need to be called only once
*************************************************************************/
void i2c_init(void)
{
/* initialize TWI clock: 100 kHz clock, TWPS = 0 => prescaler = 1 */
TWSR = 0; /* no prescaler */
TWBR = ((F_CPU/SCL_CLOCK)-16)/2; /* must be > 10 for stable operation */
 
}/* i2c_init */
 
 
/*************************************************************************
Issues a start condition and sends address and transfer direction.
return 0 = device accessible, 1= failed to access device
*************************************************************************/
unsigned char i2c_start(unsigned char address)
{
uint8_t twst;
 
// send START condition
TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
 
// wait until transmission completed
while(!(TWCR & (1<<TWINT)));
 
// check value of TWI Status Register. Mask prescaler bits.
twst = TW_STATUS & 0xF8;
if ( (twst != TW_START) && (twst != TW_REP_START)) return 1;
 
// send device address
TWDR = address;
TWCR = (1<<TWINT) | (1<<TWEN);
 
// wail until transmission completed and ACK/NACK has been received
while(!(TWCR & (1<<TWINT)));
 
// check value of TWI Status Register. Mask prescaler bits.
twst = TW_STATUS & 0xF8;
if ( (twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK) ) return 1;
 
return 0;
 
}/* i2c_start */
 
 
/*************************************************************************
Issues a start condition and sends address and transfer direction.
If device is busy, use ack polling to wait until device is ready
Input: address and transfer direction of I2C device
*************************************************************************/
void i2c_start_wait(unsigned char address)
{
uint8_t twst;
 
 
while ( 1 )
{
// send START condition
TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
// wait until transmission completed
while(!(TWCR & (1<<TWINT)));
// check value of TWI Status Register. Mask prescaler bits.
twst = TW_STATUS & 0xF8;
if ( (twst != TW_START) && (twst != TW_REP_START)) continue;
// send device address
TWDR = address;
TWCR = (1<<TWINT) | (1<<TWEN);
// wail until transmission completed
while(!(TWCR & (1<<TWINT)));
// check value of TWI Status Register. Mask prescaler bits.
twst = TW_STATUS & 0xF8;
if ( (twst == TW_MT_SLA_NACK )||(twst ==TW_MR_DATA_NACK) )
{
/* device busy, send stop condition to terminate write operation */
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
// wait until stop condition is executed and bus released
while(TWCR & (1<<TWSTO));
continue;
}
//if( twst != TW_MT_SLA_ACK) return 1;
break;
}
 
}/* i2c_start_wait */
 
 
/*************************************************************************
Issues a repeated start condition and sends address and transfer direction
 
Input: address and transfer direction of I2C device
Return: 0 device accessible
1 failed to access device
*************************************************************************/
unsigned char i2c_rep_start(unsigned char address)
{
return i2c_start( address );
 
}/* i2c_rep_start */
 
 
/*************************************************************************
Terminates the data transfer and releases the I2C bus
*************************************************************************/
void i2c_stop(void)
{
/* send stop condition */
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
// wait until stop condition is executed and bus released
while(TWCR & (1<<TWSTO));
 
}/* i2c_stop */
 
 
/*************************************************************************
Send one byte to I2C device
Input: byte to be transfered
Return: 0 write successful
1 write failed
*************************************************************************/
unsigned char i2c_write( unsigned char data )
{
uint8_t twst;
// send data to the previously addressed device
TWDR = data;
TWCR = (1<<TWINT) | (1<<TWEN);
 
// wait until transmission completed
while(!(TWCR & (1<<TWINT)));
 
// check value of TWI Status Register. Mask prescaler bits
twst = TW_STATUS & 0xF8;
if( twst != TW_MT_DATA_ACK) return 1;
return 0;
 
}/* i2c_write */
 
 
/*************************************************************************
Read one byte from the I2C device, request more data from device
Return: byte read from I2C device
*************************************************************************/
unsigned char i2c_readAck(void)
{
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);
while(!(TWCR & (1<<TWINT)));
 
return TWDR;
 
}/* i2c_readAck */
 
 
/*************************************************************************
Read one byte from the I2C device, read is followed by a stop condition
Return: byte read from I2C device
*************************************************************************/
unsigned char i2c_readNak(void)
{
TWCR = (1<<TWINT) | (1<<TWEN);
while(!(TWCR & (1<<TWINT)));
return TWDR;
 
}/* i2c_readNak */
Property changes:
Added: svn:mime-type
+text/plain
\ No newline at end of property
/Transportables_Koptertool/PKT/branches/branch_FollowMeStep2/utils/xutils.c
0,0 → 1,765
/*****************************************************************************
* 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. *
*****************************************************************************/
 
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//+ xutils.c - erweiterte String-Funktionen, xprintf (Info nach History)
//+ und weitere Hilfsfunktionen wie z.B. UTCdatetime2local()
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
//############################################################################
//# HISTORY xutils.c
//#
//# 12.04.2014 OG
//# - chg: strncpyat(), strncpyat_P(), _strncpyat() erweitert um Parameter 'sepcharcount'
//#
//# 08.04.2014 OG
//# - add: strncpyat(), strncpyat_P(), _strncpyat()
//#
//# 28.02.2014 OG
//# - add: buffered_sprintf(), buffered_sprintf_P()
//# - add: buffer sprintf_buffer[]
//# - chg: PGMBUFF_SIZE und ARGBUFF_SIZE von 80 auf 40 geaendert
//#
//# 24.06.2013 OG
//# - add: strrtrim() entfernt Leerzeichen auf der rechten Seite
//#
//# 14.05.2013 OG
//# - chg: Kommentarkopf von UTCdatetime2local() aktualisiert
//#
//# 05.05.2013 OG
//# - chg: UTCdatetime2local() auf Config.timezone/summertime umgestellt
//# - add: include eeprom.h
//#
//# 04.05.2013 OG
//# - chg: umbenannt zu xutils.c
//#
//# 03.05.2013 OG
//# - add: UTCdatetime2local()
//# - fix: _xvsnprintf() Darstellung kleiner negativer Nachkommazahlen (-1<z<0)
//#
//# 29.04.2013 OG
//# - chg: Doku zu xprintf Ergaenzt bei 'bekannte Einschraenkungen'
//# - chg: includes reduziert auf das Notwendige
//#
//# 28.04.2013 OG - NEU
//############################################################################
 
 
//############################################################################
//# xprintf
//#
//# Diese Variante von printf ist angepasst auf das PKT:
//#
//# - Unterstuetzung von Festkomma-Integer Anzeige
//# - Overflow-Anzeige durch '*' wenn eine Zahl die Format-Maske sprengt
//# - progmen wird optional unterstuetz fuer den format-String als auch fuer
//# String Argumente
//# - strikte Einhaltung von Laengen einer Format-Maske
//# (ggf. wird die Ausgabe gekuerzt)
//#
//# In diesem Source sind nur die Basis-xprintf zum Erzeugen von formatierten
//# Strings. Die direkten Ausgabefunktionen auf den Screen sind in lcd.c
//# als lcdx_printf_at() und lcdx_printf_at_P().
//#
//# FORMAT ANGABEN:
//#
//# %d: dezimal int signed (Rechtsbuendige Ausgabe) (Wandlung via itoa)
//# "%d" arg: 1234 -> "1234"
//# "%5d" arg: 1234 -> " 1234"
//# "%5.2d" arg: 1234 -> " 12.34"
//# "%05d" arg: 123 -> "00123"
//# "%3.2d" arg: -13 -> " -0.13"
//#
//# %u: dezimal int unsigned (Rechtsbuendige Ausgabe) (Wandlung via utoa)
//# wie %d jedoch mittels utoa
//#
//# %h: hex int unsigned -> Hex-Zahl Rechtsbuendig, Laenge wird unterstuetzt z.B. "%4h"
//# %o: octal int unsigned -> Octal-Zahl Rechtsbuendig, Laenge wird unterstuetzt z.B. "%2o"
//# %b: binary int unsigned -> Binaer-Zahl Rechtsbuendig, Laenge wird unterstuetzt z.B. "%8b"
//#
//# %ld, %lu, %lh, %lo, %lb:
//# wie die obigen jedoch fuer long-zahlen (via ltoa, ultoa)
//# nur wenn define USE_XPRINTF_LONG gesetzt ist!
//# Bespiele: "%ld", "%5.6ld" usw.
//#
//# %s: String aus RAM -> Linksbuendig, Laenge wird unterstuetzt (z.B. "%8s")
//# %S: String aus progmem -> Linksbuendig, Laenge wird unterstuetzt (z.B. "%8s")
//#
//# %c: einzelnes char -> Linksbuendig, Laenge wird unterstuetzt (z.B. "%8s")
//# %%: Ausgabe von "%"
//#
//#
//# BEISPIELE:
//#
//# vorhanden in: osd/osdata.c, lcd/lcd.c
//#
//#
//# BEKANNTE EINSCHRAENKUNGEN:
//#
//# 1. padding '0' mit negativen Zahlen wenn padding aktiv ist ergibt z.B. "00-1.5"
//# 2. der Entwickler muss auf eine korrekte Format-Maske achten. Andernfalls
//# kommt es zu nicht vorhersehbaren Ausgaben.
//# 3. nicht in ISR's verwenden - dazu muss ggf. eine Anpassung durchgefuert werden
//#
//# KOMPILIER OPTIONEN
//#
//# define: USE_XPRINTF_LONG
//# Unterstuetzung von long int / unsigned long int ('l' Modifier in Maske)
// Wird in der main.h gesetzt
//############################################################################
 
#define USE_XPRINTF_LONG // Unterstuetzung von long integer - Achtung! Muss fuer PKT gesetzt sein
// da in Sourcen verwendet!
 
 
#include <avr/pgmspace.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <stdbool.h>
 
#include "../main.h"
#include "../timer/timer.h"
#include "../eeprom/eeprom.h"
 
 
#define PGMBUFF_SIZE 40 // max. 40 chars bei format-String aus progmem
#define ARGBUFF_SIZE 40 // buffer fuer xprintf Parameter (strings, itoa, utoa) (fuer ltoa ggf. anpassen)
 
 
#define SPRINTF_BUFFER_SIZE 40 // max. 40 Chars fuer den Buffer fuer xsnprintf(), xsnprintf_P()
char sprintf_buffer[SPRINTF_BUFFER_SIZE];
 
 
//----------------------
// xprintf parser data
//----------------------
typedef struct
{
uint8_t parse; // true / false
char cmd; // char: d u h o b s S c %
uint8_t prelen; // Vorkomma
uint8_t declen; // decimal (Nachkomma)
uint8_t point; // true / false
uint8_t uselong; // true / false
uint8_t mask; // true / false
char pad; // ' ' oder '0'
} xprintf_t;
 
 
//----------------------
// Buffers
//----------------------
char cmddigit[7];
char argbuff[ARGBUFF_SIZE];
char pgmbuff[PGMBUFF_SIZE];
 
 
//####################################################################################
 
 
//---------------------------------------------------------------------
// Basisfunktion von xprintf
// Doku: siehe oben
//---------------------------------------------------------------------
void _xvsnprintf( uint8_t useprogmem, char *buffer, uint8_t n, const char *format, va_list ap )
{
const char *p_fmt; // pointer auf den format-String
char *p_dst; // pointer auf den destination buffer
const char *p_str; // pointer auf einen arg-String wenn ein String ausgegeben werden soll
char *p_cmddigit = 0; // pointer auf den Digit-Buffer fuer eine Maske (Laenge/Nachkommastellen)
const char *p_fmtbuff; // pointer auf den format-Buffer (fuer progmem)
const char *p_argbuff; // pointer auf den argbuffer
uint8_t fmtlen, arglen, overflow;
uint8_t i,j,dec;
uint8_t dstcnt;
uint8_t minus;
xprintf_t cmd; // parser Daten
 
p_fmtbuff = format;
 
if( useprogmem ) // format von progmem in's RAM kopieren
{
strncpy_P( pgmbuff, format, PGMBUFF_SIZE);
pgmbuff[PGMBUFF_SIZE-1] = 0;
p_fmtbuff = pgmbuff;
}
 
cmd.parse = false;
p_fmt = p_fmtbuff-1; // -1 -> wird am Anfang der Schleife korrigiert
p_dst = buffer;
dstcnt = 0;
 
do
{
if( dstcnt >= n ) // max. Anzahl von Zeichen fuer Ziel 'buffer' erreicht?
break;
 
p_fmt++; // naechstes Zeichen von format
 
//########################
//# 1. PARSE
//########################
 
//------------------------
// START: parse cmd
//------------------------
if( cmd.parse == false && *p_fmt == '%' )
{
memset( &cmd, 0, sizeof(xprintf_t) ); // init
cmd.parse = true;
cmd.pad = ' ';
p_cmddigit = cmddigit;
continue;
}
 
//------------------------
// NO parse: copy char
//------------------------
if( cmd.parse == false )
{
*p_dst = *p_fmt;
p_dst++;
dstcnt++;
continue;
}
 
//------------------------
// set: pad (eine '0' ganz am Anfang der Formatmaske)
//------------------------
if( cmd.parse == true && *p_fmt == '0' && p_cmddigit == cmddigit )
{
cmd.pad = '0';
continue;
}
 
//------------------------
// set: vor/nach-kommastellen
//------------------------
if( cmd.parse == true && *p_fmt >= '0' && *p_fmt <= '9' )
{
*p_cmddigit = *p_fmt;
p_cmddigit++;
continue;
}
 
//------------------------
// set: point
//------------------------
if( cmd.parse == true && *p_fmt == '.' && cmd.point == false )
{
cmd.point = true;
*p_cmddigit = 0;
cmd.prelen = atoi( cmddigit );
p_cmddigit = cmddigit;
continue;
}
 
//------------------------
// set: uselong
//------------------------
#ifdef USE_XPRINTF_LONG
if( cmd.parse == true && *p_fmt == 'l' )
{
cmd.uselong = true;
continue;
}
#endif
 
//------------------------
// END: parse cmd
//------------------------
if( cmd.parse == true && (*p_fmt == 'd' || *p_fmt == 'u' || *p_fmt == 'x' || *p_fmt == 'b' || *p_fmt == 'o' ||
*p_fmt == 's' || *p_fmt == 'S' || *p_fmt == 'c' || *p_fmt == '%') )
{
cmd.cmd = *p_fmt;
cmd.parse = false;
 
*p_cmddigit = 0;
if( cmd.point == false ) cmd.prelen = atoi(cmddigit);
else cmd.declen = atoi(cmddigit);
 
if( cmd.point || cmd.prelen>0 )
cmd.mask = true;
}
 
 
//########################
//# 2. EXECUTE
//########################
 
//------------------------
// exec cmd: "d,u,x,b,o"
//------------------------
if( cmd.cmd == 'd' || cmd.cmd == 'u' || cmd.cmd == 'x' || cmd.cmd == 'b' || cmd.cmd == 'o' )
{
if( cmd.uselong )
{
#ifdef USE_XPRINTF_LONG
switch(cmd.cmd)
{
case 'd': ltoa ( va_arg(ap, long) , argbuff, 10); break; // LONG dezimal int signed
case 'u': ultoa( va_arg(ap, unsigned long), argbuff, 10); break; // LONG dezimal int unsigned
case 'x': ultoa( va_arg(ap, unsigned long), argbuff, 16); break; // LONG hex int unsigned
case 'b': ultoa( va_arg(ap, unsigned long), argbuff, 2); break; // LONG binary int unsigned
case 'o': ultoa( va_arg(ap, unsigned long), argbuff, 8); break; // LONG octal int unsigned
}
#endif
}
else
{
switch(cmd.cmd)
{
case 'd': itoa( va_arg(ap, int) , argbuff, 10); break; // dezimal int signed
case 'u': utoa( va_arg(ap, unsigned int), argbuff, 10); break; // dezimal int unsigned
case 'x': utoa( va_arg(ap, unsigned int), argbuff, 16); break; // hex int unsigned
case 'b': utoa( va_arg(ap, unsigned int), argbuff, 2); break; // binary int unsigned
case 'o': utoa( va_arg(ap, unsigned int), argbuff, 8); break; // octal int unsigned
}
}
 
minus = (argbuff[0] == '-');
arglen = strlen(argbuff);
 
fmtlen = cmd.prelen + cmd.declen + (cmd.point ? 1 : 0);
arglen = strlen(argbuff);
 
overflow = cmd.mask && // Zahl zu gross -> "*" anzeigen statt der Zahl
(arglen > cmd.prelen + cmd.declen || cmd.prelen < 1+minus);
 
if( overflow ) // overflow: Zahl passt nicht in Maske
{ // -> zeige '*.*'
for( i=0; (i < fmtlen) && (dstcnt < n); i++)
{
if( cmd.point && i==cmd.prelen ) *p_dst = '.';
else *p_dst = '*';
p_dst++;
dstcnt++;
}
}
else // else: if( overflow )
{
if( !cmd.mask ) // keine Maske: alles von der Zahl ausgeben
fmtlen = arglen;
 
p_argbuff = argbuff;
if( minus ) // wenn Zahl negativ: merken und auf dem argbuff nehmen
{
p_argbuff++;
arglen--;
}
 
//-----------------
// die Zahl wird 'Rueckwaerts' uebertragen
//-----------------
dec = -1; // wird am Anfang der Schleife auf 0 gesetzt
j = 1; // zaehler fuer argbuff
for( i=1; i<=fmtlen; i++ )
{
dec++; // Zaehler Dizmalstellen
 
if( dstcnt+fmtlen-i <= n ) // wenn Zielbuffer nicht ueberschritten
{
if( cmd.point && (dec == cmd.declen) ) // Dezimalpunkt setzen
{
p_dst[fmtlen-i] = '.';
continue;
}
 
if( j <= arglen ) // Ziffer uebertragen aus argbuff
{
p_dst[fmtlen-i] = p_argbuff[arglen-j];
j++;
continue;
}
 
if( cmd.declen > 0 && // Nachkomma und 1. Vorkommastelle ggf. auf '0'
(dec < cmd.declen || dec == cmd.declen+1) ) // setzen wenn die Zahl zu klein ist
{
p_dst[fmtlen-i] = '0';
continue;
}
 
if( minus && ( (cmd.pad == ' ') || // ggf. Minuszeichen setzen
(cmd.pad != ' ' && i == fmtlen) ) ) // Minuszeichen bei '0'-padding an erster Stelle setzen
{
minus = false;
p_dst[fmtlen-i] = '-';
continue;
}
 
p_dst[fmtlen-i] = cmd.pad; // padding ' ' oder '0'
} // end: if( dstcnt+fmtlen-i <= n )
}
p_dst += fmtlen;
dstcnt += fmtlen;
}
continue;
}
 
//------------------------
// exec cmd: "s", "S", "c"
//------------------------
if( cmd.cmd == 's' || cmd.cmd == 'S' || cmd.cmd == 'c' )
{
switch(cmd.cmd)
{
case 's': p_str = va_arg( ap, char *); // String aus dem RAM
break;
 
case 'S': strncpy_P( argbuff, va_arg( ap, char *), ARGBUFF_SIZE); // String liegt im progmem -> in's RAM kopieren
argbuff[ARGBUFF_SIZE-1] = 0;
p_str = argbuff;
break;
 
case 'c': argbuff[0] = va_arg( ap, int); // einzelnes char
argbuff[1] = 0;
p_str = argbuff;
break;
}
 
fmtlen = cmd.prelen;
arglen = strlen(p_str);
 
if( !cmd.mask ) // keine Maske: alles vom String ausgeben
fmtlen = arglen;
 
for( i=0; i<fmtlen; i++)
{
if( dstcnt < n ) // wenn Zielbuffer nicht ueberschritten
{
if( *p_str ) // char uebertragen
{
*p_dst = *p_str;
p_str++;
}
else // padding
{
*p_dst = ' ';
}
p_dst++;
}
dstcnt++;
}
 
continue;
}
 
//------------------------
// exec cmd: "%"
//------------------------
if( cmd.cmd == '%' )
{
*p_dst = '%';
p_dst++;
dstcnt++;
continue;
}
 
} while( (dstcnt < n) && *p_fmt );
 
*(p_dst + (dstcnt < n ? 0 : -1)) = 0; // terminierende 0 im Ausgabebuffer setzen
}
 
 
 
//---------------------------------------------------------------------
//---------------------------------------------------------------------
void xsnprintf( char *buffer, uint8_t n, const char *format, ... )
{
va_list ap;
 
va_start(ap, format);
_xvsnprintf( false, buffer, n, format, ap);
va_end(ap);
}
 
 
//---------------------------------------------------------------------
//---------------------------------------------------------------------
void xsnprintf_P( char *buffer, uint8_t n, const char *format, ... )
{
va_list ap;
 
va_start(ap, format);
_xvsnprintf( true, buffer, n, format, ap);
va_end(ap);
}
 
 
 
//-----------------------------------------------------------
// buffered_sprintf_P( format, ...)
//
// Ausgabe direkt in einen internen Buffer.
// Der Pointer auf den RAM-Buffer wird zurueckgegeben.
// Abgesichert bzgl. Buffer-Overflow.
//
// Groesse des Buffers: PRINTF_BUFFER_SIZE
//
// Parameter:
// format : String aus PROGMEM (siehe: xprintf in utils/xstring.h)
// ... : Parameter fuer 'format'
//-----------------------------------------------------------
char * buffered_sprintf( const char *format, ... )
{
va_list ap;
 
va_start( ap, format );
_xvsnprintf( false, sprintf_buffer, SPRINTF_BUFFER_SIZE, format, ap );
va_end(ap);
return sprintf_buffer;
}
 
 
 
//-----------------------------------------------------------
// buffered_sprintf_P( format, ...)
//
// Ausgabe direkt in einen internen Buffer.
// Der Pointer auf den RAM-Buffer wird zurueckgegeben.
// Abgesichert bzgl. Buffer-Overflow.
//
// Groesse des Buffers: PRINTF_BUFFER_SIZE
//
// Parameter:
// format : String aus PROGMEM (siehe: xprintf in utils/xstring.h)
// ... : Parameter fuer 'format'
//-----------------------------------------------------------
char * buffered_sprintf_P( const char *format, ... )
{
va_list ap;
 
va_start( ap, format );
_xvsnprintf( true, sprintf_buffer, SPRINTF_BUFFER_SIZE, format, ap );
va_end(ap);
return sprintf_buffer;
}
 
 
 
//--------------------------------------------------------------
// kopiert einen String von src auf dst mit fester Laenge und
// ggf. Space paddings rechts
//
// - fuellt ggf. den dst-String auf size Laenge mit Spaces
// - setzt Terminierung's 0 bei dst auf Position size
//--------------------------------------------------------------
void strncpyfill( char *dst, const char *src, size_t size)
{
uint8_t i;
uint8_t pad = false;
 
for( i=0; i<size; i++)
{
if(*src == 0) pad = true;
 
if( pad ) *dst = ' ';
else *dst = *src;
 
src++;
dst++;
}
dst--;
*dst = 0;
}
 
 
 
//--------------------------------------------------------------
// entfernt rechte Leerzeichen aus einem String
//--------------------------------------------------------------
void strrtrim( char *dst)
{
char *p;
 
p = dst + strlen(dst) - 1;
 
while( (p != dst) && (*p == ' ') ) p--;
 
if( (*p != ' ') && (*p != 0) ) p++;
*p = 0;
}
 
 
 
//--------------------------------------------------------------
// INTERN - fuer strncpyat(), strncpyat_P()
//--------------------------------------------------------------
void _strncpyat( char *dst, const char *src, size_t size, const char sepchar, uint8_t sepcharcount, uint8_t progmem)
{
uint8_t i;
 
if( progmem )
strncpy_P( dst, src, size);
else
strncpy( dst, src, size);
 
for( i=0; i<size; i++)
{
if( *dst == 0) return;
if( *dst == sepchar)
{
sepcharcount--;
if( sepcharcount==0 )
{
*dst = 0;
return;
}
}
dst++;
}
dst--;
*dst = 0;
}
 
 
//--------------------------------------------------------------
// strncpyat( dst, src, size, sepchar)
//
// kopiert einen String von 'src 'auf 'dst' mit max. Laenge 'size'
// oder bis 'sepchar' gefunden wird.
//
// src in PROGMEM
//--------------------------------------------------------------
void strncpyat( char *dst, const char *src, size_t size, const char sepchar, uint8_t sepcharcount)
{
_strncpyat( dst, src, size, sepchar, sepcharcount, false);
}
 
 
//--------------------------------------------------------------
// strncpyat_P( dst, src, size, sepchar)
//
// kopiert einen String von 'src 'auf 'dst' mit max. Laenge 'size'
// oder bis 'sepchar' gefunden wird.
//
// src in RAM
//--------------------------------------------------------------
void strncpyat_P( char *dst, const char *src, size_t size, const char sepchar, uint8_t sepcharcount)
{
_strncpyat( dst, src, size, sepchar, sepcharcount, true);
}
 
 
 
//--------------------------------------------------------------
// UTCdatetime2local( PKTdatetime_t *dtbuffer, PKTdatetime_t dt )
//
// konvertiert die UTC-Time 'dt' in die lokale Zeit und speichert
// dieses in 'dtbuffer' ab.
//
// Parameter:
//
// dtdst: Pointer Destination (PKTdatetime_t) (Speicher muss alloziiert sein!)
// dtsrc: Pointer Source (PKTdatetime_t)
//
// Hinweise:
//
// Schaltjahre (bzw. der 29.02.) werden nicht unterstuetzt
//--------------------------------------------------------------
void UTCdatetime2local( PKTdatetime_t *dtdst, PKTdatetime_t *dtsrc )
{
int8_t timeoffset;
int32_t v;
int8_t diff;
// 01 02 03 04 05 06 07 08 09 10 11 12 Monat
int8_t daymonth[] = {31,28,31,30,31,30,31,31,30,31,30,31};
 
//--------------------------
// timezone: Einstellbereich -12 .. 0 .. 12 (+1 = Berlin)
// summertime: Einstellung: 0 oder 1 (0=Winterzeit, 1=Sommerzeit)
//--------------------------
timeoffset = Config.timezone + Config.summertime;
//timeoffset = 2; // solange noch nicht in PKT-Config: Berlin, Sommerzeit
 
 
memcpy( dtdst, dtsrc, sizeof(PKTdatetime_t) ); // copy datetime to destination
 
//--------------------------
// Zeitzonenanpassung
//--------------------------
if( dtdst->year != 0 && dtdst->month >= 1 && dtdst->month <= 12 ) // nur wenn gueltiges Datum vorhanden
{
//--------------------------
// 1. Sekunden
//--------------------------
v = (int32_t)dtdst->seconds;
v += timeoffset*3600; // Stunden korrigieren
diff = 0;
 
if( v > 86400 ) // Tagesueberschreitung? (86400 = 24*60*60 bzw. 24 Stunden)
{
v -= 86400;
diff++; // inc: Tag
}
else if( v < 0 ) // Tagesunterschreitung?
{
v += 86400;
diff--; // dec: Tag
}
dtdst->seconds = (uint32_t)v; // SET: seconds
 
//--------------------------
// 2. Tag
//--------------------------
v = (int32_t)dtdst->day;
v += diff;
diff = 0;
 
if( v > daymonth[dtdst->month-1] ) // Monatsueberschreitung?
{
v = 1; // erster Tag des Monats
diff++; // inc: Monat
}
else if( v < 1 ) // Monatsunterschreitung?
{
if( dtdst->month > 1 )
v = daymonth[dtdst->month-1-1]; // letzter Tag des vorherigen Monats
else
v = 31; // letzter Tag im Dezember des vorherigen Jahres
diff--; // dec: Monat
}
dtdst->day = (uint8_t)v; // SET: day
 
//--------------------------
// 3. Monat
//--------------------------
v = (int32_t)dtdst->month;
v += diff;
diff = 0;
 
if( v > 12 ) // Jahresueberschreitung?
{
v = 1;
diff++; // inc: Jahr
}
else if( v < 1 ) // Jahresunterschreitung?
{
v = 12;
diff--; // dec: Jahr
}
dtdst->month = (uint8_t)v; // SET: month
 
//--------------------------
// 4. Jahr
//--------------------------
dtdst->year += diff; // SET: year
}
}
Property changes:
Added: svn:mime-type
+text/plain
\ No newline at end of property
/Transportables_Koptertool/PKT/branches/branch_FollowMeStep2/utils/xutils.h
0,0 → 1,64
/*****************************************************************************
* 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 xutils.h
//#
//# 12.04.2014 OG
//# - chg: strncpyat(), strncpyat_P(), _strncpyat() erweitert um Parameter 'sepcharcount'
//#
//# 08.04.2014 OG
//# - add: strncpyat(), strncpyat_P()
//#
//# 28.02.2014 OG
//# - add: buffered_sprintf(), buffered_sprintf_P()
//#
//# 24.06.2013 OG
//# - add: strrtrim()
//#
//# 04.05.2013 OG
//# - chg: umbenannt zu xutils.h
//#
//# 03.05.2013 OG
//# - add: UTCdatetime2local()
//#
//# 28.04.2013 OG - NEU
//############################################################################
 
#ifndef _XUTILS_H
#define _XUTILS_H
 
#include <stdarg.h>
 
 
void _xvsnprintf( uint8_t useprogmem, char *buffer, uint8_t n, const char *format, va_list ap );
void xsnprintf( char *buffer, uint8_t n, const char *format, ... );
void xsnprintf_P( char *buffer, uint8_t n, const char *format, ... );
 
char *buffered_sprintf( const char *format, ... );
char *buffered_sprintf_P( const char *format, ... );
 
void strncpyfill( char *dst, const char *src, size_t size);
void strrtrim( char *dst);
void strncpyat( char *dst, const char *src, size_t size, const char sepchar, uint8_t sepcharcount);
void strncpyat_P( char *dst, const char *src, size_t size, const char sepchar, uint8_t sepcharcount);
 
 
void UTCdatetime2local( PKTdatetime_t *dtdst, PKTdatetime_t *dtsrc );
 
#endif
Property changes:
Added: svn:mime-type
+text/plain
\ No newline at end of property
/Transportables_Koptertool/PKT/branches/branch_FollowMeStep2/utils/.
Property changes:
Added: svn:ignore
+_old
+
+maniacbug-mighty-1284p-68ed99c
+
+Arduino
+
+_doc
+
+maniacbug-mighty-1284p-68ed99c.zip