#define __16f88
#include"pic/pic16f88.h"
/*  Yves Usson - october 2008

Mono keyboard scanner firmware v1.00 for 8x8 matrix (FATAR,BONTEMPI)

PORTA IN OUT					
RA0	MATRIXCOM 		IN	COMMON PIN OF THE CD4051 MATRIX			
RA1	LEGATO			IN	LEGATO SWITCH
RA2	PRIORITY		IN	PRIORITY SWITCH
RA3	STATUS			OUT STATUS LED
RA4	GATELED			OUT GATE LED
RA5	MCLR			IN	RESET
RA6	UNUSED1			OUT		
RA7	UNUSED2			OUT		

TRISA = 0b00100111

PORTB IN OUT
RB0	ADDR0			OUT		RB0 TO RB5 ADDRESS TO 4051 AND DAC
RB1	ADDR1			OUT
RB2	ADDR2			OUT
RB3	ADDR3			OUT
RB4	ADDR4			OUT
RB5 ADDR5			OUT		
RB6	DAC_CS			OUT		DAC LATCH CONTROL (LATCHES ON RISE)
RB7	GATEOUT			OUT		GATE OUTPUT

TRISB = 0b00000000

*/

typedef unsigned char ubyte;
typedef unsigned short ushort; 
typedef unsigned int word;

// Set the __CONFIG word:
// _CP_OFF no Flash program memory code protection
// _CCP1_RB0 CCP1 function on pin RB0
// _DEBUG_OFF no ISCP debugging
// _WRT_PROTECT_OFF no write protection
// _CPD_OFF no Data EE memory code protection
// _LVP_OFF no Low voltage programming
// _BODEN_OFF Brown-out Reset Enable bit disabled
// _MCLR_ON RA5 is MCLR
// _PWRTE_OFF Power-up timer OFF
// _WDT_OFF no watchdog
// _INTRC_IO Internal clock, RA6 and RA7 in/out


word at _CONFIG1  __CONFIG = _CP_OFF & _CCP1_RB0 & _DEBUG_OFF & _WRT_PROTECT_OFF & _CPD_OFF & _LVP_OFF & _BODEN_OFF & _MCLR_ON & _PWRTE_OFF & _WDT_OFF & _INTRC_IO;
//word at _CONFIG2  __CONFIG = _IESO_OFF & _FCMEN_OFF;

short legato_flag;
short highest_flag;
ubyte old_key;
ubyte gate_flag;

#define MASK_MATRIX		0b00111111
#define XIRTAM_KSAM		0b11000000
#define MAXKEYS			61

// Set various port bits
#define StatusLEDOn		RA3 = 1
#define GateLEDOn		RA4 = 1
#define DAC_CS_High		RB6 = 1
#define GateOn			RB7 = 1

// Unset various port bits
#define StatusLEDOff	RA3 = 0
#define GateLEDOff		RA4 = 0
#define DAC_CS_Low		RB6 = 0
#define GateOff			RB7 = 0

// Test various port bits
#define IsKeyOn 			(RA0 == 1)
#define IsLegatoOn 			(RA1 == 1)
#define IsHighestPriorityOn (RA2 == 1)

void Init_PIC(void)
{
	OSCCON = 0b01111100;	// osc at 8 MHz
	TRISA = 0b00100111;		// positionnenemt I/O du port A
	TRISB = 0b00000000;		// positionnenemt I/O du port B			
	ANSEL = 0;				//désactivation des convertisseurs A/N	
	PORTB = 0;
	RA1 = 0;
	RA2 = 0;	
}

void Delay100us(void) // 0.1 ms. at 8MHz
{
	unsigned char i,j;

	for(i=0;i<5;i++)
		for(j=0;j<3;j++);
}

void Delay500us(void) // 0.5 ms. at 8MHz
{
	unsigned char i,j;

	for(i=0;i<30;i++)
		for(j=0;j<3;j++);
}

void Delay100ms(void) // 0.1 s at 8MHz
{
	unsigned short i,j;

	for(i=0;i<500;i++)
		for(j=0;j<35;j++);
}

void SetMatrix(short v)
{
	ubyte by1 = PORTB & XIRTAM_KSAM;
	ubyte by2 = (ubyte)(v & MASK_MATRIX);
	PORTB = (by1 | by2);
}

void WriteDAC(void)
{
	DAC_CS_Low;   // when down latches are transparent
	//Delay100us();
	DAC_CS_High;  // when high latches are frozen
}


void Test()
{
	ubyte i;
	short j;
	
	GateOff;	
	j = 0;
	for (i = 1; i < 5; i++)
	{
		StatusLEDOn; 
		SetMatrix(j); WriteDAC();
		Delay100ms();
		SetMatrix(j+4); WriteDAC();
		Delay100ms();		
		StatusLEDOff; 
		SetMatrix(j+7); WriteDAC();
		Delay100ms();
		SetMatrix(j+4); WriteDAC();
		Delay100ms();
		j += 12;
	}
	SetMatrix(0); WriteDAC();
}

ubyte ScanDown()
{
	short i;
	
	i = MAXKEYS-1;   // set key index to highest value
	do
	{
		SetMatrix(i);				// check ith key
		if (IsKeyOn)				// test if key is depressed and do whatever is to be done
		{
			if (i != old_key)
			{
				WriteDAC();				// lock key into DAC
				if (!legato_flag && gate_flag)	// if not in legato mode and another key was previously on break GATE
				{
					GateOff;
					GateLEDOff;
					Delay500us();
				}
			}
			GateOn;
			GateLEDOn;
			gate_flag = 1;
			old_key = i;
			return 1; 				// leave the function as soon as a key was detected
		}
		i--;			// otherwise decrement key index
	} while (i > -1);	// end of keyboard reached
	return 0;
}

ubyte ScanUp()
{	
	short i;
	
	i = 0;   // set key index to lowest value
	do
	{
		SetMatrix(i);				// check ith key
		if (IsKeyOn)				// test if key is depressed and do whatever is to be done
		{
			if (i != old_key)
			{
				WriteDAC();				// lock key into DAC
				if (!legato_flag && gate_flag)	// if not in legato mode and an other key was previously on break GATE
				{
					GateOff;
					GateLEDOff;
					Delay500us();
				}
			}
			GateOn;
			GateLEDOn;
			gate_flag = 1;
			old_key = i;
			return 1;				// leave the function as soon as a key was detected
		}
		i++;			// otherwise increment key index
	} while (i < MAXKEYS);	// end of keyboard reached
	return 0;
}

void main(void) 
{
	ubyte report;

	Init_PIC();
	Test();
	gate_flag = 0;
	old_key = 0;
	// Infinite loop
	while(1)
	{
		// check the vaious switches and update the corresponding flags
		legato_flag = IsLegatoOn;
		highest_flag = IsHighestPriorityOn;
		// a full scan with no key depressed takes 61 * 25us + 100us = 1.6 ms
		if (highest_flag) report = ScanDown();
		else report = ScanUp();
		if (report == 0)
		{
			// no key depressed therefore set GATE to OFF
			GateOff;
			GateLEDOff;
			gate_flag = 0;
		} 
    }
}