/* SwissBetty-TV-Fernbedienung: Tasten.c */

#if !defined (GCC)
#pragma thumb
#endif

/*
Die Tasten sind in einer Matrix aus 7 Outputs und 6 Inputs angeordnet,
macht 42 Tasten. Ist keine Taste gedrückt, sind alle Inputs high.
Outputs: P2.18 bis P2.24
Inputs:  P1.16 bis P1.19 und P1.21 und P1.22
Zusätzlich gibt es ein diskretes AND über alle Inputs,
das an EINT3 (P0.30) geht und über diesen Interrupt via EXTWAKE.8
die CPU aufweckt, wenn eine Taste gedrückt wird. Dazu müssen allerdings
alle Outputs auf low stehen. Ist dann P0.30 low, dann ist zumindest
eine Taste gedrückt.
 */

#include "LPC22xx.h"
#include "StdTypes.h"
#include "Tasten.h"

#define SenseMaske   0x006F0000
#define AlleTreiber  0x01FC0000


#define tastenpufferlaenge 8

volatile int TastenWrZeig;
volatile int TastenRdZeig;
byte TastenPuffer[tastenpufferlaenge];


/* Testen, ob eine Taste im Tastenpuffer ist */
bool  IsKeyAvailable (void)
{ return (TastenWrZeig != TastenRdZeig); }


/* Testen, ob überhaupt eine Taste gedrückt ist */
bool  IsKeyPressed (void)
{ IO2CLR = AlleTreiber;             // alle Outputs auf low setzen
  IO2DIR = IO2DIR | AlleTreiber;    // alle Outputs auf Ausgang setzen
  /* wenn einer der Sense-Eingänge low ist, dann ist was gedrückt */
  if ((FIO1PIN & SenseMaske) != SenseMaske) return TRUE;
  return FALSE;
}

/* Taste aus Puffer abholen */
byte GetKey(void)
{ byte b;
  int rp;

  if (!IsKeyAvailable()) return 0;
  rp = TastenRdZeig;
  b = TastenPuffer[rp];
  TastenRdZeig = (rp+1) & (tastenpufferlaenge-1);
  return b;
}

const char Tastencodes[42] =
{  'r',   /*  0 roter Knopf */
   'g',   /*  1 grüner knopf */
   '2',   /*  2 Ziffer 2 */
   '3',   /*  3 Ziffer 3 */
   '*',   /*  4 ON/OFF */
   'T',   /*  5 TV */
   'I',   /*  6 info */
  0x1E,   /*  7 dk screen? */
   'Q',   /*  8 mute */
   '<',   /*  9 prog- */
   'b',   /* 10 blauer Knopf */
   'y',   /* 11 gelber Knopf */
   'M',   /* 12 menu */
   'P',   /* 13 pip */
  0x14,   /* 14 down */
   '>',   /* 15 prog+ */
  0x19,   /* 16 screen */
  0x1A,   /* 17 white screen? */
   '-',   /* 18 vol- */
   '\\',  /* 19 -/-- (du mußt es doppelt sagen bei C) */
  0x0D,   /* 20 OK = Enter*/
  0x1B,   /* 21 exit (27 esc)*/
   'W',   /* 22 16:9 */
   '/',   /* 23 A/B */
   '+',   /* 24 vol+ */
   '7',   /* 25 Ziffer 7*/
  0x11,   /* 26 links */
  0x12,   /* 27 rechts */
  0x1C,   /* 28 AV */
   '0',   /* 29 Ziffer 0 */
  0x1D,   /* 30 betty    */
   '4',   /* 31 Ziffer 4 */
  0x13,   /* 32 up */
   'D',   /* 33 Taste D  */
   '9',   /* 34 Ziffer 9 */
   '8',   /* 35 Ziffer 8 */
   'A',   /* 36 Taste A  */
   '1',   /* 37 Ziffer 1 */
   'B',   /* 38 Taste B  */
   'C',   /* 39 Taste C  */
   '6',   /* 40 Ziffer 6 */
   '5'    /* 41 Ziffer 5 */
};




/* Tasten-Nummer in Textzeichen wandeln */
char TranslateKeynum (byte KeyCode)
{ if (KeyCode > 41) return 0;
  return Tastencodes[KeyCode];
}

/************************************************************************************/


/* alle gedrückten Tasten ermitteln
   ================================
praktisch sind nur 2..3 gleichzeitig gedrückte Tasten ermittelbar,
bei mehr macht die Hardware nicht mehr so richtig mit
 */
int64 TastenZustand (void)
{ int64 tasten;
  dword outmask;
  dword i, j;

  IO2SET = AlleTreiber - (1<<18);              // alle Treiber bis auf 1. auf high setzen
  IO2CLR = (1<<18);                            // ersten Treiber auf low setzen
  IO2DIR = (IO2DIR & ~AlleTreiber) | (1<<18);  // alle Treiber außer dem ersten auf Tristate setzen
  tasten = -1;                                 // start mit allen Bits high
  outmask = (1<<18);                           // für nächste Treiber
  do                                           // von P2.18 bis P2.24
  { i = ((FIO1PIN>>16) & 0xF);                 // die ersten 4 Inputs abfragen
    j = ((FIO1PIN>>21) & 3);                   // die letzten 2 Inputs abfragen
    IO2SET  = outmask;                         // Treiber high
    IO2DIR  = IO2DIR & ~outmask;               // Treiber wieder tristate
    outmask = outmask<<1;                      // nächster Treiber
    if (outmask < (1<<25))
    { IO2CLR  = outmask;
      IO2DIR  = IO2DIR | outmask;
    }
    tasten  = (tasten<<4) | i;                 // Tastenbits einstapeln
    tasten  = (tasten<<2) | j;
  } while (outmask < (1<<25));

  IO2CLR = AlleTreiber;                        // alle Outputs wieder auf low setzen
  IO2DIR = IO2DIR | AlleTreiber;               // alle Outputs wieder auf Ausgang setzen

  return ~tasten;                              // invertiert.
}

void TasteEintragen (int64 bits)
{ int wp, wpx;
  byte b;

  if (!bits) return;
  wp = TastenWrZeig;
  wpx = (wp + 1) & (tastenpufferlaenge-1);
  if (wpx!=TastenRdZeig)
  { b = 0;
    while ((bits & 1)==0)
    { ++b;
      bits = bits>>1;
    }
    TastenPuffer[wp] = b;
    TastenWrZeig = wpx;
  }
}

#define Prellzeit 6
#define Repetier_lang 90
#define Repetier_kurz 10

volatile int RepCounter;
volatile int PrellCounter;


void Tasten_Bonze (void)
{ int64 ta;

  ta = TastenZustand();
  if (PrellCounter)                     /* wenn wir noch beim Entprellen sind */
  { if (ta)                             /* wenn noch ne Taste gedrückt ist    */
    { PrellCounter = Prellzeit;
      if (RepCounter)
      { --RepCounter;
        return;
      }
      else
      { RepCounter = Repetier_kurz;
        TasteEintragen(ta);
        return;
      }
    }
    else
    { --PrellCounter;
      return;
    }
  }
  else
  { if (!(ta)) return;
    TasteEintragen(ta);
    RepCounter = Repetier_lang;
    PrellCounter = Prellzeit;
  }
}

void Tasten_Init (void)
{ IO2CLR = AlleTreiber;           // alle Outputs auf low setzen
  IO2DIR = IO2DIR | AlleTreiber;  // alle Outputs auf Ausgang setzen
  TastenWrZeig = TastenRdZeig = 0;
}

