
/********************************************************************
 * 
 * SN.H and SN.C provide some functions to communicate with
 * a unique serial number chips like the Dallas Semiconductor DS2401.
 *
 * The DS2401 is a unique serial number chip which returns a 64 bit 
 * unique number
 * 
 * The SN.H and SN.C are designed to interface to different serial 
 * number chips, not specifically the DS2401. However at this current 
 * time, only the DS2401 is supported 
 *
 *********************************************************************/

/* Include our own header file */
#include "bioscnfg.h"
#include "sn.h"

/* Some sn.c specific constants */
/* Different kind of serial number chips */
#define DALLAS_DS2401		1

/* Some constants */
#define C196_PROCESSOR			1
#define MSP430_PROCESSOR		2

/* Definition of processor specific */
/* constants. These constants define: */
/* - the serial number chip to use */
/* - the type of microcontroller used */
/* - which port to use */
/* All processor and implementation specific */ 
/* configurations can be changed with these */
/* constants */
#define SERIAL_NUMBER_CHIP_TYPE		DALLAS_DS2401
#define PROCESSOR_TYPE				MSP430_PROCESSOR
#define CONNECTED_PORT				PORT2

/* Include processor specific files */
#if PROCESSOR_TYPE == C196_PROCESSOR
	#include <kb_sfrs.h>
	#include "sm_c196.h"
#endif


#if PROCESSOR_TYPE == MSP430_PROCESSOR
	#include <msp430x14x.h>
	#include "sn_msp.h"
#endif



/*****************************************/
/* Private Support functions definitions */
/*****************************************/


/* Write the passed bit-value (nBit) to */
/* the device on the one-wire bus */
void SN_OneWireBusWriteBit_0(void)
{
	SN_OneWireBusPinLow();   // Make the bus 0 
	SN_WaitMicroSeconds(DelayBusWrite0);
	SN_OneWireBusPinHigh();   // Make the bus 1 again 
	/* Wait for the recover period */
	/* So we are sure we will not send the */
	/* next bit to fast */
	SN_WaitMicroSeconds(DelayWriteRecover);
}

/* Write the passed bit-value (nBit) to */
/* the device on the one-wire bus */
void SN_OneWireBusWriteBit_1(void)
{
	/* Make the bus 0 */
	SN_OneWireBusPinLow();   // Make the bus 0 
	/* Wait */
	SN_Wait_DelayBusWrite1();

	/* Make the bus 1 again */
	SN_OneWireBusPinHigh();   // Make the bus 1 
	/* We have to write a 1 */
	/* The pull-up resistor will create */
	/* the 1 signal, but we have to wait */
	/* So the DS2401 can sample the 1 */
	SN_WaitMicroSeconds(DelayBusWrite1Wait);
	/* Wait for the recover period */
	/* So we are sure we will not send the */
	/* next bit to fast */
	SN_WaitMicroSeconds(DelayWriteRecover);
}


unsigned char SN_OneWireBusReadBit(void)
{
/* Read a bit-value from the one-wire bus */
/* and return 0 or !=0  */
	unsigned char cVal;

	/* Make the bus 0 */
	SN_OneWireBusPinLow();   // Make the bus 0 
	/* Wait */
	SN_Wait_DelayBusRead();

	/* Releas the bus again (that's make it 1) */
	SN_OneWireBusPinHigh();   // Make the bus 1 
	/* Wait until we can sample the data */
	SN_Wait_DelayBusReadSample();
	
	cVal = SN_OneWireBusReadPin();    //  Get the current value of the bus 
	/* Wait for the recover period */
	/* So we are sure we will not read or send the */
	/* next bit to fast */
	/* Return the read value */
	SN_WaitMicroSeconds(DelayBusReadRecover);
	return (cVal);
}

unsigned char SN_OneWireBusReset(void)
{
/* Reset the one-wire bus. Check if a device is */
/* connected. Return 1 if a device is connected */
/* or 0 when it is not */

	unsigned char cPresent;
	unsigned int  nDelay;
	unsigned char cFound;

	cPresent = 0;

	/* Make the bus 0 */
	SN_OneWireBusPinLow();   // Make the bus 0 
	/* Wait */
	SN_WaitMicroSeconds(DelayBusReset);

//	500us *  8MHz  

	/* Make the bus passive again */
	SN_OneWireBusPinHigh();   // Make the bus 1 
	/* Now within DelayBusMaxPresence the bus should be going */
	/* to zero.	 If that happens, the DS2401 is there */
	nDelay = 0;
	cFound = 0;                         
	
	while ((nDelay < DelayBusMaxPresence) && (cFound == 0))
	{
		/* Check if the bus went to 0 */
		if (SN_OneWireBusReadPin())
		{
			/* Wait a microsecond */
			SN_WaitMicroSeconds(1);
			/* Increase the counter */
			++nDelay;
		}
		else 
		{	/* It went to 0 */
			cFound = 1;
		}
	}
	if (cFound)
	{
		/* After a maximum time of DelayBusMaxResetIdle from the start */
		/* of the presence pulse the bus should be going to 1 again */
		nDelay = 0;
		cFound = 0;
		while ((nDelay < DelayBusMaxResetIdle) && (cFound == 0))
		{
			/* Check if the bus went to 0 */
			if (SN_OneWireBusReadPin())
			{
				/* It went to 1 */
				cFound = 1;
			}
			else 
			{
				/* Wait a microsecond */
				SN_WaitMicroSeconds(1);
				/* Increase the counter */
				++nDelay;
			}
		}
	}
	if (cFound)
	{
		/* The device responded correctly twice */
		/* so it is there */
		cPresent = 1;
		/* We have to wait again to correcty finish */
		/* the reset procedure, to prevent we are not */
		/* sending the next command to fast */
		SN_WaitMicroSeconds(DelayBusMaxResetIdle);
		}

	/* Return if a device is present */
	return (cPresent);	/*cPresent;	*/
}

void SN_OneWireBusWriteByte(const unsigned char nByte)
{
/* Write the passed byte-value (nByte) to */
/* the device on the one-wire bus */
	unsigned char cCounter;

	for (cCounter = 0; cCounter < 8; ++cCounter)
		if (nByte & (1 << cCounter))
			SN_OneWireBusWriteBit_1();
		else
			SN_OneWireBusWriteBit_0();

}

unsigned char SN_OneWireBusReadByte(void)
{
/* Read a byte-value from the one-wire bus */
/* and return it */

	unsigned char cCounter;
	unsigned char cByte;

	cByte = 0;
	for (cCounter = 0; cCounter < 8; ++cCounter)
	{
		if (SN_OneWireBusReadBit())
		{
			cByte |= (1 << cCounter);
		}
	}		
	return cByte;
}

/********************************/
/* Public Function declarations */
/********************************/

/* To get the serial number */

#if INCLUDE_SN == Use_Module

void SN_GetSerialNumber(SerialNumber_t *psSerial)
{
	unsigned char cCounter;
	
	/* Clear the complete serial number structure */
	for (cCounter = 0; cCounter < SN_NUMBER_OF_CHAR; ++cCounter)
		psSerial->wData[cCounter] = 0x00;

#if SERIAL_NUMBER_CHIP_TYPE == DALLAS_DS2401
	/* Reset the 1 wire bus */
	if (SN_OneWireBusReset()){
		/* Send the command to get the serial number */
		/* We will send the 0x0F command, because this */
		/* will also work with an DS2400 */
		SN_OneWireBusWriteByte(0x0F);
		/* Get the serial number */
		for (cCounter = 0; cCounter < SN_NUMBER_OF_CHAR; ++cCounter)
		{
			/* Read the byte */
			psSerial->wData[cCounter] = SN_OneWireBusReadByte();
		}

		/* Check if the serial number passes some checks */
		/* CRC for example */
		/* ..... */
		}
#endif

	/* Ready */
	return;
}
#else 
void SN_GetSerialNumber(SerialNumber_t *psSerial)
{
	unsigned char cCounter;
	for (cCounter = 0; cCounter < SN_NUMBER_OF_CHAR; ++cCounter)
	{
			/* Read the byte */
		psSerial->wData[cCounter] = (unsigned char) cCounter * 19;
	}
}
#endif 

/* To perform bit operations */
char SN_GetBit(SerialNumber_t *psSerial, const unsigned int nBitNumber)
{
	if (/*nBitNumber >= 0 && */ nBitNumber <= 63)
		/* The to be questioned bit-number is valid */
		/* Calculate the word in which the bit is located */
		/* and AND it with the correct bit-flag */
		if (psSerial->wData[3 - (nBitNumber / 16)] & (1 << (nBitNumber % 16)))
			return 1;
		else
			return 0;
	else
		return 0;
}

void SN_SetBit(SerialNumber_t *psSerial, const unsigned int nBitNumber, const unsigned char cValue)
{
	if (/*nBitNumber >= 0 && */ nBitNumber <= 63){
		/* The to be questioned bit-number is valid */
		if (cValue){
			/* The bit has to be set */
			/* Calculate the word in which the bit is located */
			/* and OR it with the correct bit-flag */
			psSerial->wData[3 - (nBitNumber / 16)] |= (1 << (nBitNumber % 16));
			}
		else {
			/* The bit has to be cleared */
			/* Calculate the word in which the bit is located */
			/* and AND it with the correct inversed bit-flag */
			psSerial->wData[3 - (nBitNumber / 16)] &= (~(1 << (nBitNumber % 16)));
			}
		}
}

