/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 |