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

      kbd.c
      v1.0 (10/02/2003)

      Generic keyboard scan driver. This driver can scan up to 64 keys.

      Input and output may be on the same resister. In this case you can scan
      up to 16 keys.
      You can use one register for output and an other for input. Yon can scan
      in this case up to 64 keys.

      Written by Philippe Corbes <philippe.corbes@laposte.net>
      This code is free for personal use. 
      You need my agreement for a commercial use. 

      USAGE:
      
          kbd_Getc(c) Will return a key value if pressed or /0 if not 
                      This function should be called frequently so as 
                      not to miss a key press.    

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

  #include    <pic.h>
  #include    "kbd.h"         // Constantes definitions
  #include    "kbd_keys.h"    // Keyboard map definitions



  #if KBD_LINES == 1
  #define ALL_LINES (LINE0)
  #elif KBD_LINES == 2
  #define ALL_LINES (LINE0|LINE1)
  #elif KBD_LINES == 3
  #define ALL_LINES (LINE0|LINE1|LINE2)
  #elif KBD_LINES == 4
  #define ALL_LINES (LINE0|LINE1|LINE2|LINE3)
  #elif KBD_LINES == 5
  #define ALL_LINES (LINE0|LINE1|LINE2|LINE3|LINE4)
  #elif KBD_LINES == 6
  #define ALL_LINES (LINE0|LINE1|LINE2|LINE3|LINE4|LINE5)
  #elif KBD_LINES == 7
  #define ALL_LINES (LINE0|LINE1|LINE2|LINE3|LINE4|LINE5|LINE6)
  #elif KBD_LINES == 8
  #define ALL_LINES (LINE0|LINE1|LINE2|LINE3|LINE4|LINE5|LINE6|LINE7)
  #else
  #warning KBD_LINES is greater than 8 
  #endif

  #if (KBD_IO == 1)
  #if KBD_COLS == 1
  #define ALL_COLS (ALL_LINES|COL0)
  #elif KBD_COLS == 2
  #define ALL_COLS (ALL_LINES|COL0|COL1)
  #elif KBD_COLS == 3
  #define ALL_COLS (ALL_LINES|COL0|COL1|COL2)
  #elif KBD_COLS == 4
  #define ALL_COLS (ALL_LINES|COL0|COL1|COL2|COL3)
  #elif KBD_COLS == 5
  #define ALL_COLS (ALL_LINES|COL0|COL1|COL2|COL3|COL4)
  #elif KBD_COLS == 6
  #define ALL_COLS (ALL_LINES|COL0|COL1|COL2|COL3|COL4|COL5)
  #elif KBD_COLS == 7
  #define ALL_COLS (ALL_LINES|COL0|COL1|COL2|COL3|COL4|COL5|COL6)
  #elif KBD_COLS == 8
  #define ALL_COLS (ALL_LINES|COL0|COL1|COL2|COL3|COL4|COL5|COL6|COL7)
  #else
  #warning KBD_COLS is greater than 8 
  #endif
  #else
  #if KBD_COLS == 1
  #define ALL_COLS (COL0)
  #elif KBD_COLS == 2
  #define ALL_COLS (COL0|COL1)
  #elif KBD_COLS == 3
  #define ALL_COLS (COL0|COL1|COL2)
  #elif KBD_COLS == 4
  #define ALL_COLS (COL0|COL1|COL2|COL3)
  #elif KBD_COLS == 5
  #define ALL_COLS (COL0|COL1|COL2|COL3|COL4)
  #elif KBD_COLS == 6
  #define ALL_COLS (COL0|COL1|COL2|COL3|COL4|COL5)
  #elif KBD_COLS == 7
  #define ALL_COLS (COL0|COL1|COL2|COL3|COL4|COL5|COL6)
  #elif KBD_COLS == 8
  #define ALL_COLS (COL0|COL1|COL2|COL3|COL4|COL5|COL6|COL7)
  #else
  #warning KBD_COLS is greater than 8 
  #endif
  #endif


  char kbd_Getc() {
     static unsigned int      kbd_count;
     static short int         kbd_down;
     static unsigned char     col;

     unsigned char kchar;
     unsigned char row;

     kchar='\0';
     if(++kbd_count>KBD_DEBOUNCE_FACTOR) {
  #if (KBD_IO == 2)
          kbd_lc |= ALL_LINES;
  #endif
         switch (col) {
  #ifdef KBD_COLS  
           case 0   :
  #if (ALL_COLS == 0xff)
                      kbd_cc = ~COL0;
                      kbd_c  = COL0;
  #else
                      kbd_cc = (kbd_cc&~ALL_COLS)|(ALL_COLS&~COL0);
                      kbd_c  = (kbd_c&~ALL_COLS)|COL0;
  #endif
                      break;
  #if KBD_COLS > 1
           case 1   :
  #if (ALL_COLS == 0xff)
                      kbd_cc = ~COL1;
                      kbd_c  = COL1;
  #else
                      kbd_cc = (kbd_cc&~ALL_COLS)|(ALL_COLS&~COL1);
                      kbd_c  = (kbd_c&~ALL_COLS)|COL1;
  #endif
                      break;
  #if KBD_COLS > 2
           case 2   :
  #if (ALL_COLS == 0xff)
                      kbd_cc = ~COL2;
                      kbd_c  = COL2;
  #else
                      kbd_cc = (kbd_cc&~ALL_COLS)|(ALL_COLS&~COL2);
                      kbd_c  = (kbd_c&~ALL_COLS)|COL2;
  #endif
                      break;
  #if KBD_COLS > 3
           case 3   :
  #if (ALL_COLS == 0xff)
                      kbd_cc = ~COL3;
                      kbd_c  = COL3;
  #else
                      kbd_cc = (kbd_cc&~ALL_COLS)|(ALL_COLS&~COL3);
                      kbd_c  = (kbd_c&~ALL_COLS)|COL3;
  #endif
                      break;
  #if KBD_COLS > 4
           case 4   :
  #if (ALL_COLS == 0xff)
                      kbd_cc = ~COL4;
                      kbd_c  = COL4;
  #else
                      kbd_cc = (kbd_cc&~ALL_COLS)|(ALL_COLS&~COL4);
                      kbd_c  = (kbd_c&~ALL_COLS)|COL4;
  #endif
                      break;
  #if KBD_COLS > 5
           case 5   :
  #if (ALL_COLS == 0xff)
                      kbd_cc = ~COL5;
                      kbd_c  = COL5;
  #else
                      kbd_cc = (kbd_cc&~ALL_COLS)|(ALL_COLS&~COL5);
                      kbd_c  = (kbd_c&~ALL_COLS)|COL5;
  #endif
                      break;
  #if KBD_COLS > 6 
           case 6   :
  #if (ALL_COLS == 0xff)
                      kbd_cc = ~COL6;
                      kbd_c  = COL6;
  #else
                      kbd_cc = (kbd_cc&~ALL_COLS)|(ALL_COLS&~COL6);
                      kbd_c  = (kbd_c&~ALL_COLS)|COL6;
  #endif
                      break;
  #if KBD_COLS > 7
           case 7   :
  #if (ALL_COLS == 0xff)
                      kbd_cc = ~COL7;
                      kbd_c  = COL7;
  #else
                      kbd_cc = (kbd_cc&~ALL_COLS)|(ALL_COLS&~COL7);
                      kbd_c  = (kbd_c&~ALL_COLS)|COL7;
  #endif
                      break;
  #endif
  #endif
  #endif
  #endif
  #endif
  #endif
  #endif
  #endif
         }

         if(kbd_down!=0) {
            // Wait for key up
            kbd_down = kbd_l & ALL_LINES;
         } else {
            if((kbd_l & (ALL_LINES))!=0) {
  #ifdef KBD_LINES
               if((kbd_l & LINE0)!=0)
                 row = 0;
  #if KBD_LINES > 1
               else if((kbd_l & LINE1)!=0)
                 row = 1;
  #if KBD_LINES > 2
               else if((kbd_l & LINE2)!=0)
                 row = 2;
  #if KBD_LINES > 3
               else if((kbd_l & LINE3)!=0)
                 row = 3;
  #if KBD_LINES > 4
               else if((kbd_l & LINE4)!=0)
                 row = 4;
  #if KBD_LINES > 5
               else if((kbd_l & LINE5)!=0)
                 row = 5;
  #if KBD_LINES > 6
               else if((kbd_l & LINE6)!=0)
                 row = 6;
  #if KBD_LINES > 7
               else if((kbd_l & LINE7)!=0)
                 row = 7;
  #endif
  #endif
  #endif
  #endif
  #endif
  #endif
  #endif
               kchar = KEYS[row][col];
               kbd_down = 1;
  #endif
            } else {
               ++col;
               if(col==KBD_COLS)
                 col = 0;
            }
         }
        kbd_count = 0;
     }
    kbd_cc |= ALL_COLS;
    return(kchar);
  }