
#include "config.h"
#include "delay.h"
#include "serial.c"
#include "serio.c"

#define S0 0
#define S1 1
#define S2 2
#define S3 3

volatile unsigned char state,last_state;
volatile unsigned char count,last_count;
volatile unsigned char int0_cnt,int0_last;
volatile unsigned char int1_cnt,int1_last;
volatile unsigned char update_flag;

#define DEBOUNCE  5

void update_state(void){
  state = PORTB & 0x3;
  switch(state) {
  case S0:
    if (last_state == S1) count++;
    else if (last_state == S2) count--;
    break;
  case S1:
    if (last_state == S3) count++;
    else if (last_state == S0) count--;
    break;
  case S2:
    if (last_state == S0) count++;
    else if (last_state == S3) count--;
    break;
  case S3:
    if (last_state == S2) count++;
    else if (last_state == S1) count--;
    break;
  }
  if (last_count != count) {
    // valid pulse
    last_state = state;
    last_count = count;
  } else {
    // invalid transistion, reset last state
    last_state = state;
  }
}

// debounces rotary encoder inputs by sampling
// their value at regular intervals
#if defined(HI_TECH_C)
void interrupt pic_isr(void)
#endif
#if defined(__18CXX)
#pragma interrupt pic_isr
void pic_isr(void)
#endif
{
  if (TMR2IF) {
    // debouncing rotary inputs
    TMR2IF = 0;
    if (RB0 != int0_last) {
      int0_cnt++;
      if (int0_cnt == DEBOUNCE) {
	update_flag = 1; int0_cnt = 0;int0_last = RB0;
      }
    }
    // reset cnt, if pulse width not long enough
    else if (int0_cnt)  int0_cnt = 0;
    if (RB1 != int1_last) {
      int1_cnt++;
      if (int1_cnt == DEBOUNCE) {
	update_flag = 1; int1_cnt = 0; int1_last = RB1;
      }
    }
    // reset cnt, if pulse width not long enough
    else if (int1_cnt)   int1_cnt = 0;
    if (update_flag) {
      // can read the rotary inputs
      update_state();
      update_flag = 0;
    }
  }
}

void main(void){
  unsigned char count_old;
  // set RB0, RB1 for input
  TRISB0 = 1;TRISB1 = 1;
  RBPU = 0; // enable weak pullups
  int0_last = RB0;
  int1_last = RB1;
  last_state = PORTB & 0x03; // init last state
  serial_init(95,1); // 19200 in HSPLL mode, crystal = 7.3728 MHz

  // configure timer 2
  // post scale of 11
  TOUTPS3 = 1; TOUTPS2 = 0; TOUTPS1 = 1; TOUTPS0 = 0;
  // pre scale of 16 */
  T2CKPS1 = 1;
  TMR2ON = 1 ;
  PR2 = 250;  // interrupt interrupt interval of 6 mS

  // enable TMR2 interrupt
  IPEN = 0;  TMR2IF = 0; TMR2IE = 1; 
  PEIE = 1;  GIE = 1;
  printf("With Timer2 Debounce");  pcrlf();
  printf("Rotary Switch Test Started");
  pcrlf();
  count =0;count_old=0;
  while(1) {
    //tip: don't put volatile variables in printfs, may change 
    // by the time the printf gets around to printing it!
    if (count != count_old){
      count_old = count;
      printf("Count: %x",count_old);
      pcrlf();
    }
  }
}

//for MCC18, place the interrupt vector goto
#if defined(__18CXX)
#if defined(HIGH_INTERRUPT)
#pragma code HighVector=HIGH_INTERRUPT
#else
#pragma code HighVector=0x0008  
#endif
void HighVector (void)
{
    _asm goto pic_isr _endasm
}
#pragma code
#endif
