/*********************************************************************
 *                    Flowcode One Wire Component Code
 *
 * File: OO_Code.c
 *
 * (c) 2007 Matrix Multimedia Ltd.
 * http://www.matrixmultimedia.com
 *
 * Software License Agreement
 *
 * The software supplied herewith by Matrix Multimedia Ltd (the
 * “Company”) for its Flowcode graphical programming language is
 * intended and supplied to you, the Company’s customer, for use
 * solely and exclusively on the Company's products. The software
 * is owned by the Company, and is protected under applicable
 * copyright laws. All rights are reserved. Any use in violation
 * of the foregoing restrictions may subject the user to criminal
 * sanctions under applicable laws, as well as to civil liability
 * for the breach of the terms and conditions of this licence.
 *
 * THIS SOFTWARE IS PROVIDED IN AN “AS IS” CONDITION. NO WARRANTIES,
 * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED
 * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT,
 * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR
 * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
 *
 * Changelog:
 *
 *  date  | by | description
 * -------+----+-----------------------------------------------------
 * 240407 | ST | Created
 *        |    |
 *        |    |
 *        |    |
 *        |    |
 *
 *
 *
 ********************************************************************/

/*********************************************************************

 Return & parameter types:
   void
   char
   short
   char*
   oo_tdata

 Pin directions:
   0 = OUTPUT
   2 = INPUT
   3 = BIDIRECTIONAL

 Macro substitutions:
   %a = ??
   %b = ??
   %c = ??
   %d = ??
   %e = ??
   %f = ??
   %g = ??
   %h = ??
   %i = ??
   %j = ??

**********************************************************************

[Settings]
CLSID={4B174520-75AB-4B14-A0F7-2AA6C203F1DC}
IsAnalogue=0
MultipleAllowed=0
Description=One Wire Flowcode Component

**********************************************************************

[Port]
DesiredPort=0
PortMandatory=0
SamePortAsID=0

[Pins]
Count=0

[PinPort]
# PORTA = 0
# PORTB = 1
# PORTC = 2
# PORTD = 3
# PORTE = 4

[PinDesiredBit]

[PinDirection]
# DIR_INPUT = 2
# DIR_OUTPUT = 0
# DIR_BIDIRECTIONAL = 3

[PinMustUsePort]
# boolean

[SamePortAsPinX]
# -1 = any pin
# otherwise, the pin number

[PinMustUsePin]
# boolean

[PinValue]
# boolean (0 = off, 1 = on)

**********************************************************************

[MacroNames]
Count=11
1=GetDefines
2=oo_busreset
3=oo_get_pad_byte
4=oo_tx_byte
5=oo_rx_byte
6=oo_scanbus
7=oo_get_devicecount
8=oo_read_device
9=DS1820_start_conversion
10=DS1820_read_scratchpad
11=DS1820_get_temp

[MacroReturns]
1=void
2=char
3=char
4=void
5=char
6=char
7=char
8=char
9=char
10=char
11=short

[MacroIsPrivate]
1=1
2=0
3=0
4=0
5=0
6=0
7=0
8=0
9=0
10=0
11=0

[MacroParameters_GetDefines]
Count=0

[MacroParamTypes_GetDefines]


[MacroParameters_oo_busreset]
Count=0

[MacroParamTypes_oo_busreset]


[MacroParameters_oo_get_pad_byte]
Count=1
1=index

[MacroParamTypes_oo_get_pad_byte]
1=char

[MacroParameters_oo_tx_byte]
Count=1
1=data

[MacroParamTypes_oo_tx_byte]
1=char

[MacroParameters_oo_rx_byte]
Count=0

[MacroParamTypes_oo_rx_byte]


[MacroParameters_oo_scanbus]
Count=0

[MacroParamTypes_oo_scanbus]


[MacroParameters_oo_get_devicecount]
Count=0

[MacroParamTypes_oo_get_devicecount]


[MacroParameters_oo_read_device]
Count=1
1=count

[MacroParamTypes_oo_read_device]
1=char

[MacroParameters_DS1820_start_conversion]
Count=0

[MacroParamTypes_DS1820_start_conversion]


[MacroParameters_DS1820_read_scratchpad]
Count=0

[MacroParamTypes_DS1820_read_scratchpad]


[MacroParameters_DS1820_get_temp]
Count=0

[MacroParamTypes_DS1820_get_temp]



 ********************************************************************/

/********************************************************************
 * ADDITIONAL CODE
 ********************************************************************/

/*InitialisationCode_Start*/
/*InitialisationCode_End*/

/*InterruptCode_Start*/
/*InterruptCode_End*/




/********************************************************************
 * FUNCTIONS
 ********************************************************************/


void GetDefines()
{
/*Macro_GetDefines_Start*/

}  //Dummy end of function to allow defines to be added correctly

//Common Defines

#define CRC_CHECKING  	%a
#define OO_PORT  		%b
#define OO_TRIS  		%c
#define OO_PIN  		%d
#define OO_1US_DELAY  	%e
#define MX_CUSTOM_6  	%f
#define MX_CUSTOM_7  	%g
#define MX_CUSTOM_8  	%h
#define MX_CUSTOM_9  	%i
#define MX_CUSTOM_10 	%j

//Global Variables

char oo_scratchpad[9];
// Scratchpad contents
// 0	Temperature LSB
// 1	Temperature MSB
// 2	Hi alarm temperature
// 3	Lo alarm temperature
// 4	Reserved, 0xFF
// 5	Reserved, 0xFF
// 6	Remainder register
// 7	Nr of counts per degree
// 8	CRC of pad contents


// Commands for the OO
//    1. ROM function commands
#define        OO_READROM        	0x33
#define        OO_MATCHROM       	0x55
#define        OO_SKIPROM        	0xCC
#define        OO_SEARCHROM      	0xF0
#define        OO_ALARMSEARCH    	0xEC
//    2. Memory Command Functions
#define        OO_WRITEPAD       	0x4E
#define        OO_READPAD        	0xBE
#define        OO_COPYPAD        	0x48
#define        OO_CONVERTT       	0x44
#define        OO_RECALLE2			0xB8
#define        OO_READSUPPLY		0xB4


//I/O for the OO
#define Float_OO {set_bit(OO_TRIS, OO_PIN);}
#define Clear_OO {clear_bit(OO_TRIS, OO_PIN);	clear_bit(OO_PORT, OO_PIN);}


char oo_get_next_id();
void tx_bit(char out);
char rx_bit();

//CRC for the OO
#if CRC_CHECKING == 1

	// CRC working variable
	char crc = 0;

	// CRC lookup table
	rom char* crc_rom = {0, 94, 188, 226, 97, 63, 221, 131, 194, 156, 126, 32, 163, 253, 31, 65,
		157, 195, 33, 127, 252, 162, 64, 30, 95, 1, 227, 189, 62, 96, 130, 220,
		35, 125, 159, 193, 66, 28, 254, 160, 225, 191, 93, 3, 128, 222, 60, 98,
		190, 224, 2, 92, 223, 129, 99, 61, 124, 34, 192, 158, 29, 67, 161, 255,
		70, 24, 250, 164, 39, 121, 155, 197, 132, 218, 56, 102, 229, 187, 89, 7,
		219, 133, 103, 57, 186, 228, 6, 88, 25, 71, 165, 251, 120, 38, 196, 154,
		101, 59, 217, 135, 4, 90, 184, 230, 167, 249, 27, 69, 198, 152, 122, 36,
		248, 166, 68, 26, 153, 199, 37, 123, 58, 100, 134, 216, 91, 5, 231, 185,
		140, 210, 48, 110, 237, 179, 81, 15, 78, 16, 242, 172, 47, 113, 147, 205,
		17, 79, 173, 243, 112, 46, 204, 146, 211, 141, 111, 49, 178, 236, 14, 80,
		175, 241, 19, 77, 206, 144, 114, 44, 109, 51, 209, 143, 12, 82, 176, 238,
		50, 108, 142, 208, 83, 13, 239, 177, 240, 174, 76, 18, 145, 207, 45, 115,
		202, 148, 118, 40, 171, 245, 23, 73, 8, 86, 180, 234, 105, 55, 213, 139,
		87, 9, 235, 181, 54, 104, 138, 212, 149, 203, 41, 119, 244, 170, 72, 22,
		233, 183, 85, 11, 136, 214, 52, 106, 43, 117, 151, 201, 74, 20, 246, 168,
		116, 42, 200, 150, 21, 75, 169, 247, 182, 232, 10, 84, 215, 137, 107, 53};

	// CRC function prototypes
	void oo_crc_init();
	void oo_crc_shuffle_byte(char input);
#endif


// Internal variables
char        id[8];
signed char conflict;
char        new_conflict;


//Device ID Variables
char num_devices = 0;
char DevID[64] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
						0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

//internal function implementations

////////////////////////////////////////////////////////////
// oo_get_next_id()
// Helper function for the scanbus option. Gets the next
// id on the bus.
////////////////////////////////////////////////////////////
char oo_get_next_id()
{
	char val0 = 0;
	char val1 = 0;
	char counter    = 0;
	char bit_index  = 0;
	char byte_index = 0;
	char current_conflict = -1;
	new_conflict = 0;

	if (FCD_Custom0_oo_busreset())	// Reset the bus
	{
		return 1; // -> error
	}
	// Issue the search ROM command
	oo_tx_byte(OO_SEARCHROM);

	// Start the search for the sensor
	for (byte_index = 0; byte_index < 8; byte_index++)
	{
		char data_in_byte = 0;
		for (bit_index = 0; bit_index < 8; bit_index++)
		{
			// Read 2 consecutive bits from the One Wire bus
			val0 = rx_bit();						//Test Input
			val1 = rx_bit();						//Test Input

			// Evaluate the result
			if ((val0 == 0) && (val1 == 0))
			{
				current_conflict = counter;
				// if conflict occurs earlier than the previous conflict, then use the previous value
				if (current_conflict < conflict)
				{
					// use previous value
					if (id[byte_index] && (1 << bit_index))
					{
						val0 = 1;
					}
					else
					{
						val0 = 0;
						conflict = current_conflict;
						new_conflict = 1;
					}
				}
				else if (current_conflict == conflict)
				{
					// use 1
					val0 = 1;
				}
				else
				{
					// use zero on new conflicts
					val0 = 0;
					conflict = current_conflict;
					new_conflict = 1;
				}
			}
			else if (val0 && val1)
			{
				return 2;
			}
			// Store the bit in the ID array
			data_in_byte = data_in_byte >> 1;
			if (val0)
			{
				data_in_byte |= 0x80;
			}

			tx_bit(val0);

			counter++;
		}
		id[byte_index] = data_in_byte;
	}
	// Verify ID CRC
	#if CRC_CHECKING == 1
		oo_crc_init();
	#endif

	for (byte_index = 0; byte_index < 8; byte_index++)
	{
		#if CRC_CHECKING == 1
				oo_crc_shuffle_byte(id[byte_index]);
		#endif
	}
	// Bail on CRC errors
#if CRC_CHECKING == 1
	if (crc) return crc;
#endif
	return 0;
}


void tx_bit(char out)
{
	char count;
	Clear_OO;							//Clear Output Pin
	for (count=0; count<OO_1US_DELAY; count++)
	{
		nop();							//Delay 1us
	}
	if (out & 0x01)
		Float_OO;						//Float Output Pin
	delay_10us(6);						//Delay 60us
	Float_OO;							//Float Output Pin
	delay_10us(1);						//Delay 10us
}


char rx_bit()
{
	char oo_bit, count;
	Clear_OO;							//Clear Output Pin
	for (count=0; count<OO_1US_DELAY; count++)
	{
		nop();							//Delay 1us
	}
	Float_OO;							//Float Output Pin
	delay_10us(1);						//Delay 10us
	oo_bit = test_bit(OO_PORT, OO_PIN);	//Test Input
	delay_10us(5);						//Delay 50us
	return oo_bit;
}


#if CRC_CHECKING == 1

	////////////////////////////////////////////////////////////
	// oo_crc_init()
	// Initialise the CRC working register to be able to
	// start a new calculation
	////////////////////////////////////////////////////////////
	void oo_crc_init()
	{
		crc = 0;
	}



	////////////////////////////////////////////////////////////
	// oo_crc_shuffle_byte()
	//
	// Shuffle the next byte into the CRC
	////////////////////////////////////////////////////////////
	void oo_crc_shuffle_byte(char input)
	{
		crc = crc_rom[crc ^ input];
	}

#endif



// Dummy function to close the defines section off
void CUSTOM_Dummy_Function();
void CUSTOM_Dummy_Function()
{

/*Macro_GetDefines_End*/
}

////////////////////////////////////////////////////////////
// oo_busreset()
//
// Issues a 'ping' on the bus. If there is at least one
// sensor on the bus, it will generate a presence pulse.
// Returns: 0 if a presence pulse was detected
//          1 if no device was detected
////////////////////////////////////////////////////////////
char oo_busreset()
{
/*Macro_oo_busreset_Start*/
	Float_OO; 						// Release bus
	Clear_OO;						// Send the reset pulse
	delay_10us(60);					// Wait for 600 µs, this is the reset pulse
	Float_OO; 						// Release bus
	delay_10us(6);					// Wait 60 us (release) let device drive the bus
	if (test_bit(OO_PORT, OO_PIN) == 1)	// Now sample, if there is a sensor on the bus, the line should be low
		return 1; 					// <<-error
	delay_10us(54);					// Wait another 540 us to complete the reset sequence
	return 0;
/*Macro_oo_busreset_End*/
}



////////////////////////////////////////////////////////////
// char oo_get_pad_byte(char index)
// Returns the data from a byte in the last read scratchpad
////////////////////////////////////////////////////////////
char oo_get_pad_byte(char index)
{
/*Macro_oo_get_pad_byte_Start*/
	return oo_scratchpad[index];
/*Macro_oo_get_pad_byte_End*/
}



////////////////////////////////////////////////////////////
// oo_tx_byte(char data)
// Transmits a single byte to the bus
////////////////////////////////////////////////////////////
void oo_tx_byte(char data)
{
/*Macro_oo_tx_byte_Start*/
	char counter = 0;
	while (counter < 8)
	{
		tx_bit(data);
		data = data >> 1;				//Rotate to next bit of data
		counter++;						//Increment Counter
	}
/*Macro_oo_tx_byte_End*/
}



////////////////////////////////////////////////////////////
// char oo_rx_byte()
// Receives a single byte from the bus
////////////////////////////////////////////////////////////
char oo_rx_byte()
{
/*Macro_oo_rx_byte_Start*/
	char counter = 0;
	char data    = 0;
	bit  oo_bit  = 0;
	while (counter < 8)
	{
		oo_bit = rx_bit();
		data = data >> 1;					//Shift incoming data to next bit
		if (oo_bit==1)
		{
			data = data | 0x80;				//Append incoming bit to data byte
		}
		counter++;							//Increment Counter
	}
	#ifdef OO_CRC_CHECKING
		oo_crc_shuffle_byte(data);			//Check CRC
	#endif
	return data;
/*Macro_oo_rx_byte_End*/
}



////////////////////////////////////////////////////////////
// oo_scanbus()
// Scan the bus to detect all devices
////////////////////////////////////////////////////////////
char oo_scanbus(void)
{
/*Macro_oo_scanbus_Start*/
	char retval = 0;
	char device_count = 0;
	char loper;
	conflict = -1;
	new_conflict = 1;
	// Reset the bus, wake up devices.
	retval = FCD_Custom0_oo_busreset();
	if (retval == 1)
	{
		return 255; // -> error
	}
	// new_conflict gets updated in the oo_get_next_id() function.
	while (new_conflict)
	{
		retval = oo_get_next_id();
		// Bail in case of errors
		if (retval) return retval;
		// Add the device id to EEPROM
		for (loper=0; loper < 8; loper++)
		{
			DevID[loper+(device_count<<3)] = id[loper];
		}
		device_count++;
	}
	// Write number of devices to the EEPROM
	num_devices = device_count;
	return 0;
/*Macro_oo_scanbus_End*/
}



////////////////////////////////////////////////////////////
// char oo_get_devicecount()
// Returns the number of detected devices
////////////////////////////////////////////////////////////
char oo_get_devicecount()
{
/*Macro_oo_get_devicecount_Start*/
	return num_devices;
/*Macro_oo_get_devicecount_End*/
}



////////////////////////////////////////////////////////////
// char oo_read_device()
// Reads the temperature of the device @ location 'count'
// in the DevID array
////////////////////////////////////////////////////////////
char oo_read_device(char count)
{
/*Macro_oo_read_device_Start*/
	char loper = 0;
	char counter = 0;
	char temp;
	short value;
	FCD_Custom0_oo_busreset();
	FCD_Custom0_oo_tx_byte(OO_MATCHROM);
	for (loper=0; loper < 8; loper++)
	{
		id[loper] = DevID[loper+(count<<3)];
		FCD_Custom0_oo_tx_byte(id[loper]);
	}
	FCD_Custom0_oo_tx_byte(OO_READPAD);
	#if CRC_CHECKING == 1
		oo_crc_init();			//Reset the CRC register, CRC is updated in the oo_rx_byte() function.
	#endif
	while (counter < 9)
	{
		temp = oo_rx_byte();
		oo_scratchpad[counter] = temp;
		counter++;
	}
	#if CRC_CHECKING == 1
		return crc;				//Verify the CRC
	#endif
	return 0;
/*Macro_oo_read_device_End*/
}



////////////////////////////////////////////////////////////
// DS1820_start_conversion()
// DS1820 specific
// Commands all sensors to start a temperature conversion
////////////////////////////////////////////////////////////
char DS1820_start_conversion()
{
/*Macro_DS1820_start_conversion_Start*/
	char in = 0;
	char counter = 0;
	FCD_Custom0_oo_busreset();
	FCD_Custom0_oo_tx_byte(OO_SKIPROM);		// Command all temp sensors on the bus to start a conversion
	FCD_Custom0_oo_tx_byte(OO_CONVERTT);	// Convert temperature
	while (in == 0)
	{
		in = FCD_Custom0_oo_rx_byte();
		delay_ms(4);
		counter++;
		if (counter == 0xFF)		// Security: if the conversion is not completed
			return 1;				// after > 1 sec -> break.
	}
	return 0;
/*Macro_DS1820_start_conversion_End*/
}



////////////////////////////////////////////////////////////
// char DS1820_read_scratchpad()
// Reads the scratchpad of the currently selected device
////////////////////////////////////////////////////////////
char DS1820_read_scratchpad()
{
/*Macro_DS1820_read_scratchpad_Start*/
	char temp;
	char counter = 0;
	if (FCD_Custom0_oo_busreset())
		return (1);
	FCD_Custom0_oo_tx_byte(OO_SKIPROM);		//Command all temp sensors on the bus to start a conversion
	FCD_Custom0_oo_tx_byte(OO_READPAD);		//Convert temperature
	#if CRC_CHECKING == 1
		oo_crc_init();			//Reset the CRC register, CRC is updated in the oo_rx_byte() function.
	#endif
	while (counter < 9)
	{
		temp = oo_rx_byte();
		oo_scratchpad[counter] = temp;
		counter++;
	}
	#if CRC_CHECKING == 1
		return crc;				//Verify the CRC
	#endif
	return 0;
/*Macro_DS1820_read_scratchpad_End*/
}



////////////////////////////////////////////////////////////
// short DS1820_get_temp()
// DS1820 specific
// Returns the 2-byte value of the temperature register
////////////////////////////////////////////////////////////
short DS1820_get_temp()
{
/*Macro_DS1820_get_temp_Start*/
	short retval;
	retval = (short)oo_scratchpad[1];
	retval = retval << 8;
	retval += (short)oo_scratchpad[0];
	return retval;
/*Macro_DS1820_get_temp_End*/
}
