 /* ----------------------------------------------------------------------
 * Demo program routine to read/interpret a detented rotary encoder
 * Coded by Ishan Karve (ishan at the rate gmail dot com)
 * 14 Feb 2012
 * Platform : TI MSP-EXP430G2 Launchpad running MSP430G2553
 * Encoder  :  Rotary Encoder Switch With Keyswitch
 *             http://www.sureelectronics.net/goods.php?id=221
 * Software Suite : Code Compose Studio, Version: 4.2.3.00004
 * ----------------------------------------------------------------------
 * 
 * Routine Caters for 
 * 		Clockwise Rotation.
 * 		Counter Clockwise Rotation
 * 		Single Button Click
 * 		Double Button Click
 * To Do 		
 *		Click and Turn (CW or CCW)
 */ 

#include <msp430g2553.h>
#include <stdbool.h>
//Defines for Launchpad LEDs
#define LED1	BIT6
#define LED0	BIT0
//define for quarature encoder
#define CH_B	BIT0	//P2.0  Encoder Pin 
#define CH_A	BIT1	//P2.1  Encoder Pin
#define BUTTON	BIT2	//P2.2  Encoder Pin
#define COMM	BIT5	//P1.5	Encoder Pin
//function declaration
void pattern_match(); 					//determine direction of rotation
void TX(char *tx_message);				//Serial UART TX
static char *i2a(unsigned i, char *a, unsigned r); 	//convert int to char
char *itoa(int i, char *a, int r);			//convert int to char
void ADC_init(void);

//variable declaration
char buffer[5];
int a=0;		//variable stores interrupt edge
int b=0;		//variable stores interrupt edge
int cval=3;		//store current value to determine rotation
int pval=3;		//stores previous value to determine rotation direction
int tr_state=0; 	//variable to store transition state  
int num=0;		//arbitary number. will increment or decrement iff tr_satate=4
int tr;			//holds trigget state for variable tr_state
int pnum=0;		
int inc_fact=1; 	//this variable holds the increment factor
int click=0;		//holds button click count
int sclick=false;	//flag holds single click, has to be reset in program loop
int dblclk=false;	//flag holds double click, has to be reset in program loop
void main(){
    //stop watchdog
    WDTCTL = WDTPW + WDTHOLD;
  
  	//setup internal DCO
  	BCSCTL1 = CALBC1_1MHZ;            // Set DCO to 1MHz
	DCOCTL = CALDCO_1MHZ;   
	
    //Setup output ports
    P1DIR |= (LED0+LED1+COMM);
    P1OUT &=~(LED0+LED1+COMM);
   
    //setup interrupts for quadrature encoder
    P2DIR&= ~(CH_A + CH_B + BUTTON); 			//set ports as inputs
   	P2IE |=  (CH_A + CH_B + BUTTON);  		//enable interrupts for Quad Encoder
    
    //active-high configuration
    P2REN |=(CH_A + CH_B + BUTTON);			//enable pullups on respective ports
    P2OUT |=(CH_A + CH_B + BUTTON);
    
    P2IFG&=~(CH_A + CH_B + BUTTON);			//clear interrupt flag
    P2IES&=~(CH_A + CH_B + BUTTON);			//Interrupt on Hi->Lo transition
    
    //Setup USCI for UART communication at 9800-N-1
	P1SEL = BIT1 + BIT2;            		// Set P1.1 to RXD and P1.2 to TXD
	P1SEL2 = BIT1 + BIT2; 
	UCA0CTL1 |= UCSSEL_2;            		// Have USCI use SMCLK AKA 1MHz main CLK
	UCA0BR0 = 104;                  		// Baud: 9600, N= CLK/Baud, N= 10^6 / 9600
	UCA0BR1 = 0;                  			// Set upper half of baud select to 0 
	UCA0MCTL = UCBRS_1;               		// Modulation UCBRSx = 1
	UCA0CTL1 &= ~UCSWRST;             		// Start USCI
	TX("Rotary Encoder Demo\r\n");
	
	/* setup timer to watch for double click
	 * the double clik period is 0.5 second
	 * mcu is running at 1 MHZ, hence we will divide (prescale) 
	 * the clock by 8 to get a frequency of 125 KHZ. Clock source 
	 * is SMCLK
	 * 
	 * interrupt_period = (ticks/timer_clock_freq)
	 * hence for a period of 0.5 second no of ticks = 62500
	 */
	 
	 TACTL= TASSEL_2 + ID_3 + TACLR;	//SMCLJK + divide by 8 + clear counter
	 TACCTL0=CCIE;				//enable timer
	 TACCR0=62500;				//set timer interrupt count
	 //note timer is not enabled. timer will be enabled in button interrupt routine

    _enable_interrupt();
    for (;;)
    {
    	if (num!=pnum){
    	itoa(num, buffer, 10);
		TX(buffer);
		TX("\r\n");
		pnum=num; 
    	}
	}
}

void pattern_match(){
 /* Transition sequence is as follows (Active High Config)
  * 		--Clockwise--  
  * CH_A	->  H L L H H
  * CH_B	->  H H L L H
  * 	---Counter-Clockwise--- 
  * CH_A 	->  H H L L H
  * CH_B	->  H L L H H 
  * 
  * If the above pattern is stored in a 2 bit array with CH_A as Bit 0 and CH_B as Bit 1
  * The value shall be as follows (integer)
  * CW		-> 3-2-0-1-3
  * CCW		-> 3-1-0-2-3
  */ 
 	int cw[]={3,2,0,1,3};
	int ccw[]={3,1,0,2,3};
	int i;
	for (i=1;i<5;i++){
		if (pval==cw[i-1] && cval==cw[i]) 
		{ 
			if (tr){tr_state++;} else (tr=1); 
			if (tr_state>=5)
			{
				num=num+inc_fact;
				tr_state=0;												
			}
			
		}
	}
		
	for (i=1;i<5;i++){
		if (pval==ccw[i-1] && cval==ccw[i])
		{
			if (!tr){tr_state++;} else (tr=0);
			if (tr_state>=5)
			{
				num=num-inc_fact; 				
				tr_state=0;
			}
			
		}
	}
}
static char *i2a(unsigned i, char *a, unsigned r)
{
	if (i/r > 0) a = i2a(i/r,a,r);
	*a = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[i%r];
	return a+1;
}

char *itoa(int i, char *a, int r)
{
	if ((r < 2) || (r > 36)) r = 10;
	if (i < 0)
	{
		*a = '-';
		*i2a(-(unsigned)i,a+1,r) = 0;
	}
	else *i2a(i,a,r) = 0;
	return a;
} 

void TX(char *tx_message)
{
	unsigned int i=0; //Define end of string loop int
	char *message; // message variable
	unsigned int message_num; // define ascii int version variable
	message = tx_message; // move tx_message into message
	while(1)
	{
		if(message[i]==0) // If end of input string is reached, break loop. 
		{break;}
		message_num = (int)message[i]; //Cast string char into a int variable
		UCA0TXBUF = message_num; // write INT to TX buffer
		i++; // increase string index
		__delay_cycles(10000); //transmission delay
		if(i>50) //prevent infinite transmit
		{
			P1OUT |= LED1; 
			break;   
		}
   	} // End TX Main While Loop
} // End TX Function

// Port 2 interrupt service routine
#pragma vector=PORT2_VECTOR
__interrupt void Port_2(void)
{
	pval=cval;		//store current_value
//disable all interrupts
	P2IE&=~(CH_A + CH_B + BUTTON);
//check interrupt flags to find which interrupt was triggred
	
	//Check for CH_A interrupt
	if ((P2IFG & CH_A)==CH_A)
	{
		if ((P2IN & CH_A)==CH_A) {a=1;}else {a=0;}	//read pin state
      	if ((P2IN & CH_B)==CH_B) {b=1;}else {b=0;}		//read pin state
      	cval=(a << 0 ) | (b <<1);				
		P2IES^=CH_A;					//toggle interrupt edge
			
	}
	
	//Check for CH_B interrupt
	if ((P2IFG & CH_B)==CH_B)
	{
		if ((P2IN & CH_A)==CH_A) {a=1;}else {a=0;} 	//read pin state
      	if ((P2IN & CH_B)==CH_B) {b=1;}else {b=0;}		//read pin state
      	cval=(a << 0 ) | (b <<1);
		P2IES^=CH_B;	//toggle interrupt edge
		
	}
	
	
	
	
	//Check for Buttton interrupt also caters for double click
	if ((P2IFG & BUTTON)==BUTTON)
	{
		click++;	
		if (click>=2)
		{
			click=0;
			dblclk=true;	//set flag true, has to be set false once action is taken on flag
			P1OUT ^= (LED0+LED1);	//toggle both leds
		}		
		TACTL |= MC_1;			//enable timer
		
	}
	pattern_match();
	//clear all interrupts
	P2IFG&=~(CH_A + CH_B + BUTTON);	
	//enable all interrupts
	P2IE|=(CH_A + CH_B + BUTTON);

 }
 

#pragma vector=TIMER0_A0_VECTOR
__interrupt void Timer0(void)
{
	if (click==1){sclick=true;P1OUT ^= LED0;}
	TACTL |= MC_0;				//disable timer
	click=0;
	
	
}



