/* 
 * File:   Lab2-keypad-klee.c
 * Author: rich
 *
 * Created on February 23, 2014, 8:26 AM
 */
/** I N C L U D E S **************************************************/
#include <stdio.h>
#include <stdlib.h>
#include "Lab2-keypad-klee.h" // header file
#include <xc.h>         //for NOP() and delays
#include <p18cxxx.h>
#include <string.h>

/** C O N F I G U R A T I O N   B I T S ******************************/
// CONFIG1H -Internal OSC running, Fail safe clock mon disabled, Osc switchover mode disabled
#pragma config FOSC = INTIO67, FCMEN = OFF, IESO = OFF
// CONFIG2L - Power up timer disabled, Brown out reset disabled Brown out volatage =3.0v
#pragma config PWRT = OFF, BOREN = OFF, BORV = 30
// CONFIG2H  -watchdog timer disabled, Watch dog timer postscale  select - 1:32768
#pragma config WDTEN = OFF, WDTPS = 32768
// CONFIG3H - Master clear enabled RE3 is the clear pin, Low power timer 1 osc - high power, PORT B <4:0> A/D  - are digital i/o, CCP2 =muxed with RC1
#pragma config MCLRE = ON, LPT1OSC = OFF, PBADEN = OFF, CCP2MX = PORTC
// CONFIG3H - Stack full/underflow reset - no, Single supply ICSP - disabled, Extended instruction set - disabled, Background debugger - enabled (RB6 and RB7 are dedicated pins)
#pragma config STVREN = ON, LVP = OFF, XINST = OFF, DEBUG = ON
// the rest of the config registers are all protection enablements - nothing is protected
#pragma config CP0 = OFF, CP1 = OFF, CP2 = OFF, CP3 = OFF                   // CONFIG5L
#pragma config CPB = OFF, CPD = OFF                                         // CONFIG5H
#pragma config WRT0 = OFF, WRT1 = OFF, WRT2 = OFF, WRT3 = OFF               // CONFIG6L
#pragma config WRTB = OFF, WRTC = OFF, WRTD = OFF                           // CONFIG6H
#pragma config EBTR0 = OFF, EBTR1 = OFF, EBTR2 = OFF, EBTR3 = OFF           // CONFIG7L
#pragma config EBTRB = OFF                                                  // CONFIG7H


unsigned char n;
unsigned char Row;
unsigned char Col;
unsigned char error;
unsigned char RawDigit;
unsigned char HexBack;
 

void main(void) {
ANSELH = 0;                     //  make all bits  of Port B digital - they will always be digital
ANSEL  = 0;                     //  make all bits  of Port A digital - they will always be digilal
TRISD =0;                       //  Port for LEDs configured as output
LATD = 0;                       // Make sure LEDS are off
INTCON2bits.RBPU = 0;           //  enable pull ups on Port B
WPUB = 0b00111111;
while (1){
// enable all pulls on PORT B except bit 6 and 7
/******************** state machine for determining if a button has been pushed *****************************/
                     // needs to be implemented for proper debounce
 while (Col == 0xF)  {          // we check to see if there is activity  in the colums - will include 44pin board switch
 Col = KeyPadColumnRead();      //should have the column number as the lower nibble ( if no button are pushed Col = 0)
 Row = KeyPadRowRead();         //should have the row number as the upper nibble ( if no button are pushed Row = 0)
 /**************************** NEED DEBOUNCE HERE!*******************************/
 RawDigit = Col | Row;                   // combine row and column input
 }
 HexBack = ConvertRawtoHex(RawDigit);    //get result of the hash array
 Row = 0xF;                              // reset row and column
 Col = 0xF;
 LATD = HexBack;                         // output to LEDS
   }
 }
/*************************************************************************************************
 *  Function  to initialiaze 4x4 key pad.
 *  The  columns are hooked up to Port B RB0 and RB1, RB2 and RB3.
 *  The rows are hooked up to Port B RB4, RB5, RA1, RA2
 *  These will be the drive pins. The default state is to drive the rows all low.
 * ************************************************************************************************************/
 unsigned char KeyPadColumnRead(void){
 unsigned char PortTemp;
TRISB = 0b11001111;      // Colums are inputs and rows are outputs.
                         // RB6,7 are not used - and are configured as inputs - ICSP pins
TRISA = 0b11111001;     // RA1 and RA2 are outputs
LATB = 0b11001111;      // PortB RB4 and RB5 low - Drive it out
TRISAbits.RA1 = 0;      //output for Row    3
TRISAbits.RA2 = 0;      //output for Row    4
LATAbits.LA1 = 0;       // use latch for Read modify Write problem -  drive out row 3
LATAbits.LA2 = 0;       // drive out row 4
NOP();
NOP();
PortTemp = PORTB;                 // Read in port B
PortTemp &= 0b00001111;           // mask unused bits to 0
return(PortTemp);                 // return value has the lowest nible as the colums of keypad
 }
/*************************************************************************************************
 *  The  columns are hooked up to Port B RB0 and RB1, RB2 and RB3.
 *  These will be the drive pins.
 *  The rows are hooked up to Port B RB4 and RB5, and Port A RA1 and RA2.
 *  A bit of bit manipulation to get all the bits in the right places
 * ***********************************************************************************************************/
 unsigned char KeyPadRowRead (void){
 unsigned char PortTemp;
 unsigned char PortTemp1;
TRISB = 0b11110000;      // Colums are outputs and rows are inputs. RB6,7 are not used - and are configured as inputs - ICSP pins
LATB = 0b11110000;      // Drive out PortB RB0, RB1, RB2, RB4 as 0s.the rest doesn't matter - they are inputs
TRISAbits.RA1 = 1;                   //input for Row    3
TRISAbits.RA2 = 1;                    //input for Row    4
PortTemp = PORTA;                     //get values from PORT A
PortTemp = PortTemp << 5;             //Shift everything by 5 - bits 1 and 2 become bit 6 and 7, 0s are roated in
PortTemp & = 0b11011111;              // Mask bit 0 of Port A - it's not used
PortTemp1 = PORTB & 0b00110000;;      // Read in port B mask for bits 4 and 5
PortTemp |= PortTemp1;                // so now we have the upper bits as the rows that were read in
return(PortTemp);                     // return value has the upper nibble as the rows of the keypad
 }
/*************************************************************************************************
 *  Function  to convert raw nibble info (got the order of the rows and columns reversed).
 *  A function of two variables is used as a  hash array - look up table for the two nibles
 *  The nibles are combined into RawDigs and than a pointer to the punction goes through
 *  all states until there is a match. It outputs a hex number,
 *  which is at the same pointer location. If a column 1 detect occurs without a corresponding
 *  row - it is the switch on the 44 pin board that is being activated.
 * ***********************************************************************************************************/
  unsigned char ConvertRawtoHex(unsigned char RawDigs){
  unsigned char i;
  unsigned char Raw;
  KeyPadtoHex *  pointhash;     //create a pointer to our hash array
  KeyPadtoHex keybyte[] = {     // define an array keybyte for the conversion
      {0b11101110, 0b0001},     // row 1, column 1 = 1
      {0b11101101, 0b0010},     // row 1, column 2 = 2
      {0b11101011, 0b0011},     // row 1, column 3 = 3
      {0b11100111, 0b1111},     // row 1, column 4 = 0xF
      {0b11011110, 0b0100},     // row 2, column 1 = 4
      {0b11011101, 0b0101},     // row 2, column 2 = 5
      {0b11011011, 0b0110},     // row 2, column 3 = 6
      {0b11010111, 0b1110},     // row 2, column 4 = 0xE
      {0b10111110, 0b0111},     // row 3, column 1 = 7
      {0b10111101, 0b1000},     // row 3, column 2 = 8
      {0b10111011, 0b1001},     // row 3, column 3=  9
      {0b10110111, 0b1101},     // row 3, column 4 = 0xD
      {0b01111110, 0b1010},     // row 4, column 1 = 0xA
      {0b01111101, 0b10000},    // row 4, column 2 = 0x10 - to differentiate from 0
      {0b01111011, 0b1011},     // row 4, column 3 = 0xB
      {0b01110111, 0b1100},     // row 4, column 4 = 0xC
      {0b11111110, 0x55}          // no row, column 4 = 55 - push button on 44 pin board
   };
   pointhash = &keybyte[0];
   for (i=0; i<18; i++){
    if (RawDigs == (pointhash+i)->RawDig) {
       Raw = (pointhash+i)->HexDigOut;
       break;
    }
  }
  return(Raw);

  }
  /*************************************************************************************************
 *  Function  to tak ethe number and flash it to the Leds, but do it only in 5 ms intervals.
  convert raw nibble info (got the order of the rows and columns reversed).
 *  A function of two variables is used as a  hash array - look up table for the two nibles
 *  The nibles are combined into RawDigs and than a pointer to the punction goes through
 *  all states until there is a match. It outputs a hex number,
 *  which is at the same pointer location. If a column 1 detect occurs without a corresponding
 *  row - it is the switch on the 44 pin board that is being activated.
 * ***********************************************************************************************************/
  void ToLeds(unsigned char HexOut){
  volatile unsigned char count;
  LATD = HexOut;                         // output to LEDS
  Delay1KTCYx(1);                       // Delay 1 x 1000 = 1000 cycles -> 4 ms
  if (count > 249) LATD = 0; count = 0;
 return;
  }

