/*
 * GeneralDefinitions.h
 *
 * Created: 03.06.2012
 * Author: Ulli
 * 10.12.2015
 *   Makro 'TODO' hinzugefügt
 *   Definition für Typ 'bool' bei C++ angepasst
 * 01.01.2016
 *   Makro-Definition für min() und max() unterscheidlich für C und C++
 */ 


#ifndef GENERALDEFINITIONS_H_
#define GENERALDEFINITIONS_H_

#ifndef _AVR_IO_H_
 #include <avr/io.h>
#endif

//************************************************************************
// min, max (typsicher!)
//************************************************************************
#ifdef max
 #pragma message "redefining max()"
 #undef max
#endif
#ifdef min
 #pragma message "redefining min()"
 #undef min
#endif

#ifdef __cplusplus
  template <typename T> inline T max(const T a, const T b) { return a > b ? a : b; }
  template <typename T> inline T min(const T a, const T b) { return a > b ? b : a; }
#else
  #define max(a,b) \
  ({ typeof (a) _a = (a); \
     typeof (b) _b = (b); \
     _a > _b ? _a : _b; })

  #define min(a,b) \
  ({ typeof (a) _a = (a); \
     typeof (b) _b = (b); \
     _a > _b ? _b : _a; })
#endif



#ifdef __cplusplus
  extern "C"{
#endif

//************************************************************************
// bool, true, false
//************************************************************************
#ifndef __cplusplus // c++ implementiert den Datentyp bool
  typedef enum
  { false = 0,
    true  = !false
  } bool;
#endif

#define FALSE 0 // für den Precompiler
#define TRUE 1
#define NONE -1

//************************************************************************
// Stringification 
// stringify(Dummy) ==> "Dummy"
//************************************************************************
#define stringify(str) #str

//************************************************************************
// DDR(x), PIN(x)
// Berechnung der Registeradressen basierend auf den PORT-Angaben
//************************************************************************
// Beispiel: DDR(PORTB) |= _BV(PB2);
//           PIN(PORTB) |= _BV(PB2);

#define DDR(x) (*(&x - 1))      // Adresse des DDR von PORTx
#if defined(__AVR_ATmega64__) || defined(__AVR_ATmega128__)
    // Beim ATmega64/128 ist PINF auf port 0x00 und nicht 0x60
    #define PIN(x) ( &PORTF==&(x) ? _SFR_IO8(0x00) : (*(&x - 2)) )
#else
    #define PIN(x) (*(&x - 2))  // Adresse des Input-Register von PORTx         
#endif


//************************************************************************
// Funktionen
//************************************************************************
// nop
//************************************************************************
inline void nop(void)
{ __asm volatile ("nop");}

//
//************************************************************************
// ALWAYS_INLINE erzwingt, dass eine Funktion inline eingebunden wird
//************************************************************************
#define ALWAYS_INLINE static __attribute__((always_inline)) inline


//************************************************************************
// min, max (typsicher!)
//************************************************************************

inline void swapBytes(uint8_t *x, uint8_t *y)
{ uint8_t t = *x;
  *x = *y;
  *y = t;
}

inline void swap(int *x, int *y)
{ int t = *x;
  *x = *y;
  *y = t;
}

//************************************************************************
// ClearBit, SetBit, ToggleBit, GetBit
//************************************************************************
#define ClearBit(sfr, bit)     (sfr &= ~_BV(bit))     // ClearBit(PORTA, PA2);
#define SetBit(sfr, bit)       (sfr |=  _BV(bit))     // SetBit(PORTA, PA2);
#define ToggleBit(sfr, bit)    (sfr ^=  _BV(bit))     // ToggleBit(PORTA, PA2);
#define GetBit(sfr, bit)       (sfr &   _BV(bit))     // x = GetBit(PORTA, PA2);


//************************************************************************
// Zugriff auf eine Bits eines Registers über eine Struktur
//************************************************************************
typedef struct  {
	bool P0: 1;
	bool P1: 1;
	bool P2: 1;
	bool P3: 1;
	bool P4: 1;
	bool P5: 1;
	bool P6: 1;
	bool P7: 1;
} Register_t;


#ifdef PORTA
 #define RPORTA (*((volatile Register_t *) &PORTA))
 #define RDDRA  (*((volatile Register_t *) &DDR(PORTA)))
 #define RPINA  (*((volatile Register_t *) &PIN(PORTA)))
#endif

#ifdef PORTB
 #define RPORTB (*((volatile Register_t *) &PORTB))
 #define RDDRB  (*((volatile Register_t *) &DDR(PORTB)))
 #define RPINB  (*((volatile Register_t *) &PIN(PORTB)))
#endif

#ifdef PORTC
 #define RPORTC (*((volatile Register_t *) &PORTC))
 #define RDDRC  (*((volatile Register_t *) &DDR(PORTC)))
 #define RPINC  (*((volatile Register_t *) &PIN(PORTC)))
#endif

#ifdef PORTD
 #define RPORTD (*((volatile Register_t *) &PORTD))
 #define RDDRD  (*((volatile Register_t *) &DDR(PORTD)))
 #define RPIND  (*((volatile Register_t *) &PIN(PORTD)))
#endif

//************************************************************************
// Festlegung allgemein genutzter Register
//************************************************************************
// Dies ist eine Alternative zum Abschalten der Interrupts.
// Interrupt-Routinen können beim Eintreffen einer Unterbrechung dieses Register auf TRUE setzen.
//
// Vor dem Eintritt in eine zeitkritischen Funktionen wird das Register gelöscht (FALSE).
// Nach Beendigung des zeitkritischen Teils kann dann geprüft werden, ob die Funktion
// durch einen Interrupt unterbrochen wurde.

register uint8_t InteruptOccured asm("r7"); 

//************************************************************************
// Hilfsfunktion TODO
//************************************************************************
#define DO_PRAGMA(x) _Pragma (#x)
#define TODO(x) DO_PRAGMA(message ("TODO - " #x))
#define todo(x) DO_PRAGMA(message ("TODO - " #x))
#define ToDo(x) DO_PRAGMA(message ("TODO - " #x))
// TODO(Nacharbeit notwendig)
// Gibt bei jedem Compile-Vorgang die Meldung "Nacharbeit notwendig" aus

#ifdef __cplusplus
  } // extern "C"
#endif

#endif /* GENERALDEFINITIONS_H_ */