#ifndef PIN_C
#define PIN_C

#include    "PIN.h"

// Only for PIC24FJ64GA002 in QFN-28 format.
int PIN_RP_TABLE[ 16*2 ] = {
	-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
	0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
};

// Only for PIC24FJ64GA002 in QFN-28 format.
int PIN_PULL_UP_TABLE[ 16*2 ] = {
	2,3,30,29,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
	4,5,6,7,1,27,24,23,22,21,16,15,14,13,12,11	
};

PIN *PINOpen( PIN *this, char io, char v ){
	if( this == NULL || this->PORT == NULL )
		return NULL;
		
	PINSetOutFunc( this, OUT_FN_PPS_NULL );
	PINWrite( this, v );
	PINConfigDrain( this, NORMAL_DRAIN );
	PINConfigDir( this, io );
	return this;
}

void PINClose( PIN *this ){
	PINConfigDir( this, INPUT );
	PINConfigDrain( this, NORMAL_DRAIN );
	PINWrite( this, LOW );
}

char PINRead( PIN *this ){
	if( this->TRIS & this->BITMASK ) 		// IsInput()?
		return ((*this->PORT & this->BITMASK) != 0 );
	else
		return ((this->LAT & this->BITMASK) != 0 );
	return 0;
}

void PINWrite( PIN *this, char x ){
	if( x == HIGH )
		this->LAT |= this->BITMASK;
	else
		this->LAT &= ~this->BITMASK;
	PIN_DELAY;
	return;
}

void PINConfigDrain( PIN *this, char x ){
	if( x == OPEN_DRAIN )
		this->ODC |= this->BITMASK;
	else
		this->ODC &= ~this->BITMASK;
	PIN_DELAY;
	return;
}


void PINConfigDir( PIN *this, char x ){
	if( x == INPUT )
		this->TRIS |= this->BITMASK;
	else
		this->TRIS &= ~this->BITMASK;
	PIN_DELAY;
	return;
}

void PINSetInFunc( PIN *this, int fn ){
	return;
}

void PINSetOutFunc( PIN *this, int fn ){
	int P = 0, B = 0;
	
	if( this == NULL || this->PORT == NULL )
		return;	
		
	if( this->PORT == &PORTA )			P = 0;
	else if( this->PORT == &PORTB )		P = 1;

	for( B = 0 ; B < 16 ; B++ ){
		if( this->BITMASK == (1<<B) )
			break;
	}
	
	int RP = PIN_RP_TABLE[ P * 16 + B];
	volatile unsigned int *pRPOR = &RPOR0;
	if( RP != -1) {
	//	PPSUnLock;	// ¿NOT SUPORTED BY PROTEUS?
		pRPOR[RP/2] &= ~(0x001F<<((RP%2)*8)); 
		pRPOR[RP/2] |= (fn<<((RP%2)*8));
	//	PPSLock;	// ¿NOT SUPORTED BY PROTEUS?
	}
	return;
}	

void PINSetPullUp( PIN *this, char pu ){
	int P = 0, B = 0;
	
	if( this == NULL || this->PORT == NULL )
		return;
		
	if( this->PORT == &PORTA )			P = 0;
	else if( this->PORT == &PORTB )		P = 1;

	for( B = 0 ; B < 16 ; B++ ){
		if( this->BITMASK == (1<<B) )
			break;
	}
	
	int PU = PIN_PULL_UP_TABLE[ P * 16 + B];
	volatile unsigned int *pCNPU = &CNPU1;
	if( PU != -1) {
/*		// NOT SUPORTED BY PROTEUS
		pCNPU[PU/16] &= ~(0x001F<<((PU%2)*8)); 
		pCNPU[PU/16] |= (pu<<((PU%2)*8));
*/
	}
	return;
}


#endif	// #ifndef PIN_C
