#ifndef __I2CSIG_C
#define __I2CSIG_C

#include "i2csig.h"





void i2csig_init()
{

	I2CSIG_SCL_HI;  //internal pullups also activ ???????
	I2CSIG_SDA_HI;	//internal pullups also activ ???????

	sbi( SCLSIGDIRPORT, SCLSIG);	// set SCLSIG as output
	sbi( SDASIGDIRPORT, SDASIG);	// set SDASIG as output

	I2CSIG_SCL_HI;
	I2CSIG_SDA_HI;
}

#define I2CSIG_START {  I2CSIG_SDA_LO; \
						I2CSIGQDEL; \
						I2CSIG_SCL_LO; \
					 }

#define I2CSIG_STOP  { 	I2CSIG_SDA_LO; \
						NOP; \
						I2CSIGQDEL; \
						I2CSIG_SCL_HI; \
    					I2CSIGQDEL; \
						I2CSIG_SDA_HI; \
						I2CSIGQDEL; \
					 }




BYTE _i2csig_putbyte(BYTE val)
{
    int i;
	BYTE ack,b;
	//first sending address of device  
  	//bit-data is set on middle of low-clock-period
  	b = val;
	for (i=7;i>=0;i--) {
		I2CSIGQDEL;
		if ( b & (1<<i) ){
        	I2CSIG_SDA_HI;
        } else {
            I2CSIG_SDA_LO;
        }
        I2CSIGQDEL;

		//complete high-clock-period, where receiver can
		//read data
		I2CSIG_SCL_HI;
		I2CSIGQDEL;
		I2CSIGQDEL;
		I2CSIG_SCL_LO;
    }
  
  	//the nineth clock for getting the acknowledge
	I2CSIGQDEL;
	I2CSIG_SDA_HI;            // set sda high ( enable pullups )
	cbi(SDASIGDIRPORT, SDASIG);	// change direction to input on SDASIG line
	I2CSIGQDEL;
	//a complete clock for receiver to set its stuff	
    I2CSIG_SCL_HI;
	I2CSIGQDEL;    
	I2CSIGQDEL;    
	//we read it at end of clock, so receiver have a lot of time
  	ack = inp(SDASIGREADPORT) & (1<<SDASIG);  // get the ACK bit
  	NOP;
    I2CSIG_SCL_LO;
    I2CSIGQDEL;
	sbi(SDASIGDIRPORT, SDASIG);	// change direction back to output
	NOP;

    return (ack);            // return ACK value
}




/*
    Send a byte sequence on the I2CSIG line
*/
BYTE i2csig_send(BYTE dev, BYTE sub, WORD length, BYTE *data)
{
	//start sequence
	//we avoid a high scl for min. QDEL time before
	//and a high SDA line
	I2CSIG_START;
    
    if( _i2csig_putbyte(dev & 0x0fe) != 0 ){
    	//we set a stop condition, also if an error
    	I2CSIG_STOP;
    	return( I2C_NO_ACKNOWLEDGE );
	}
	
    if(_i2csig_putbyte(sub) != 0){
    	I2CSIG_STOP;
    	return( I2C_NO_ACKNOWLEDGE );    	
    }

    // send the data
    while (length--){
        if( _i2csig_putbyte(*data++) != 0 ){
    		I2CSIG_STOP;
    		return( I2C_NO_ACKNOWLEDGE );        	
        }
    }

	I2CSIG_STOP;
	
	return( I2C_SUCCESSFUL );
}










/*
    Retrieve a byte sequence on the I2CSIG line
*/
BYTE i2csig_receive(BYTE dev, BYTE sub, WORD length, BYTE *data)
{
    int i;
    BYTE c,b = 0;
    WORD j  = 0;
    BYTE *p = data;

	//start sequence
	//we avoid a high scl for min. QDEL time before
	//and a high SDA line
	I2CSIG_START;

	//deviceid
    if( _i2csig_putbyte(dev & 0x0fe) != 0 ){
    	//we set a stop condition, also if an error
    	I2CSIG_STOP;
   		return( I2C_NO_ACKNOWLEDGE );
	}

	//sending slave address with cleared read-flag
    if( _i2csig_putbyte(sub) != 0 ){
    	I2CSIG_STOP;    	
   		return( I2C_NO_ACKNOWLEDGE );    	
    }

	//Here we have to start the reading sequence
	//At this time SCL is low since a quarter low-period
	//SDA is output
	//first we have to do a startcondition again
	I2CSIG_SDA_HI;
	I2CSIGQDEL; //fullfill low-period
	I2CSIG_SCL_HI;
	I2CSIGQDEL;
	//new start
	I2CSIG_START;

	//sending device-address with set read-flag
    if( _i2csig_putbyte(dev | 1) != 0 ){
    	I2CSIG_STOP;    	
   		return( I2C_NO_ACKNOWLEDGE );    	
    }

	//now we can read the data
	//At this time SCL is low since a quarter low-period
	//SDA is output
	//first we set it to input
	I2CSIG_SDA_HI;            // set sda high ( enable pullups )
	cbi(SDASIGDIRPORT, SDASIG);	// change direction to input on SDASIG line


    // receive data bytes
    while (j < length){

		//reading bits per byte
		b = 0;
	    for (i=7;i>=0;i--) {
			I2CSIGQDEL;
			I2CSIG_SCL_HI;
			I2CSIGQDEL;
			I2CSIGQDEL;
			//we read bit at end of high-clock-period			
			c = inp(SDASIGREADPORT) & (1<<SDASIG);  

        	b <<= 1;
        	if (c){
            	b |= 1;
            }
			I2CSIG_SCL_LO;
			I2CSIGQDEL;
	    }
		//first storing received byte
        *p = b;
        p++;
        j++;
		//at this time SCL is low since a quarter period
		//now handling the ack-bit
		//for the last byte we have to set a nak ( high )
		//for all other an ack ( low )

		sbi(SDASIGDIRPORT, SDASIG);	// change direction to output on SDASIG line		
  		NOP;
  		if( j < length ){
 
  			I2CSIG_SDA_LO;//ack
  			I2CSIGQDEL;
			I2CSIG_SCL_HI;
  			I2CSIGQDEL;
  			I2CSIGQDEL;
			I2CSIG_SCL_LO;
			I2CSIGQDEL;
			cbi(SDASIGDIRPORT, SDASIG);	// change direction to input on SDASIG line
			NOP;
  		}
  		else {
  			I2CSIG_SDA_HI;//nak
  			I2CSIGQDEL;
			I2CSIG_SCL_HI;
  			I2CSIGQDEL;
  			I2CSIGQDEL;
			I2CSIG_SCL_LO;
			I2CSIGQDEL;
  		}

    }

	//here we should have SDA set to output,
	//and SCL low since a quarter-clock-period
	//and the nak for the last received byte is
	//send before
	I2CSIG_STOP;
	
	return( I2C_SUCCESSFUL );
}






#endif