
/****************************************************/
/*  Program written by Craig Newman	                */
/*                                                  */
/*	This program will only run in					*/
/*	stand-alone mode, ie will not run in		    */
/*	KD30 debug mode	since KD30 & monitor program	*/
/*	also uses UART1.				                */
/****************************************************/	

#include <stdio.h>
#include "sfr62.h"

void main(void);
void initUART1(void);
void initPort(void);
void initProgramTimers(void);
void getContactData(void);		// interupt processing function for timing program
void debounceDelay(void);		// interupt processing function for debouncing samples
int compareLogs(void);			// check that both connection samples are equivalent
void updateConnections(void);	// buffer the current connections in 3 bytes
void transmitConnections(void);	// receive interrupt routine -> Tx data 
void eraseConnectLog(void);		// clear connections ready for next reading
int isItConnected(int,int);		// Return 1 if current pin is connected already, else 0
void scanPorts(int,int);		// Find and log connections to current pin
void delay(void);

int connectLog[11][12][2];      // [pin tested] [pin connected] [logNumber]
int debounceTimerFlag;			// enable (1)/disable (0) program execution
int TxByteCount=0;				// number of bytes to be Tx
unsigned char currentTxData[18];// holds the current connection data for Tx
int doNOTinterrupt=0;			// used when updating Tx string

#pragma INTERRUPT getContactData
#pragma INTERRUPT debounceDelay
#pragma INTERRUPT transmitConnections

void main(void)
{
	initProgramTimers();
	initPort();			// Turn off pull-up resistors for ports 0 and 2
	initUART1();		// Setup serial communications

	ta0s = 1;		// start program timer : timerA0

	while (1);		// endless loop
}


void getContactData(void)
{
	int currentPin;		// current pin being tested
    int logNumber;		// Identifies the connectLog being used

	asm("fset I");		// enable interrupts

	for (logNumber=0;logNumber < 2; logNumber++)		// Determines which connectLog is being used
	{
	    for (currentPin = 0; currentPin < 11; currentPin++)	// For all but the last pin
	    {
		    if (isItConnected(currentPin, logNumber) == 0)		// If current pin not logged as already connected
		    {
			    scanPorts(currentPin, logNumber);			// Find and log connections to current pin
		    }
	    }

		if (logNumber == 0)				// If this is the first test
		{
			debounceTimerFlag = 0;
			ta1s = 1;					// Start debounce timer : timerA1
			while (debounceTimerFlag == 0);   // wait until timer finishes
		}
	}	// end logNumber loop
 
	if (compareLogs() == 1)		// If samples are the same
	{
		updateConnections();			// update the data
	}
	eraseConnectLog();				// erase data so connectLog is ready for next sampling period
}


void initPort(void)
{
	pu00 = 0;		// no pull-up for P0_0 to P0_3
	pu01 = 0;		// no pull-up for P0_4 to P0_7
	pu04 = 0;		// no pull-up for P2_0 to P2_3
	pu05 = 0;		// no pull-up for P2_4 to P2_7
}


void debounceDelay(void)
{
	asm("fset I");		// enable interrupts
	ta1s = 0;			// stop timerA1
	debounceTimerFlag = 1;		// Let program continue execution
}


int isItConnected(int currentPin, int logNumber)
{
	int isConnectedFlag = 0;
	int pinNumber;
	for (pinNumber = 0; pinNumber < currentPin; pinNumber++)   // cycle through all pins tested
	{
		if (connectLog[pinNumber][currentPin][logNumber] == 1)		// if pin is already connected
		{
			isConnectedFlag = 1;			//  set isConnected
		}
	}
	return isConnectedFlag;
}	


void scanPorts (int currentPin, int logNumber)		// writes current pin high and logs connected pins
{
	unsigned char port0, port2;
	switch (currentPin)
	{
	case 0:	pd0 = 0x01;		// Set port 0 direction, 1 output, 0 input
			pd2 = 0x00;		// Set port 2 direction, 1 output, 0 input
			p0 = 0x01;		// write L Pinky HIGH
			delay();		// inhibit induced voltage due to switching
			port0 = p0 & 0x3E;	// masking to read p0_1 to p0_5
			port2 = p2 & 0x3F;	// masking to read p2_0 to p2_5
			break;
	case 1: pd0 = 0x02;		// Set port 0 direction, 1 output, 0 input
			pd2 = 0x00;		// Set port 2 direction, 1 output, 0 input
			p0 = 0x02;		// write L Ring HIGH
			delay();		// inhibit induced voltage due to switching
			port0 = p0 & 0x3C;	// masking to read p0_2 to p0_5
			port2 = p2 & 0x3F;	// masking to read p2_0 to p2_5 
			break;
	case 2: pd0 = 0x04;		// Set port 0 direction, 1 output, 0 input
			pd2 = 0x00;		// Set port 2 direction, 1 output, 0 input
			p0 = 0x04;		// write L Middle HIGH
			delay();		// inhibit induced voltage due to switching
			port0 = p0 & 0x38;	// masking to read p0_3 to p0_5s
			port2 = p2 & 0x3F;	// masking to read p2_0 to p2_5 
			break;
	case 3: pd0 = 0x08;		// Set port 0 direction, 1 output, 0 input
			pd2 = 0x00;		// Set port 2 direction, 1 output, 0 input
			p0 = 0x08;		// write L Index HIGH
			delay();		// inhibit induced voltage due to switching
			port0 = p0 & 0x30; // masking to read p0_4 and p0_5
			port2 = p2 & 0x3F;	// masking to read p2_0 to p2_5 
			break;
	case 4: pd0 = 0x10;		// Set port 0 direction, 1 output, 0 input
			pd2 = 0x00;		// Set port 2 direction, 1 output, 0 input
			p0 = 0x10;		// write L Thumb HIGH
			delay();		// inhibit induced voltage due to switching
			port0 = p0 & 0x20;	// masking to read p0_5
			port2 = p2 & 0x3F;	// masking to read p2_0 to p2_5 
			break;
	case 5: pd0 = 0x20;		// Set port 0 direction, 1 output, 0 input
			pd2 = 0x00;		// Set port 2 direction, 1 output, 0 input
			p0 = 0x20;		// write L Palm HIGH
			delay();		// inhibit induced voltage due to switching
			port0 = 0x00;	// no data required
			port2 = p2 & 0x3F;	// masking to read p2_0 to p2_5 
			break;
	case 6: pd0 = 0x00;		// Set port 0 direction, 1 output, 0 input
			pd2 = 0x01;		// Set port 2 direction, 1 output, 0 input
			p2 = 0x01;		// write R Palm HIGH
			delay();		// inhibit induced voltage due to switching
			port0 = 0x00;	// no data required
			port2 = p2 & 0x3E;	// masking to read p2_1 to p2_5
			break;
	case 7: pd0 = 0x00;		// Set port 0 direction, 1 output, 0 input
			pd2 = 0x02;		// Set port 2 direction, 1 output, 0 input
			p2 = 0x02;		// write R Thunb HIGH
			delay();		// inhibit induced voltage due to switching
			port0 = 0x00;	// no data required
			port2 = p2 & 0x3C;	// masking to read p2_2 to p2_5
			break;
	case 8: pd0 = 0x00;		// Set port 0 direction, 1 output, 0 input
			pd2 = 0x04;		// Set port 2 direction, 1 output, 0 input
			p2 = 0x04;		// write R Index HIGH
			delay();		// inhibit induced voltage due to switching
			port0 = 0x00;	// no data required
			port2 = p2 & 0x38;	// masking to read p2_3 to p2_5
			break;
	case 9: pd0 = 0x00;		// Set port 0 direction, 1 output, 0 input
			pd2 = 0x08;		// Set port 2 direction, 1 output, 0 input
			p2 = 0x08;		// write R Middle HIGH
			delay();		// inhibit induced voltage due to switching
			port0 = 0x00;	// no data required
			port2 = p2 & 0x30;	// masking to read p2_4 and p2_5
			break;
	case 10:pd0 = 0x00;		// Set port 0 direction, 1 output, 0 input
			pd2 = 0x10;		// Set port 2 direction, 1 output, 0 input
			p2 = 0x10;		// write R Ring HIGH
			delay();		// inhibit induced voltage due to switching
			port0 = 0x00;	// no data required
			port2 = p2 & 0x20;	// masking to read p2_5
			break;
	// case 11 -> pin 12, if connected would already be logged
	}

	pd0 = 0;	// set port 0 to input for protection
	pd2 = 0;	// set port 2 to input for protection

	// pin p0_0 is first tested (L Pinky) and is not connected to it's self

	if ((port0 & 0x02) == 0x02)		// if pin p0_1 was read HIGH, L Ring
	{
		connectLog[currentPin][1][logNumber] = 1;	// record pin 1 connected
	}
	if ((port0 & 0x04) == 0x04)		// if pin p0_2 was read HIGH, L Middle
	{
		connectLog[currentPin][2][logNumber] = 1;	// record pin 2 connected
	}
	if ((port0 & 0x08) == 0x08)		// if pin p0_3 was read HIGH, L Index
	{
		connectLog[currentPin][3][logNumber] = 1;	// record pin 3 connected
	}
	if ((port0 & 0x10) == 0x10)		// if pin p0_4 was read HIGH, L Thumb
	{
		connectLog[currentPin][4][logNumber] = 1;	// record pin 4 connected
	}
	if ((port0 & 0x20) == 0x20)		// if pin p0_5 was read HIGH, L Palm
	{
		connectLog[currentPin][5][logNumber] = 1;	// record pin 5 connected
	}
	if ((port2 & 0x01) == 0x01)		// if pin p2_0 was read HIGH, R Palm
	{
		connectLog[currentPin][6][logNumber] = 1;	// record pin 6 connected
	}
	if ((port2 & 0x02) == 0x02)		// if pin p2_1 was read HIGH, R Thumb
	{
		connectLog[currentPin][7][logNumber] = 1;	// record pin 7 connected
	}
	if ((port2 & 0x04) == 0x04)		// if pin p2_2 was read HIGH, R Index
	{
		connectLog[currentPin][8][logNumber] = 1;	// record pin 8 connected
	}
	if ((port2 & 0x08) == 0x08)		// if pin p2_3 was read HIGH, R Middle
	{
		connectLog[currentPin][9][logNumber] = 1;	// record pin 9 connected
	}
	if ((port2 & 0x10) == 0x10)		// if pin p2_4 was read HIGH, R Ring
	{
		connectLog[currentPin][10][logNumber] = 1;	// record pin 10 connected
	}
	if ((port2 & 0x20) == 0x20)		// if pin p2_5 was read HIGH, R Pinky
	{
		connectLog[currentPin][11][logNumber] = 1;	// record pin 11 connected
	}
}


int compareLogs(void)
{
	int testedPin, connectedTo, samplesAreSameFlag = 1;

	for (testedPin = 0; testedPin < 11; testedPin++)	// for all pins 
	{
		for (connectedTo = 0; connectedTo < 12; connectedTo++)	// for all connections
		{
			if (connectLog[testedPin][connectedTo][0] != connectLog[testedPin][connectedTo][1])	// if logs are NOT the same
			{
				samplesAreSameFlag = 0;	// clear flag to note difference in samples
			}
		}
	}	// end of equivalency check
	return samplesAreSameFlag;	// returns 1 if samples are the same, else 0
}


void delay(void)
{
	int count;
	for (count = 0; count < 1500; count++);
}


void updateConnections(void)
{
	unsigned char tempChar[18];
	int testedPin, connectedTo, isConnectedFlag, tempInt, charCount, count, checkSum=0;

	tempChar[0] = 0x00;		// upper byte of STX
	tempChar[1] = 0x40;		// lower byte of STX
	charCount = 2;			// charCount ready for next two bytes

	for (testedPin = 0; testedPin < 11; testedPin++)
	{
		tempInt = 0x0000;
		isConnectedFlag = 0;

		switch (testedPin)
		{
		case 0:
			tempInt |= 0x2000;	// set bit 14 high -> L pinky
			break;
		case 1:
			tempInt |= 0x1000;	// set bit 13 high -> L ring
			break;
		case 2:
			tempInt |= 0x0800;	// set bit 12 high -> L middle
			break;
		case 3:
			tempInt |= 0x0400;	// set bit 11 high -> L index
			break;
		case 4:
			tempInt |= 0x0200;	// set bit 10 high -> L thumb
			break;
		case 5:
			tempInt |= 0x0100;	// set bit 9 high -> L palm
			break;
		case 6:
			tempInt |= 0x0020;	// set bit 6 high -> R palm
			break;
		case 7:
			tempInt |= 0x0010;	// set bit 5 high -> R thumb
			break;
		case 8: 
			tempInt |= 0x0008;	// set bit 4 high -> R index
			break;
		case 9:
			tempInt |= 0x0004;	// set bit 3 high -> R middle
			break;
		case 10:
			tempInt |= 0x0002;	// set bit 2 high -> R ring
			break;
		// case 11: If R pinky connected, is already accounted for
		}	// end testedPin switch
		for (connectedTo = testedPin+1; connectedTo < 12; connectedTo++)
		{
			if (connectLog[testedPin][connectedTo][0]==1)
			{
				switch (connectedTo)
				{
				// case 0: L pinky, already set by tested pin
				case 1:
					tempInt |= 0x1000;	// set bit 14 high -> L ring
					isConnectedFlag = 1;
					break;
				case 2:
					tempInt |= 0x0800;	// set bit 13 high -> L middle
					isConnectedFlag = 1;
					break;
				case 3:
					tempInt |= 0x0400;	// set bit 12 high -> L index
					isConnectedFlag = 1;
					break;
				case 4:
					tempInt |= 0x0200;	// set bit 11 high -> L thumb
					isConnectedFlag = 1;
					break;
				case 5:
					tempInt |= 0x0100;	// set bit 10 high -> L palm
					isConnectedFlag = 1;
					break;
				case 6:
					tempInt |= 0x0020;	// set bit 9 high -> R palm
					isConnectedFlag = 1;
					break;
				case 7:
					tempInt |= 0x0010;	// set bit 8 high -> R thumb
					isConnectedFlag = 1;
					break;
				case 8:
					tempInt |= 0x0008;	// set bit 7 high -> R index
					isConnectedFlag = 1;
					break;
				case 9:
					tempInt |= 0x0004;	// set bit 6 high -> R middle
					isConnectedFlag = 1;
					break;
				case 10:
					tempInt |= 0x0002;	// set bit 5 high -> R ring
					isConnectedFlag = 1;
					break;
				case 11:
					tempInt |= 0x0001;	// set bit 4 high -> R pinky
					isConnectedFlag = 1;
					break;
				}	// end connectedTo switch
			}	// end if statement
		}	// end connectedTo FOR loop
		if (isConnectedFlag==1)	// if these is one or more connections
		{
			tempChar[charCount] = (tempInt & 0xFF00) >> 8;	// upper byte of tempInt
			charCount++;
			tempChar[charCount] = (tempInt & 0x00FF);	// lower byte of tempInt
			charCount++;
			checkSum = checkSum + tempInt;		// increment checkSum with tempInt
			// note if there are no connections, checkSum = 0x0000
		}
	}	// end testedPin FOR loop
	tempChar[charCount] = 0x40;		// upper byte of ETX
	charCount++;
	tempChar[charCount] = 0x00;		// lower byte of ETX
	charCount++;
	tempChar[charCount] = (checkSum & 0xFF00) >> 8; // upper byte of checkSum
	charCount++;
	tempChar[charCount] = (checkSum & 0x00FF);	// lower byte of checkSum
	charCount++;

	doNOTinterrupt=1;  // disable Tx interrupt while updating Tx data
	for (count = 0; count < charCount; count++)
	{
		currentTxData[count] = tempChar[count];	// update currentTxData
	}
	TxByteCount = charCount;	// update number of bytes to Tx

	if(doNOTinterrupt)
		doNOTinterrupt=0;	// not interrupt occured, enable interrupt 
	else
		s1ric = 0x0B;		// interrupt occured -> request interrupt
}


void transmitConnections(void)
{
	char Rx;
	int count, byte;

	asm("fset I");	// enable interrupts
	s1ric = 0x03;	// clear interrupt request

	if(doNOTinterrupt)
		doNOTinterrupt=0;
	else
	{
		while (u1c1 & 0x08 == 0x08)
		{
			Rx = u1rbl;	// read Rx data
		}
		u1c1 = 0x01;			// enable Tx
		for (count = 0; count < 1500; count++);	// wait for Tx enable to propagate
		for (byte=0; byte < TxByteCount; byte++)
		{
			while (!(u1c1 & 0x02));	// Wait while data is present in transmit buffer
			for (count = 0; count < 7500; count++); // wait for PC recieve buffer to empty
    		u1tbl = currentTxData[byte];	// write data to UART1 transmit buffer
		}
		u1c1 = 0x04;		// enable Rx
	}	// end else
}


void eraseConnectLog(void)
{
	int testedPin, connectedTo;

	for (testedPin = 0; testedPin < 11; testedPin++)	// for all pins 
	{
		for (connectedTo = 0; connectedTo < 12; connectedTo++)	// for all connections
		{
			connectLog[testedPin][connectedTo][0] = 0;	// erase log
			connectLog[testedPin][connectedTo][1] = 0;	// erase log		
		}
	}	// end of erasing
}

void initProgramTimers(void)
{
    	ta0mr = 0x80;       // XX0X XX00 
                            // |||| |||+- must always be 0 in timer mode
                            // |||| ||+-- must always be 0 in timer mode
                            // |||| |+--- 0: pulse is not output at pin TA0out
                            // |||| |     1: pulse is output at pin TA0out
                            // |||| |        TA0out is automatically  output
                            // |||| +---- 0: gate function: timer counts only 
                            // ||||          when TA0in is held "L"
                            // ||||       1: gate function: timer counts only
                            // ||||          when TA0in is held "H"
                            // |||+------ 0: gate function not available
                            // |||        1: gate function available
                            // ||+------- must always be 0 in timer mode
                            // |+-------- count source select bits:
                            // +--------- count source select bits:
                            //            00:  f1
                            //            01:  f8
                            //            10:  f32
                            //            11:  fc32
		ta1mr = 0x80;

    	ta0 = 0x208D;		// Set program execution to 60Hz
		ta1 = 0x0C35;		// Set debounce timer to 6.25ms

		ta0ic = 0x01;           // ---- XXXX
                            //      ||||
                            //      |||+-- Interupt priority level select bit
                            //      ||+--- Interupt priority level select bit
                            //      |+---- Interupt priority level select bit
                            //      |      000: Level 0 (interrupt disabled)
                            //      |      001: Level 1
                            //      |      010: Level 2
                            //      |      011: Level 3
                            //      |      100: Level 4
                            //      |      101: Level 5
                            //      |      110: Level 6
                            //      |      111: Level 7
                            //      +----- Interupt request bit 
                            //             0: Interrupt not requested
                            //             1: Interrupt requested
		ta1ic = 0x02;	// higher level than timerA0 because it occurs within timerA0 interupt function
}

void initUART1(void)
{
    // Setting UART1 transmit/receive mode register (UART mode)
    u1mr = 0x05;            // XXXX XXXX 
                            // |||| |||+- uart mode
                            // |||| ||+-- uart mode
                            // |||| |+--- uart mode
                            // |||| |     100: 7 bit data
                            // |||| |     101: 8 bit data 
                            // |||| |     110: 9 bit data
                            // |||| +---- Internal/external clock select bit 
                            // ||||       0: Internal clock 
                            // ||||       1: External clock
                            // |||+------ Stop bit length select bit
                            // |||        0: One stop bit 
                            // |||        1: Two stop bit
                            // ||+------- Odd/even parity select bit
                            // ||         Valid when bit 6 = 1
                            // ||         0: Odd parity 
                            // ||         1: Even parity
                            // |+-------- Parity enable bit
                            // |          0: Parity disabled
                            // |          1: Parity enabled
                            // +--------- Sleep select bit
                            //            0: Sleep mode deselected
                            //            1: Sleep mode selected

    // Setting UART1 transmit/receive control register 0 (UART mode)
    u1c0 = 0x10;            // 00XX XXXX 
                            // |||| |||+- BRG count source select bit
                            // |||| ||+-- BRG count source select bit
                            // |||| ||    00: f1 is selected    
                            // |||| ||    01: f8 is selected    
                            // |||| ||    10: f32 is selected    
                            // |||| ||    11: inhibited    
                            // |||| |+--- /CTS//RTS function select bit
                            // |||| |     (Valid when bit 4 ='0')
                            // |||| |     0: /CTS function is selected
                            // |||| |     1: /RTS function is selected
                            // |||| +---- Transmit register empty flag 
                            // ||||       0: Data present in transmit register 
                            // ||||          (during transmission)
                            // ||||       1: No Data present in transmit register
                            // ||||          (transmission completed)
                            // |||+------ /CTS//RTS disable bit
                            // |||        0: /CTS//RTS function enabled
                            // |||        1: /CTS//RTS function disabled
                            // ||+------- Data output select bit
                            // ||         0: TxD0 pin is CMOS output
                            // ||         1: TxD0 pin is N-channel open-drain 
                            // ||            output
                            // |+-------- Must be fixed to '0'
                            // +--------- Must be fixed to '0'

    // Setting UART1 transmit/receive control register 1 (UART mode)
    u1c1 = 0x04;            // ---- X1X1 
                            //      |||+- Transmit enable bit
                            //      |||   0: Transmission disabled
                            //      |||   1: Transmission enabled 
			    //	    ||+-- Transmit buffer empty flag
			    //	    ||	0: Data present in transmit buffer register
			    //	    ||	1: No data present in transmit buffer register
                            //      |+--- Receive enable bit
                            //      |     0: Reception disabled
                            //      |     1: Reception enabled
                            //      +---- Receive complete flag
                            //            0: No data present in receive buffer
                            //            1: Data present in receive buffer

    // Setting UART1 transmit/receive control register 2 (UART mode)
    ucon |= 0x00;           // -X0- --XX 
							//	||    |+- UART0 transmit interrupt cause select bit
                            //  ||    +-  UART1 transmit interrupt cause select bit
                            //  ||        0: Transmit buffer empty (TI=1)
                            //  ||        1: Transmission completed (TXEPT=1)
                            //  |+------- Must be fixed to '0'
                            //  +-------- Separate /CTS//RTS bit
                            //            0: /CTS//RTS shared pin
                            //            1: /CTS//RTS separate pin
	
	// Setting UART1 receive interrupt control regiser. Note highest priority.
	s1ric = 0x03;           // ---- XXXX
                            //      ||||
                            //      |||+-- Interupt priority level select bit
                            //      ||+--- Interupt priority level select bit
                            //      |+---- Interupt priority level select bit
                            //      |      000: Level 0 (interrupt disabled)
                            //      |      001: Level 1
                            //      |      010: Level 2
                            //      |      011: Level 3
                            //      |      100: Level 4
                            //      |      101: Level 5
                            //      |      110: Level 6
                            //      |      111: Level 7
                            //      +----- Interupt request bit 
                            //             0: Interrupt not requested
                            //             1: Interrupt requested

    // Setting UART1 bit rate generator for 9600 baud (UART mode)
    u1brg = 0x67;           // REMARKS: U1BRG=(Xin/(16*clock_select*Baud))-1
                            // For example:                
                            // Xin = 16MHz                 
                            // clock_select = 1 (source=f1)
                            // Baud = 9600 Baud rate
			    // =>  u1brg = 103d = 0x67 (actual baud = 9615)
}
