/*********************************************************************
 *                  Flowcode Internals Header File
 *
 * File: internals.h
 *
 * (c) 2009 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
 * -------+----+-----------------------------------------------------
 * 010107 | ST | Created
 * 010108 | SK | Edited for ICD Operation
 * 031108 | BR | Edited for integration with PPP
 * 130309 | BR | Added Floating point, Hex and Decimal String Coversion Functions
 * 160309 | BR | Added ICD Port Definitions
 * 160309 | BR | Added Watchdog Delay routines
 * 090409 | BR | Fixed minor definitions bug
 * 170409 | BR | Optimised Floating / String conversions
 * 210509 | BR | Fixed ICD Stop and wait functionality
 * 110809 | BR | Changed the amount of delay in the watchdog ms delay routine
 * 160909 | BR | Added BoostC and HiTECH definitions
 * 290909 | BR | Altered the Test_bit function and ICD arrays for HITECH
 * 161009 | BR | Added a missing semi colon and added the math.h library for 16F devices
 * 221009 | BR | Removed the FCI_TMP_STR and FCI_TMP_INT variables
 * 101209 | BR | Altered timeout val and in <dbg_hold> routine got rid of initial delay and comms now wait forever
 * 181209 | BR | Edited reset function for use with the HITECH compiler.
 * 230210 | BR | Fixed a bug with multiple string concats requiring surplus variables.
 * 230710 | BR | Fixed an overflow bug in the Float to string and string to int functions
 * 270511 | ST | Added CAN fucntions for the MIAC_SYSTEM (from SK)
 * 020611 | BR | Disabled ICD functions from running when an interrupt is active
 * 220611 | BR | Modified the watchdog delays to try to provide better delay accuracy
 * 300611 | SK | Added MIAC Add-on Float Union Code
 * 110711 | SK | Duplicated MIAC I/O Functions - System Components
 * 210711 | ST | Fixed minor delay code bug
 ********************************************************************/

#ifndef internals_h
#define internals_h

//BR 23/02/10 - These are needed by multiple concat statements?
//However 10F devices could not allocate enough memory to create array
#ifndef MX_10F_TRIS
	unsigned char FCI_TMP_STR[20];
	int FCI_TMP_INT;
#endif

//String function definitions
char FCI_GETCHAR(char* sStr1, char iStr1_len, char iPos);
char FCI_GETLENGTH(char* sStr1, char iStr1_len);
char FCI_MIDSTRING(char* sSrc, char iSrc_len, char* sDst, char iDst_len, char iStart, char iCount);
char FCI_LEFTSTRING(char* sSrc, char iSrc_len, char* sDst, char iDst_len, char iCount);
char FCI_RIGHTSTRING(char* sSrc, char iSrc_len, char* sDst, char iDst_len, char iCount);
char FCI_CONCATENATE(char* sSrc1, char iSrc1_len, char* sSrc2, char iSrc2_len, char* sDst, char iDst_len);
char FCI_TOSTRING(int iSrc1, char* sDst, char iDst_len);
void FCI_TOLOWER(char* sSrc, char iSrc_len, char* sDst, char iDst_len);
void FCI_TOUPPER(char* sSrc, char iSrc_len, char* sDst, char iDst_len);
char FCI_COMPARE(char* sSrc1, char iSrc1_len, char* sSrc2, char iSrc2_len, char iNoCase);
char FCI_FLOAT_TO_STRING(float Number, char Precision, char* String, char MSZ_String);
char FCI_NUMBER_TO_HEX(short Number, char* String, char MSZ_String);
long FCI_STRING_TO_INT(char* String, char MSZ_String);
float FCI_STRING_TO_FLOAT(char* String, char MSZ_String);
void Wdt_Delay_S(char delay);
void Wdt_Delay_Ms(char delay);
char isinf(float f);
char FCI_LONG_TOSTRING(long iSrc1, char* sDst, char iDst_len);



	char FCI_LONG_TOSTRING(long iSrc1, char* sDst, char iDst_len)
	{
		char tmp1;
		long tmp2;
		char idx = 0;

		//copy source 1 into destination:
		//minus sign
		if (iSrc1 < 0)
		{
			sDst[0] = '-';
			idx++;
			iSrc1 = 0 - iSrc1;
		}

		tmp2 = iSrc1;
		if (iSrc1 >= 10000000)
		{
			if (idx < iDst_len)
			{
				tmp1 = tmp2 / 10000000;
				sDst[idx] = '0' + tmp1;
				idx++;
			}

			while (tmp1 > 0)
			{
				tmp2 = tmp2 - 10000000;
				tmp1--;
			}
		}

		if (iSrc1 >= 1000000)
		{
			if (idx < iDst_len)
			{
				tmp1 = tmp2 / 1000000;
				sDst[idx] = '0' + tmp1;
				idx++;
			}

			while (tmp1 > 0)
			{
				tmp2 = tmp2 - 1000000;
				tmp1--;
			}
		}

		if (iSrc1 >= 100000)
		{
			if (idx < iDst_len)
			{
				tmp1 = tmp2 / 100000;
				sDst[idx] = '0' + tmp1;
				idx++;
			}

			while (tmp1 > 0)
			{
				tmp2 = tmp2 - 100000;
				tmp1--;
			}
		}

		if (iSrc1 >= 10000)
		{
			if (idx < iDst_len)
			{
				tmp1 = tmp2 / 10000;
				sDst[idx] = '0' + tmp1;
				idx++;
			}

			while (tmp1 > 0)
			{
				tmp2 = tmp2 - 10000;
				tmp1--;
			}
		}

		if (iSrc1 >= 1000)
		{
			if (idx < iDst_len)
			{
				tmp1 = tmp2 / 1000;
				sDst[idx] = '0' + tmp1;
				idx++;
			}

			while (tmp1 > 0)
			{
				tmp2 = tmp2 - 1000;
				tmp1--;
			}
		}

		if (iSrc1 >= 100)
		{
			if (idx < iDst_len)
			{
				tmp1 = tmp2 / 100;
				sDst[idx] = '0' + tmp1;
				idx++;
			}

			while (tmp1 > 0)
			{
				tmp2 = tmp2 - 100;
				tmp1--;
			}
		}

		if (iSrc1 >= 10)
		{
			if (idx < iDst_len)
			{
				tmp1 = tmp2 / 10;
				sDst[idx] = '0' + tmp1;
				idx++;
			}

			while (tmp1 > 0)
			{
				tmp2 = tmp2 - 10;
				tmp1--;
			}
		}

		if (idx < iDst_len)
		{
			sDst[idx] = '0' + tmp2;
			idx++;
		}

		//add terminating null (if we can)
		if (idx < iDst_len)
		{
			sDst[idx] = 0;
		}

		return (idx);
	}




/******************** BOOST C SPECIFICS *****************/
#ifdef _BOOSTC

	#include <float.h>

	#pragma CLOCK_FREQ 				MX_CLK_SPEED
	#define MX_INTERRUPT_MACRO		interrupt
	#define MX_CLEAR_WATCHDOG		clear_wdt()

	#define st_bit(var,bitno) 		set_bit(var,bitno)
	#define cr_bit(var,bitno) 		clear_bit(var,bitno)
	#define ts_bit(var,bitno)		test_bit(var,bitno)

#endif

/******************* HITECH C SPECIFICS *****************/
#ifdef HI_TECH_C

	#include <htc.h> 				//Delay Params
	#include "definitions.h"
	#include <math.h>

	#define _XTAL_FREQ 				MX_CLK_SPEED
	#define MX_INTERRUPT_MACRO		interrupt myisr
	#define MX_CLEAR_WATCHDOG		CLRWDT()

	char ts_bit(char reg, char bt);
	char test_bit(char reg, char bt);
	void delay_10us(char del);
	void delay_us(char del);
	void delay_ms(char del);
	void delay_s(char del);
	void nop(void);
	float float32_add(float a, float b);
	float float32_sub(float a, float b);
	float float32_mul(float a, float b);
	float float32_div(float a, float b);
	float float32_rem(float a, float b);
	char float32_is_signaling_nan(float a);
	char float32_eq(float a, float b);
	char float32_ge(float a, float b);
	char float32_gt(float a, float b);
	char float32_le(float a, float b);
	char float32_lt(float a, float b);
	short float32_to_int32 (float a);
	float float32_from_int32 (short a);

	#define INTE					INT0IE
	#define INTF					INT0IF

	#define st_bit(var,bitno) 		bitno = 1
	#define cr_bit(var,bitno) 		bitno = 0
	#define set_bit(var,bitno) 		var |= (1 << bitno)
	#define clear_bit(var,bitno) 	var &= ~(1 << bitno)

	char ts_bit(char reg, char bt)
	{
		if (bt)
			return 1;
		return 0;
	}

	char test_bit(char reg, char bt)
	{
		if (reg & (1 << bt))
			return (1 << bt);
		return 0;
	}

	void delay_10us(char del)
	{
		char count;
		for(count=0; count<10; count++)
		{
			delay_us(del);
		}
	}

	void delay_us(char del)
	{
		while (del > 1)
		{
			__delay_us(1);
			del = del - 1;
		}
	}

	void delay_ms(char del)
	{
		while (del > 1)
		{
			__delay_ms(1);
			del = del - 1;
		}
	}

	void delay_s(char del)
	{
		char i;
		for(i=0; i<del; i++)
		{
			delay_ms(250);
			delay_ms(250);
			delay_ms(250);
			delay_ms(250);
		}
	}

	void nop()
	{
		asm("NOP");
	}

	float float32_add(float a, float b)
	{
		return (a + b);
	}

	float float32_sub(float a, float b)
	{
		return (a - b);
	}

	float float32_mul(float a, float b)
	{
		return (a * b);
	}

	float float32_div(float a, float b)
	{
		return (a / b);
	}

	float float32_rem(float a, float b)
	{
		return (fmod(a, b));
	}

	char float32_is_signaling_nan(float a)
	{
		return isinf(a);
	}

	char float32_eq(float a, float b)
	{
		return (a == b);
	}

	char float32_ge(float a, float b)
	{
		return (a >= b);
	}

	char float32_gt(float a, float b)
	{
		return (a > b);
	}

	char float32_le(float a, float b)
	{
		return (a <= b);
	}

	char float32_lt(float a, float b)
	{
		return (a < b);
	}

	short float32_to_int32 (float a)
	{
		return ((int)a);
	}

	float float32_from_int32 (short a)
	{
		return ((float)a);
	}

	char FCI_GETCHAR(char* sStr1, char iStr1_len, char iPos)
	{
		char tmp;
		for (tmp = 0; tmp < iStr1_len; tmp++)
		{
			if (*sStr1 == 0)
				break;
			sStr1++;
		}

		if(iPos < tmp)
			tmp = *sStr1;
		else tmp = 0;
		return (tmp);
	}

	char FCI_GETLENGTH(char* sStr1, char iStr1_len)
	{
		char tmp;
		for (tmp = 0; tmp < iStr1_len; tmp++)
		{
			if (*sStr1 == 0)
				break;
			sStr1++;
		}
		return (tmp);
	}

	char FCI_MIDSTRING(char* sSrc, char iSrc_len, char* sDst, char iDst_len, char iStart, char iCount)
	{
		char idx;
		for (idx = 0; idx < iSrc_len; idx++)	//find the length of the source string
		{
			if (*sSrc == 0)
				break;
			sSrc++;
		}

		if (iStart >= idx)
		{
			*sDst = 0;							//starting position is beyond string length, so return a null string
		}
		else
		{
			if ((iStart + iCount) >= idx)		//Make sure the required length is not too big
				iCount = idx - iStart;

			sSrc = 0;

			for (idx = 0; idx < iStart; idx++)	//Move to the correct place in the source string
				sSrc++;

			for (idx = 0; idx < iCount; idx++)	//Copy the contents of the source string
			{
				if (idx < iDst_len)
				{
					*sDst = *sSrc;
					sDst++;
					sSrc++;
				}
				else break;
			}

			if (idx < iDst_len)					//add terminating null (if we can)
				*sDst = 0;
		}
		return (idx);
	}

	char FCI_LEFTSTRING(char* sSrc, char iSrc_len, char* sDst, char iDst_len, char iCount)
	{
		char idx = 0;
		for (idx = 0; idx < iSrc_len; idx++)	//find the length of the source string
		{
			if (*sSrc == 0)
				break;
			sSrc++;
		}

		if (iCount > idx)						//make sure the required length is not too big
			iCount = idx;

		sSrc = 0;

		for (idx = 0; idx < iCount; idx++)		//copy the required characters
		{
			if (idx < iDst_len)
			{
				*sDst = *sSrc;
				sDst++;
				sSrc++;
			}
			else break;
		}

		if (idx < iDst_len)						//add terminating null (if we can)
			*sDst = 0;

		return (idx);
	}

	char FCI_RIGHTSTRING(char* sSrc, char iSrc_len, char* sDst, char iDst_len, char iCount)
	{
		char idx = 0;
		char delta;

		for (idx = 0; idx < iSrc_len; idx++)	//find the length of the source string
		{
			if (*sSrc == 0)
				break;
			sSrc++;
		}

		if (iCount > idx)						//make sure the required length is not too big
			iCount = idx;

		delta = idx - iCount;					//get the offset

		sSrc = 0;
		for (idx = 0; idx < delta; idx++)		//Move to the correct place in the source string
			sSrc++;

		for(idx = 0; idx < iCount; idx++)		//copy the required characters
		{
			if (idx < iDst_len)
			{
				*sDst = *sSrc;
				sDst++;
				sSrc++;
			}
			else break;
		}

		if (idx < iDst_len)						//add terminating null (if we can)
			*sDst = 0;

		return (idx);
	}

	char FCI_CONCATENATE(char* sSrc1, char iSrc1_len, char* sSrc2, char iSrc2_len, char* sDst, char iDst_len)
	{
		char tmp;
		char idx = 0;

		for (tmp=0; tmp<iSrc1_len; tmp++)		//copy source 1 into destination
		{
			if (idx < iDst_len)
			{
				*sDst = *sSrc1;
				sDst++;
				sSrc1++;

				if (*sSrc1 != 0)
					idx++;
				else break;
			}
		}

		for (tmp=0; tmp<iSrc2_len; tmp++)		//copy source 2 into destination
		{
			if (idx < iDst_len)
			{
				*sDst = *sSrc2;
				sDst++;
				sSrc2++;

				if (*sSrc2 != 0)
					idx++;
				else break;
			}
		}

		if (idx < iDst_len)						//add terminating null (if we can)
			*sDst = 0;

		return (idx);
	}


	char FCI_TOSTRING(int iSrc1, char* sDst, char iDst_len)
	{
		char tmp1;
		short tmp2;
		char idx = 0;

		//copy source 1 into destination:
		//minus sign
		if (iSrc1 < 0)
		{
			sDst[0] = '-';
			idx++;
			iSrc1 = 0 - iSrc1;
		}

		tmp2 = iSrc1;
		if (iSrc1 >= 10000)
		{
			if (idx < iDst_len)
			{
				tmp1 = tmp2 / 10000;
				sDst[idx] = '0' + tmp1;
				idx++;
			}

			while (tmp1 > 0)
			{
				tmp2 = tmp2 - 10000;
				tmp1--;
			}
		}

		if (iSrc1 >= 1000)
		{
			if (idx < iDst_len)
			{
				tmp1 = tmp2 / 1000;
				sDst[idx] = '0' + tmp1;
				idx++;
			}

			while (tmp1 > 0)
			{
				tmp2 = tmp2 - 1000;
				tmp1--;
			}
		}

		if (iSrc1 >= 100)
		{
			if (idx < iDst_len)
			{
				tmp1 = tmp2 / 100;
				sDst[idx] = '0' + tmp1;
				idx++;
			}

			while (tmp1 > 0)
			{
				tmp2 = tmp2 - 100;
				tmp1--;
			}
		}

		if (iSrc1 >= 10)
		{
			if (idx < iDst_len)
			{
				tmp1 = tmp2 / 10;
				sDst[idx] = '0' + tmp1;
				idx++;
			}

			while (tmp1 > 0)
			{
				tmp2 = tmp2 - 10;
				tmp1--;
			}
		}

		if (idx < iDst_len)
		{
			sDst[idx] = '0' + tmp2;
			idx++;
		}

		//add terminating null (if we can)
		if (idx < iDst_len)
		{
			sDst[idx] = 0;
		}

		return (idx);
	}

	void FCI_TOLOWER(char* sSrc, char iSrc_len, char* sDst, char iDst_len)
	{
		char idx;
		char ch;

		//copy source into destination and change to lower case
		for (idx=0; idx<iSrc_len; idx++)
		{
			if (idx < iDst_len)
			{
				ch = sSrc[idx];
				sDst[idx] = ch;
				if (ch != 0)
				{
					if ((ch >= 'A') && (ch <= 'Z'))
					{
						sDst[idx] = (ch | 0x20);
					}
				} else {
					break;
				}
			}
		}
	}

	void FCI_TOUPPER(char* sSrc, char iSrc_len, char* sDst, char iDst_len)
	{
		char idx;
		char ch;

		//copy source into destination and change to upper case
		for (idx=0; idx<iSrc_len; idx++)
		{
			if (idx < iDst_len)
			{
				ch = sSrc[idx];
				sDst[idx] = ch;
				if (ch != 0)
				{
					if ((ch >= 'a') && (ch <= 'z'))
					{
						sDst[idx] = (ch & 0xDF);
					}
				} else {
					break;
				}
			}
		}
	}

	char FCI_COMPARE(char* sSrc1, char iSrc1_len, char* sSrc2, char iSrc2_len, char iNoCase)
	{
		char iRetVal = 0;
		char idx;
		char ch1, ch2;

		for (idx=0; idx < iSrc1_len; idx++)	//compare a byte from the strings
		{
			if (idx < iSrc2_len)
			{
				ch1 = *sSrc1;
				ch2 = *sSrc2;

				if (iNoCase)
				{
					if ((ch1 >= 'a') && (ch1 <= 'z'))
						ch1 = (ch1 & 0xDF);

					if ((ch2 >= 'a') && (ch2 <= 'z'))
						ch2 = (ch2 & 0xDF);

				}

				if (ch1 < ch2)
				{
					return(255);
				}
				else if (ch1 > ch2)
				{
					return(1);
				}

				sSrc1++;
				sSrc2++;
			}
			else
			{
				if (*sSrc1 == 0)
					return (0);				//end of source1 as well, so ok
				else
					return (1);				//reached the end of iSrc2, but still more of iSrc1
			}
		}

		if (iSrc1_len == iSrc2_len)			//reached the end of iSrc1.  If we're also at the end of iSrc2, then return 0
			return (0);
		else
		{
			if (*sSrc2 == 0)
				return (0);					//end of source1 as well, so ok
			else
				return (255);				//not at end of source2, so return -1
		}
	}
#endif


/********************* ICD SPECIFICS *******************/
#ifdef USE_FLOWCODE_ICD

	char ICD_Interrupt_Enable = 0;

	//ICD Clock Port Defines
	#if (ICD_CLK_PORT == 0)
		#ifdef PORTA
			#define ICD_CLK_PIN_TRIS trisa
			#define ICD_CLK_PIN_PORT porta
		#endif
		#ifdef gpio
			#define ICD_CLK_PIN_PORT gpio
			#ifdef trisgpio
				#define ICD_CLK_PIN_TRIS trisgpio
			#endif
			#ifdef trisio
				#define ICD_CLK_PIN_TRIS trisio
			#endif
			#ifdef tris
				#define ICD_CLK_PIN_TRIS tris
			#endif
		#endif
	#endif
	#if (ICD_CLK_PORT == 1)
	  #define ICD_CLK_PIN_TRIS trisb
	  #define ICD_CLK_PIN_PORT portb
	#endif
	#if (ICD_CLK_PORT == 2)
	  #define ICD_CLK_PIN_TRIS trisc
	  #define ICD_CLK_PIN_PORT portc
	#endif
	#if (ICD_CLK_PORT == 3)
	  #define ICD_CLK_PIN_TRIS trisd
	  #define ICD_CLK_PIN_PORT portd
	#endif
	#if (ICD_CLK_PORT == 4)
	  #define ICD_CLK_PIN_TRIS trise
	  #define ICD_CLK_PIN_PORT porte
	#endif
	#if (ICD_CLK_PORT == 5)
	  #define ICD_CLK_PIN_TRIS trisf
	  #define ICD_CLK_PIN_PORT portf
	#endif
	#if (ICD_CLK_PORT == 6)
	  #define ICD_CLK_PIN_TRIS trisg
	  #define ICD_CLK_PIN_PORT portg
	#endif

	//ICD Data Port Defines
	#if (ICD_DATA_PORT == 0)
		#ifdef PORTA
			#define ICD_DATA_PIN_TRIS trisa
			#define ICD_DATA_PIN_PORT porta
		#endif
		#ifdef GPIO
			#define ICD_DATA_PIN_PORT gpio
			#ifdef trisgpio
				#define ICD_DATA_PIN_TRIS trisgpio
			#endif
			#ifdef trisio
				#define ICD_DATA_PIN_TRIS trisio
			#endif
			#ifdef tris
				#define ICD_DATA_PIN_TRIS tris
			#endif
		#endif
	#endif
	#if (ICD_DATA_PORT == 1)
	  #define ICD_DATA_PIN_TRIS trisb
	  #define ICD_DATA_PIN_PORT portb
	#endif
	#if (ICD_DATA_PORT == 2)
	  #define ICD_DATA_PIN_TRIS trisc
	  #define ICD_DATA_PIN_PORT portc
	#endif
	#if (ICD_DATA_PORT == 3)
	  #define ICD_DATA_PIN_TRIS trisd
	  #define ICD_DATA_PIN_PORT portd
	#endif
	#if (ICD_DATA_PORT == 4)
	  #define ICD_DATA_PIN_TRIS trise
	  #define ICD_DATA_PIN_PORT porte
	#endif
	#if (ICD_DATA_PORT == 5)
	  #define ICD_DATA_PIN_TRIS trisf
	  #define ICD_DATA_PIN_PORT portf
	#endif
	#if (ICD_DATA_PORT == 6)
	  #define ICD_DATA_PIN_TRIS trisg
	  #define ICD_DATA_PIN_PORT portg
	#endif

	#ifndef ICD_CLK_PIN_TRIS
	  #warning "Error: no definition for the ICD clock pin"
	#endif

	#ifndef ICD_DATA_PIN_TRIS
	  #warning "Error: no definition for the ICD data pin"
	#endif

	//ICD Global Defines
	#define ICD_START	  0x80
	#define ICD_SETBP	  0x81
	#define ICD_CLRBP	  0x82
	#define ICD_EN_IBP	  0x83
	#define ICD_DIS_IBP	  0x84
	#define ICD_EN_SBP	  0x85
	#define ICD_DIS_SBP	  0x86
	#define ICD_RD_RAM	  0x87
	#define ICD_WR_RAM	  0x88
	#define ICD_GET_ID    0x8C
	#define ICD_GET_STACK 0x8D
	#define ICD_DIS_BPS	  0x8B
	#define ICD_RESET	  0x8E

	#ifdef MX_EE					//If EEPROM
		#define ICD_RD_EE	  0x89
		#define ICD_WR_EE	  0x8A
	#endif

	//ICD Global Variables
	unsigned char dbg_mode = 0x00;
	unsigned char icd_stack_ptr = 0x00;
	unsigned int ICD_TIMEOUT = 1000;

	//ICD Functions
	void FC_MARKER(signed int block_id);
	void ICD_PUSH(char macro_id);
	void ICD_POP();
	unsigned char icd_byte_tx(char data);
	unsigned char icd_byte_rx(void);
	unsigned char wait_clock(char state, char timeout_inc);
	unsigned char wait_data(char state);
	char read_register(unsigned int address);
	void write_register(unsigned int address, char data);
	void rst_dev(void);

	//ICD Marker Functions - Called at the start of every Flowcode block when ICD is enabled.
	void FC_MARKER(signed int block_id)
	{
		if (ICD_Interrupt_Enable == 0)
		{
			unsigned char dbg_hold = 0;
			unsigned char icd_cmd;
			unsigned int address;
			unsigned char int_store = 0;
			unsigned char idx;
			char tempdata = 0;

			set_bit(ICD_CLK_PIN_TRIS, ICD_CLK_PIN);					//Clock is an input
			clear_bit(ICD_DATA_PIN_TRIS, ICD_DATA_PIN);				//Data is an output
			set_bit(ICD_DATA_PIN_PORT, ICD_DATA_PIN);				//Data is default low	****** inverted

			if(test_bit(ICD_CLK_PIN_PORT, ICD_CLK_PIN))				//Test to see if clock input is 1
				dbg_mode = dbg_mode | 0x04;					//Enable ICD Pause
			else
				dbg_mode = dbg_mode & 0xFB;					//Disable ICD Pause

			if(dbg_mode)									//Is ICD Active?
			{
				int_store = intcon;							//Store interrupt register
				intcon = 0;									//Disable all interrupts

				if(dbg_mode & 0x01) dbg_hold = 0x01;		//Test for Single Step operation
				if(dbg_mode & 0x02)							//Test for Breakpoint operation and match
				{
					for(idx=0; idx<ICD_NUM_BPS; idx++)
					{
						if(block_id == *(brk_pnt + idx)) dbg_hold = dbg_hold | 0x02;		//if(block_id == brk_pnt[idx]) dbg_hold = dbg_hold | 0x02;
					}
				}

				if(dbg_mode & 0x04) 								//Test for Flowcode triggered operation
					dbg_hold = dbg_hold | 0x04;

				if(dbg_mode & 0x08) 								//Test for initial stop condition
				{
					dbg_hold = dbg_hold | 0x08;						//Place target into infinite wait mode
					dbg_mode = dbg_mode & 0xF7;						//Disable infinite wait mode for next iteration.
				}

				if(dbg_hold)										//Enter Debug mode
				{
					set_bit(ICD_DATA_PIN_TRIS, ICD_DATA_PIN);		//Data is an input target stopped

					if (dbg_hold & 0x08)
					{
						//delay_us(250);								//Wait for pins to settle after reset
						delay_us(250);								//Wait for pins to settle after reset
						wait_clock(1<<ICD_CLK_PIN, 0);				//Wait indefinitely for the next clock
						wait_clock(0, 0);							//Wait indefinitely for the next clock
						wait_clock(1<<ICD_CLK_PIN, 0);				//Wait indefinitely for the next clock
						icd_byte_tx(dbg_mode);						//Send current ICD mode
						icd_byte_tx(block_id);						//Send block ID
						icd_byte_tx(block_id>>8);

					}
					else
					{
						if (wait_clock(1<<ICD_CLK_PIN, 1))			//Wait for clock to go high
							return;
						if (wait_clock(0, 0))						//Wait for clock to go low
							return;
						if (wait_clock(1<<ICD_CLK_PIN, 0))			//Wait for clock to go high
							return;

						if (icd_byte_tx(dbg_mode)) dbg_hold = 0;	//Send current ICD mode
						if (icd_byte_tx(block_id)) dbg_hold = 0;	//Send block ID
						if (icd_byte_tx(block_id>>8)) dbg_hold = 0;
					}

					while(dbg_hold)
					{
						icd_cmd = icd_byte_rx();							//Receive command byte

						switch(icd_cmd)
						{
							case ICD_START:									//Start Command

								dbg_hold = 0;								//Start the target running
								clear_bit(ICD_DATA_PIN_TRIS, ICD_DATA_PIN);				//Data is an output
								set_bit(ICD_DATA_PIN_PORT, ICD_DATA_PIN);				//Data is default low	**** inverted
								wait_clock(0, 1);
								break;

							case ICD_SETBP:						//Set Breakpoint Command

								address = icd_byte_rx();					//Receive BP ID
								address = address | (icd_byte_rx() << 8);
								idx=0;										//Initialise BP counter
								while(idx < ICD_NUM_BPS && *(brk_pnt + idx) != -1)	//Scan for empty BP slot           //while(idx < ICD_NUM_BPS && brk_pnt[idx] != -1)	//Scan for empty BP slot
									idx = idx + 1;

								if (idx == ICD_NUM_BPS)						//If breakpoint command list full
									icd_byte_tx(255);						//Let the ICD know
								else
								{
									*(brk_pnt + idx) = address;					//Else assign the BP ID to the BP list				//brk_pnt[idx] = address;
									icd_byte_tx(0);							//Transmit an acknowledge
								}
								break;

							case ICD_CLRBP:						//Clear Breakpoint Command

								address = icd_byte_rx();
								address = address | (icd_byte_rx() << 8);
								idx=0;										//Initialise BP counter
								while(idx < ICD_NUM_BPS && *(brk_pnt + idx) != address)	//Scan for slot containing BP				//while(idx < ICD_NUM_BPS && brk_pnt[idx] != address)
									idx = idx + 1;

								if (idx == ICD_NUM_BPS)						//If breakpoint not in the list
									icd_byte_tx(255);						//Let the ICD know
								else
								{
									*(brk_pnt + idx) = -1;						//Else clear the BP ID from the BP list					//brk_pnt[idx] = -1;
									icd_byte_tx(0);							//Transmit an acknowledge
								}
								break;

							case ICD_EN_IBP:					//Enable indexed breakpoints Command

								dbg_mode = dbg_mode | 0x02;					//Enable indexed breakpoints
								break;

							case ICD_DIS_IBP:					//Disable indexed breakpoints Command

								dbg_mode = dbg_mode & 0xFD;					//Disable indexed breakpoints
								break;

							case ICD_EN_SBP:					//Enable step breakpoint Command

								dbg_mode = dbg_mode | 0x01;					//Enable step breakpoint
								break;

							case ICD_DIS_SBP:					//Disable step breakpoint Command

								dbg_mode = dbg_mode & 0xFE;					//Disable step breakpoint
								break;

							case ICD_RD_RAM:					//Read Byte Of RAM Command

								address = icd_byte_rx();
								address = address | (icd_byte_rx() << 8);
								icd_byte_tx(read_register(address));		//&address//Transmit the register value
								break;

							case ICD_WR_RAM:					//Write Byte Of RAM Command

								address = icd_byte_rx();
								address = address | (icd_byte_rx() << 8);
								write_register(address, icd_byte_rx());
								break;

							case ICD_DIS_BPS:					//Clear all breakpoints

								idx=0;	//init BP counter
								while (idx < ICD_NUM_BPS)
								{
									*(brk_pnt + idx) = -1;											//brk_pnt[idx] = -1;
									idx = idx + 1;
								}
								break;

							#ifdef MX_EE						//Is EEPROM Available?
								#ifdef _BOOSTC
									#ifndef MX_EEADR
										#ifdef EEADR
											#define MX_EEADR eeadr
										#endif
										#ifdef EEADRL
											#define MX_EEADR eeadrl
										#endif
									#endif
									#ifndef MX_EEDATA
										#ifdef EEDATA
											#define MX_EEDATA eedata
										#endif
										#ifdef EEDATAL
											#define MX_EEDATA eedatal
										#endif
									#endif
								#endif

								case ICD_RD_EE:					//Read Contents Of EEPROM Command

									address = icd_byte_rx();
									address = address | (icd_byte_rx() << 8);

									#ifdef _BOOSTC
										MX_EEADR = address & 0xff;
										#if (MX_EE_SIZE > 256)
											eeadrh = (address & 0xff00) >> 8;
										#endif
										#ifdef MX_EE_TYPE2
											cr_bit(eecon1, EEPGD);
										#endif
										#ifdef MX_EE_TYPE3
											cr_bit(eecon1, EEPGD);
											cr_bit(eecon1, CFGS);
										#endif
											st_bit(eecon1, RD);

										icd_byte_tx(MX_EEDATA);
									#endif
									#ifdef HI_TECH_C
										icd_byte_tx(eeprom_read(address));
									#endif
									break;

								case ICD_WR_EE:					//Write Byte to EEPROM Command

									address = icd_byte_rx();
									address = address | (icd_byte_rx() << 8);
									tempdata = icd_byte_rx();

									#ifdef _BOOSTC
										while (ts_bit(eecon1, WR));				//wait for previous EE writes to complete...

										#if (MX_EE_SIZE > 256)
											eeadrh = (address & 0xff00) >> 8;
										#endif

										MX_EEADR = address & 0xff;
										MX_EEDATA = tempdata;

										#ifdef MX_EE_TYPE2
											cr_bit(eecon1, EEPGD);
										#endif
										#ifdef MX_EE_TYPE3
											cr_bit(eecon1, EEPGD);
											cr_bit(eecon1, CFGS);
										#endif

										st_bit(eecon1, WREN);
										eecon2 = 0x55;
										eecon2 = 0xAA;
										st_bit(eecon1, WR);
										while (ts_bit(eecon1, WR));				//wait for EE write to complete...
									#endif
									#ifdef HI_TECH_C
										eeprom_write(address, tempdata);
									#endif

									break;

							#endif								//End of EEPROM code

							case ICD_GET_ID:
								icd_byte_tx(ICD_ID0);
								icd_byte_tx(ICD_ID1);
								icd_byte_tx(ICD_ID2);
								icd_byte_tx(ICD_ID3);
								icd_byte_tx(ICD_ID4);
								icd_byte_tx(ICD_ID5);
								icd_byte_tx(ICD_ID6);
								icd_byte_tx(ICD_ID7);
								break;

							case ICD_GET_STACK:
								icd_byte_tx(ICD_STACK_SIZE+1);		//+1 because the PPP firmware does not expect the stack pointer return as well
								icd_byte_tx(icd_stack_ptr);
								for (idx=0; idx<ICD_STACK_SIZE; idx++)
								{
									icd_byte_tx(*(icd_stack + idx));											//icd_byte_tx(icd_stack[idx]);
								}
								break;

							case ICD_RESET:
								rst_dev();
								break;

							default:
								break;
						}
					}
				}
				clear_bit(ICD_DATA_PIN_TRIS,ICD_DATA_PIN);				//Data line as output
				set_bit(ICD_DATA_PIN_PORT,ICD_DATA_PIN);				//Data output low	**** inverted
				intcon = int_store;										//Restore all interrupts
			}
		}
	}


	void ICD_PUSH(char macro_id)
	{
		if (ICD_Interrupt_Enable == 0)
		{
			//note: there is no specific stack overflow test here (there will be at the PC end though)
			if (icd_stack_ptr < ICD_STACK_SIZE)
			{
				*(icd_stack + icd_stack_ptr) = macro_id;			//Assign macro ID				//icd_stack[icd_stack_ptr] = macro_id;
			}
			icd_stack_ptr++;									//Move to next layer of stack
		}
	}


	void ICD_POP()
	{
		if (ICD_Interrupt_Enable == 0)
		{
			//note: there is no specific stack underflow test here (there will be at the PC end though)
			icd_stack_ptr--;
		}
	}


	//ICD transmit byte Function - Bit bangs out a data byte.
	char icd_byte_tx(char data)
	{
		char count, mask;

		set_bit(ICD_CLK_PIN_TRIS,ICD_CLK_PIN);				//Clock line as input
		clear_bit(ICD_DATA_PIN_TRIS,ICD_DATA_PIN);			//Data line as output
		set_bit(ICD_DATA_PIN_PORT,ICD_DATA_PIN);			//Data is 0 RTS		**** inverted

		if (wait_clock(0, 1))							//Wait for clock to go low
			return 255;

		for(count=0; count<8; count++)
		{
			mask = data & 0x01;						//Prepare data
			if(mask)								//Write data onto data line
				clear_bit(ICD_DATA_PIN_PORT,ICD_DATA_PIN);			// **** inverted
			else
				set_bit(ICD_DATA_PIN_PORT,ICD_DATA_PIN);			// **** inverted
			data = data >> 1;
			if (wait_clock(1<<ICD_CLK_PIN, 1))				//Wait for clock to go high
				return 254;
			if (wait_clock(0, 1))						//Wait for clock to go low
				return 253;
		}

		set_bit(ICD_DATA_PIN_TRIS,ICD_DATA_PIN);					//Data line as input end of byte
		if (wait_data(0))							//Wait for byte acknowledge
				return 252;
		if (wait_clock(1<<ICD_CLK_PIN, 1))					//Wait for byte acknowledge end
				return 251;
		return 0;									//Success!
	}



	//ICD receive byte Function - Collects a bit banged serial data byte.
	char icd_byte_rx(void)
	{
		unsigned char data = 0;
		unsigned char count;

		set_bit(ICD_DATA_PIN_TRIS,ICD_DATA_PIN);			//Data line as input
		set_bit(ICD_CLK_PIN_TRIS,ICD_CLK_PIN);				//Clock line as input
		for(count=0; count<8; count++)				//Receive Byte
		{
			data = data >> 1;
			if (wait_clock(0, 1))						//Wait for clock to go low
				return 0;

			if (test_bit(ICD_DATA_PIN_PORT,ICD_DATA_PIN) == 0) 		//Read incoming data on data pin	**** inverted
				data = data | 0x80;

			if (wait_clock(1<<ICD_CLK_PIN, 1))				//Wait for clock to go high
				return 0;
		}

		if (wait_data(1<<ICD_DATA_PIN))					//Wait for data to go high
			return 0;

		if (wait_clock(0, 1))							//Wait for clock to go low
			return 0;

		clear_bit(ICD_DATA_PIN_TRIS, ICD_DATA_PIN);				//ICD data is an output
		set_bit(ICD_DATA_PIN_PORT, ICD_DATA_PIN);				//ICD data 0 send Ack		**** inverted

		if (wait_clock(1<<ICD_CLK_PIN, 1))					//Wait for clock to go high
			return 0;

		set_bit(ICD_DATA_PIN_TRIS, ICD_DATA_PIN);				//ICD data clear ack
		return(data);
	}


	char wait_clock(char state, char timeout_inc)
	{
		unsigned int timeout = 0;

		while ((test_bit(ICD_CLK_PIN_PORT,ICD_CLK_PIN) != state) && (timeout < ICD_TIMEOUT))	//Wait for clk
			timeout = timeout +  timeout_inc;		//Increment time out

		if (timeout == ICD_TIMEOUT)					//Has the routine timed out
			return 1;
		return 0;
	}


	char wait_data(char state)
	{
		unsigned int timeout = 0;
		while ((test_bit(ICD_DATA_PIN_PORT, ICD_DATA_PIN) == state) && (timeout < ICD_TIMEOUT))	//Wait for data		**** inverted
			timeout = timeout +  1;					//Increment time out

		if (timeout == ICD_TIMEOUT)					//Has the routine timed out
			return 1;
		return 0;
	}


	char read_register(unsigned int address)
	{
		char RetVal;

		volatile char* register_ptr = (char*)address;

		RetVal = *register_ptr;

		return RetVal;
	}


	void write_register(unsigned int address, char data)
	{
		volatile char* register_ptr = (char*)address;

		*register_ptr = data;
	}


	void rst_dev()
	{
		//Disable all interrupts
		intcon = 0;
		#ifdef PIE1 | pie1
			pie1 = 0x00;
		#endif
		#ifdef PIE2 | pie2
			pie2 = 0x00;
		#endif

		//Reset all port pins back to inputs
		#ifdef PORTA | porta
			trisa = 0xff;
			porta = 0x00;
		#endif
		#ifdef GPIO | gpio
			gpio = 0x00;
			#ifdef TRISGPIO | trisgpio
				trisgpio = 0xff;
			#endif
			#ifdef TRISIO | trisio
				trisio = 0xff;
			#endif
			#ifdef TRIS | tris
				tris = 0xff;
			#endif
		#endif
		#ifdef PORTB | portb
			trisb = 0xff;
			portb = 0x00;
		#endif
		#ifdef PORTC | portc
			trisc = 0xff;
			portc = 0x00;
		#endif
		#ifdef PORTD | portd
			trisd = 0xff;
			portd = 0x00;
		#endif
		#ifdef PORTE | porte
			trise = 0xff;
			porte = 0x00;
		#endif
		#ifdef PORTF | portf
			trisf = 0xff;
			portf = 0x00;
		#endif

		//Software Reset
		#ifdef _BOOSTC
			reset();			//Supported in BoostC
		#endif
		#ifdef HI_TECH_C
			intcon=0;			//Disable Interrupts
			option_reg=8;		//Enable watchdog timer with 1:1 prescale
			while(1) ;   		//Wait forever for watchdog reset
		#endif
	}

//End of ICD functionality
#endif


void Wdt_Delay_S(char delay)
{
    char i;
    short j;
    for (i=0; i<delay; i++)
    {
        for (j=0; j<999; j++)
        {
            Wdt_Delay_Ms(1);
        }
    }
}


void Wdt_Delay_Ms(char delay)
{
    char i;
    for (i=0; i<delay; i++)
    {
        MX_CLEAR_WATCHDOG;        //Clear Watchdog Timer
        delay_ms(1);
    }
}


char FCI_FLOAT_TO_STRING(float Number, char Precision, char* String, char MSZ_String)
{
	long whole;
	char str_length;
	char idx;
	char stringidx = 0;
	float real, temp;
	char old;
	char temp_string[12];

	#ifdef _BOOSTC									//BoostC Floating Point

		float_rounding_mode = 3;					//Always round to zero
		whole = float32_to_int32(Number);			//Convert to whole integer
		temp = float32_from_int32(whole);			//Convert whole number back to floating point

		if (float32_ge(Number,0))
		{
			real = float32_sub(Number, temp);		//Subtract whole number from floating point number
		}
		else
		{
			if (whole == 0)							//Fix -0 bug
			{
				String[stringidx] = '-';
				stringidx = stringidx + 1;
			}

			real = float32_sub(temp, Number);		//Subtract floating point number from whole number
		}
	#endif

	#ifdef HI_TECH_C								//HiTECH Floating Point

		whole = (int)Number;						//Convert to whole integer
		temp = whole;								//Convert whole number back to floating point

		if (Number >= 0)
		{
			real = Number - temp;					//Subtract whole number from floating point number
		}
		else
		{
			if (whole == 0)							//Fix -0 bug
			{
				String[stringidx] = '-';
				stringidx = stringidx + 1;
			}

			real = temp - Number;					//Subtract floating point number from whole number
		}
	#endif

	str_length = FCI_LONG_TOSTRING(whole, temp_string, 7);		//Convert integer numbers to strings

	for (idx=0; idx<str_length; idx++)						//Copy whole part of number to string
	{
		if(stringidx < MSZ_String)
		{
			String[stringidx] = temp_string[idx];
			stringidx = stringidx + 1;
		}
	}

	if(stringidx < MSZ_String)						//Add decimal point to string
	{
		String[stringidx] = '.';
		stringidx = stringidx + 1;
	}

	for (idx = 0; idx < Precision; idx++)			//Output Real Part Of Number
	{
		if (stringidx >= MSZ_String)
			break;

		#ifdef _BOOSTC								//BoostC Floating Point
			real = float32_mul(real, 10);
			whole = float32_to_int32(real);			//Convert to whole integer
			temp = float32_from_int32(whole);		//Convert whole number back to floating point
			real = float32_sub(real, temp);			//Subtract whole number from floating point number
		#endif
		#ifdef HI_TECH_C							//HiTECH Floating Point
			real = real * 10;
			whole = (int)real;						//Convert to whole integer
			temp = whole;							//Convert whole number back to floating point
			real = real - temp;						//Subtract whole number from floating point number
		#endif

		String[stringidx] = '0' + whole;
		stringidx = stringidx + 1;
	}

	if(stringidx < MSZ_String)									//Add null termination to string
	{
		String[stringidx] = 0;
	}

	return stringidx;
}


char FCI_NUMBER_TO_HEX(short Number, char* String, char MSZ_String)
{
	char stringidx;
	char idx = 0;
	char temp;
	char digit[4] = {0,0,0,0};
	unsigned int num;

	//Check that output string is long enough to store result
	if(Number < 256 && MSZ_String < 4)
		return 0;

	if(Number > 255 && MSZ_String < 6)
		return 0;

	//Initialise start of string with hexadecimal indicator
	String[0] = '0';
	String[1] = 'x';

	//Number is positive
	if(Number < 0)
	{
		num = 0 - Number;
		num = 0xFFFF - (num - 1);
	}
	else
		num = Number;

	//Calculate hex values
	while (num > 0)
	{
		temp = num % 16;
		num = num / 16;

		if(temp > 9)
		{
			temp = temp - 10;
			digit[idx] = temp + 'A';
		}
		else
			digit[idx] = temp + '0';

		idx = idx + 1;
	}

	//Copy Hex values over to output string
	for (stringidx = 2; stringidx < (idx + 2); stringidx++)
		String[stringidx] = digit[idx - (stringidx - 1)];

	//Add null termination to string
	if(stringidx < MSZ_String)
	{
		String[stringidx] = 0;
	}

	return stringidx;
}


long FCI_STRING_TO_INT(char* String, char MSZ_String)
{
	char bNegative = 0;
	char idx = 0;
	long RetVal = 0;

	//Is number negative
	if(String[0] == '-')
	{
		bNegative = 1;
		idx = 1;
	}

	//While string contains a valid number
	while (idx < MSZ_String && String[idx] >= '0' && String[idx] <= '9')
	{
		//Pull character from string and add to running total
		RetVal = (long) RetVal * 10;
		RetVal = (long) RetVal + (String[idx] - '0');
		idx = idx + 1;
	}

	if (bNegative)
		RetVal = (long) 0 - RetVal;

	return RetVal;
}


float FCI_STRING_TO_FLOAT(char* String, char MSZ_String)
{
	float RetVal = 0;
	float real_divider = 1;
	unsigned long whole, real;			//Changed from INT 23/07/10
	char idx = 0;
	char idx2 = 0;
	char offset = 0;
	char bNegative = 0;
	char Comp_String[8];

	//Is number negative
	if(String[0] == '-')
	{
		bNegative = 1;
		offset = 1;
	}

	//Scan for decimal point
	for(idx=offset; idx<MSZ_String; idx++)
	{
		if(String[idx] == '.')
			break;
	}

	//Convert whole portion of number from string
	whole = FCI_STRING_TO_INT (String, idx);

	//No decimal point found
	if(idx == MSZ_String)
	{
		#ifdef _BOOSTC
			RetVal = float32_from_int32(whole);
		#endif
		#ifdef HI_TECH_C
			RetVal = (int)whole;
		#endif
		return RetVal;
	}

	//Collect real portion of number into new string
	offset = idx + 1;
	for(idx=offset; idx<MSZ_String; idx++)
	{
		if(String[idx] >= '0' && String[idx] <= '9')
		{
			Comp_String[idx - offset] = String[idx];
			#ifdef _BOOSTC
				real_divider = float32_mul(real_divider, 0.1);
			#endif
			#ifdef HI_TECH_C
				real_divider = real_divider * 0.1;
			#endif
		}
		else
			break;
	}

	//Convert real portion of number from string
	real = FCI_STRING_TO_INT (Comp_String, (idx - offset));

	//Adjust weighting of values and combine into one float variable
	#ifdef _BOOSTC

		RetVal = float32_from_int32(real);
		RetVal = float32_mul(RetVal, real_divider);
		real_divider = float32_from_int32(whole);
		RetVal = float32_add(RetVal, real_divider);

		if (bNegative)
			RetVal = float32_sub(0, RetVal);

	#endif
	#ifdef HI_TECH_C

		RetVal = (float)real;
		RetVal = RetVal * real_divider;
		real_divider = (float)whole;
		RetVal = RetVal + real_divider;

		if (bNegative)
			RetVal = 0 - RetVal;
	#endif

	return RetVal;
}


char isinf(float f)
{
      char* b;
      b = (char*)&f;
      if ((b[0] == 0)   &&
          (b[1] == 0)   &&
          (b[2] == 128) &&
          ((b[3] & 127) == 127))
      {
            return (255);
      }
      return (0);
}

#endif



#ifdef MX_MIAC_SYSTEM		//Automatic CAN implementation

	char MIAC_CAN_TX[6];
	char MIAC_CAN_RX[6];


	union Float4Bytes
	{
		float FloatVal;
		char ByteArray[4];
	};
	union Float4Bytes FloatConv;


	void SPI_Init(void);
	char SPI_SendByte(char);
	char CAN_MaskFromBit(char);
	void CAN_Reset(void);
	void CAN_Write(char, char);
	char CAN_Read(char);
	void CAN_Config(char);
	char CAN_ReadStatus(void);
	char CAN_ReadRXStatus(void);
	void CAN_BitModify(char, char, char);
	char CAN_ReadRX_ID_and_Data(char);
	void CAN_Init(void);
	void CAN_SendBuffer(char);
	char CAN_CheckRx(char);
	char CAN_GetRxDataCount(char);
	char CAN_GetRxData(char, char);
	void CAN_SetTxData(char, char, char, char, char, char, char, char, char, char);
	void CAN_SetTxID(char, unsigned short);
	char CAN_GetRxIDLo(char);
	char CAN_GetRxIDHi(char);
	void CAN_CancelTx(char);
	void CAN_SetFilter (unsigned short);
	void MIAC_Module_WR(unsigned short, unsigned short, char, char, char);
	char MIAC_Module_RD(unsigned short, unsigned short);
	char MIAC_Module_GetAck(unsigned short, unsigned short, char);
	void MIAC_Master_RelayON(char);
	void MIAC_Master_RelayOFF(char);
	void MIAC_Master_OutputON(char);
	void MIAC_Master_OutputOFF(char);
	char MIAC_Master_InputDIGITAL(char);
	char MIAC_Master_InputANA(char);
	short MIAC_Master_InputANA10(char);


	#define MX_CAN_PORT 		portb
	#define MX_CAN_TRIS 		trisb
	#define MX_CAN_SDO_TRIS 	trisc
	#define MX_CAN_CS_PORT 		portd
	#define MX_CAN_CS_TRIS 		trisd
	#define MX_CAN_INT_PORT 	porta
	#define MX_CAN_INT_TRIS 	trisa
	#define CAN_CHIPSEL  		7
	#define CAN_INTERRUPT  		4
	#define CAN_INT_MASK  		16


	//common defines
	#define CNF1_VAL  		0x01
	#define CNF2_VAL  		0xd1
	#define CNF3_VAL  		0x03
	#define BFPCTRL_VAL    	0x00
	#define TXRTSCTRL_VAL	0x00

	#define CAN_MAX_TX_BUF	(3)
	#define CAN_MAX_RX_BUF	(2)

	//One shot mode, CLKOUT enable, CLKOUT prescaler
	#define CANCTRL_VAL		0x80
	#define MX_CANSTAT_VAL	0x80

	//Extended ID Dummy Values
	#define TXB0EID8_VAL	0x00
	#define TXB0EID0_VAL	0x00
	#define TXB1EID8_VAL	0x00
	#define TXB1EID0_VAL	0x00
	#define TXB2EID8_VAL	0x00
	#define TXB2EID0_VAL	0x00
	#define RXF0EID8_VAL	0x00
	#define RXF0EID0_VAL	0x00
	#define RXF1EID8_VAL	0x00
	#define RXF1EID0_VAL	0x00
	#define RXF2EID8_VAL	0x00
	#define RXF2EID0_VAL	0x00
	#define RXF3EID8_VAL	0x00
	#define RXF3EID0_VAL	0x00
	#define RXF4EID8_VAL	0x00
	#define RXF4EID0_VAL	0x00
	#define RXF5EID8_VAL	0x00
	#define RXF5EID0_VAL	0x00
	#define RXM0EID8_VAL	0xFF
	#define RXM0EID0_VAL	0xFF
	#define RXM1EID8_VAL	0xFF
	#define RXM1EID0_VAL	0xFF

	//CANCTRL
	#define REQOP_CONFIG		0x80
	#define REQOP_LISTEN		0x60
	#define REQOP_LOOPBACK		0x40
	#define REQOP_SLEEP			0x20
	#define REQOP_NORMAL		0x00


	//Transmission message (TXB0):
	#define TXB0CTRL_VAL   3		//Priority (highest)
	#define TXB0SIDH_VAL   0
	#define TXB0SIDL_VAL   0
	#define TXB0DLC_VAL    0
	#define TXB0DB0_VAL    0
	#define TXB0DB1_VAL    0
	#define TXB0DB2_VAL    0
	#define TXB0DB3_VAL    0
	#define TXB0DB4_VAL    0
	#define TXB0DB5_VAL    0
	#define TXB0DB6_VAL    0
	#define TXB0DB7_VAL    0

	//Transmission message (TXB1):
	#define TXB1CTRL_VAL   2		//Priority
	#define TXB1SIDH_VAL   0
	#define TXB1SIDL_VAL   0
	#define TXB1DLC_VAL    0
	#define TXB1DB0_VAL    0
	#define TXB1DB1_VAL    0
	#define TXB1DB2_VAL    0
	#define TXB1DB3_VAL    0
	#define TXB1DB4_VAL    0
	#define TXB1DB5_VAL    0
	#define TXB1DB6_VAL    0
	#define TXB1DB7_VAL    0

	//Transmission message (TXB2):
	#define TXB2CTRL_VAL   1		//Priority (lowest)
	#define TXB2SIDH_VAL   0
	#define TXB2SIDL_VAL   0
	#define TXB2DLC_VAL    0
	#define TXB2DB0_VAL    0
	#define TXB2DB1_VAL    0
	#define TXB2DB2_VAL    0
	#define TXB2DB3_VAL    0
	#define TXB2DB4_VAL    0
	#define TXB2DB5_VAL    0
	#define TXB2DB6_VAL    0
	#define TXB2DB7_VAL    0

	//Reception (RXB0)
	#define RXB0CTRL_VAL   0x60
	#define RXF0SIDH_VAL   0
	#define RXF0SIDL_VAL   0
	#define RXF1SIDH_VAL   0
	#define RXF1SIDL_VAL   0
	#define RXM0SIDH_VAL   255
	#define RXM0SIDL_VAL   224		//Every bit is active

	//Reception (RXB1)
	#define RXB1CTRL_VAL   0x20
	#define RXF2SIDH_VAL   0
	#define RXF2SIDL_VAL   0
	#define RXF3SIDH_VAL   0
	#define RXF3SIDL_VAL   0
	#define RXF4SIDH_VAL   0
	#define RXF4SIDL_VAL   0
	#define RXF5SIDH_VAL   0
	#define RXF5SIDL_VAL   0
	#define RXM1SIDH_VAL   255
	#define RXM1SIDL_VAL   128


	//This is the interrupt enable register (set to flag on message received - RX0 and RX1 - and on an error)
	//#define CANINTE_VAL		0x23
	//TODO: should we turn interrupts off, like this:
	//#define CANINTE_VAL		0x00
	//TODO: of just turn on RX interrupts, like this:
	#define CANINTE_VAL		0x03


	// **********************************************************************
	// *              MCP2510 Register Definitions                          *
	// **********************************************************************

	//Configuration Registers
	#define MX_CANSTAT			0x0E
	#define CANCTRL				0x0F
	#define BFPCTRL				0x0C
	#define TEC					0x1C
	#define REC					0x1D
	#define CNF3				0x28
	#define CNF2				0x29
	#define CNF1				0x2A
	#define CANINTE				0x2B
	#define CANINTF				0x2C
	#define EFLG				0x2D
	#define TXRTSCTRL			0x0D

	//Receive Filters
	//NOTE: Use "a" for i={0,1,2} and "b" for i={3,4,5}
	#define RXFxaSIDH(i)			((i*4)+0)
	#define RXFxaSIDL(i)			((i*4)+1)
	#define RXFxaEID8(i)			((i*4)+2)
	#define RXFxaEID0(i)			((i*4)+3)
	#define RXFxbSIDH(i)			((i*4)+4)
	#define RXFxbSIDL(i)			((i*4)+5)
	#define RXFxbEID8(i)			((i*4)+6)
	#define RXFxbEID0(i)			((i*4)+7)

	//Receive Masks
	#define RXMxSIDH(i)			((i*4)+0x20)
	#define RXMxSIDL(i)			((i*4)+0x21)
	#define RXMxEID8(i)			((i*4)+0x22)
	#define RXMxEID0(i)			((i*4)+0x23)

	//Tx Buffers
	#define TXBxCTRL(i)			((i*0x10)+0x30)
	#define TXBxSIDH(i)			((i*0x10)+0x31)
	#define TXBxSIDL(i)			((i*0x10)+0x32)
	#define TXBxEID8(i)			((i*0x10)+0x33)
	#define TXBxEID0(i)			((i*0x10)+0x34)
	#define TXBxDLC(i)			((i*0x10)+0x35)
	#define TXBxD0(i)			((i*0x10)+0x36)
	#define TXBxDy(i,j)			((i*0x10)+0x36+j)

	//Rx Buffers
	#define RXBxCTRL(i)			((i*0x10)+0x60)
	#define RXBxSIDH(i)			((i*0x10)+0x61)
	#define RXBxSIDL(i)			((i*0x10)+0x62)
	#define RXBxEID8(i)			((i*0x10)+0x63)
	#define RXBxEID0(i)			((i*0x10)+0x64)
	#define RXBxDLC(i)			((i*0x10)+0x65)
	#define RXBxD0(i)			((i*0x10)+0x66)
	#define RXBxDy(i,j)			((i*0x10)+0x66+j)


	// *******************************************************************
	// *               Bit register masks                                *
	// *******************************************************************

	//TXBnCTRL
	#define MX_TXREQ			0x08
	#define TXP					0x03

	//RXBnCTRL
	#define RXM					0x60
	#define BUKT				0x04

	//CANCTRL
	#define REQOP				0xE0
	#define MX_ABAT				0x10
	#define CLKEN				0x04
	#define CLKPRE				0x03
	#define OSM					0x08             // (ST) new for the 2515

	//MX_CANSTAT
	#define REQOP				0xE0
	#define ICOD				0x0E

	//CANINTE
	#define RX0IE				0x01
	#define RX1IE				0x02
	#define TX0IE				0x04
	#define TX1IE				0x80
	#define TX2IE				0x10
	#define MX_ERRIE			0x20
	#define MX_WAKIE			0x40
	#define IVMIE				0x80

	//CANINTF
	#define RX0IF				0x01
	#define RX1IF				0x02
	#define TX0IF				0x04
	#define TX1IF				0x80
	#define TX2IF				0x10
	#define MX_ERRIF			0x20
	#define MX_WAKIF			0x40
	#define IVMIF				0x80

	//BFPCTRL
	#define B1BFS				0x20
	#define B0BFS				0x10
	#define B1BFE				0x08
	#define B0BFE				0x04
	#define B1BFM				0x02
	#define B0BFM				0x01

	//CNF1 Masks
	#define SJW					0xC0
	#define BRP					0x3F

	//CNF2 Masks
	#define BTLMODE				0x80
	#define MX_SAM				0x40
	#define PHSEG1				0x38
	#define PRSEG				0x07

	//CNF3 Masks
	#define MX_WAKFIL			0x40
	#define PHSEG2				0x07
	#define SOF					0x80             // (ST) new for the 2515

	//TXRTSCTRL Masks
	#define TXB2RTS				0x04
	#define TXB1RTS				0x02
	#define TXB0RTS				0x01


	// *******************************************************************
	// *                    Bit Timing Configuration                     *
	// *******************************************************************

	//CNF1
	#define SJW_1TQ				0x40
	#define SJW_2TQ				0x80
	#define SJW_3TQ				0x90
	#define SJW_4TQ				0xC0

	//CNF2
	#define BTLMODE_CNF3		0x80
	#define BTLMODE_PH1_IPT		0x00

	#define SMPL_3X				0x40
	#define SMPL_1X				0x00

	#define PHSEG1_8TQ			0x38
	#define PHSEG1_7TQ			0x30
	#define PHSEG1_6TQ			0x28
	#define PHSEG1_5TQ			0x20
	#define PHSEG1_4TQ			0x18
	#define PHSEG1_3TQ			0x10
	#define PHSEG1_2TQ			0x08
	#define PHSEG1_1TQ			0x00

	#define PRSEG_8TQ			0x07
	#define PRSEG_7TQ			0x06
	#define PRSEG_6TQ			0x05
	#define PRSEG_5TQ			0x04
	#define PRSEG_4TQ			0x03
	#define PRSEG_3TQ			0x02
	#define PRSEG_2TQ			0x01
	#define PRSEG_1TQ			0x00

	//CNF3
	#define PHSEG2_8TQ			0x07
	#define PHSEG2_7TQ			0x06
	#define PHSEG2_6TQ			0x05
	#define PHSEG2_5TQ			0x04
	#define PHSEG2_4TQ			0x03
	#define PHSEG2_3TQ			0x02
	#define PHSEG2_2TQ			0x01
	#define PHSEG2_1TQ			0x00

	#define MX_WAKFIL_ENABLED	0x40
	#define MX_WAKFIL_DISABLED	0x00


	// *******************************************************************
	// *                  Control/Configuration Registers                *
	// *******************************************************************

	//CANINTE
	#define RX0IE_ENABLED		0x01
	#define RX0IE_DISABLED		0x00
	#define RX1IE_ENABLED		0x02
	#define RX1IE_DISABLED		0x00
	#define G_RXIE_ENABLED		0x03
	#define G_RXIE_DISABLED		0x00

	#define TX0IE_ENABLED		0x04
	#define TX0IE_DISABLED		0x00
	#define TX1IE_ENABLED		0x08
	#define TX2IE_DISABLED		0x00
	#define TX2IE_ENABLED		0x10
	#define TX2IE_DISABLED		0x00
	#define G_TXIE_ENABLED		0x1C
	#define G_TXIE_DISABLED		0x00

	#define MX_ERRIE_ENABLED	0x20
	#define MX_ERRIE_DISABLED	0x00
	#define MX_WAKIE_ENABLED	0x40
	#define MX_WAKIE_DISABLED	0x00
	#define IVRE_ENABLED		0x80
	#define IVRE_DISABLED		0x00

	//CANINTF
	#define RX0IF_SET			0x01
	#define RX0IF_RESET			0x00
	#define RX1IF_SET			0x02
	#define RX1IF_RESET			0x00
	#define TX0IF_SET			0x04
	#define TX0IF_RESET			0x00
	#define TX1IF_SET			0x08
	#define TX2IF_RESET			0x00
	#define TX2IF_SET			0x10
	#define TX2IF_RESET			0x00
	#define MX_ERRIF_SET		0x20
	#define MX_ERRIF_RESET		0x00
	#define MX_WAKIF_SET		0x40
	#define MX_WAKIF_RESET		0x00
	#define IVRF_SET			0x80
	#define IVRF_RESET			0x00


	#define ABORT				0x10

	#define CLKOUT_ENABLED		0x04
	#define CLKOUT_DISABLED		0x00
	#define CLKOUT_PRE_8		0x03
	#define CLKOUT_PRE_4		0x02
	#define CLKOUT_PRE_2		0x01
	#define CLKOUT_PRE_1		0x00

	//MX_CANSTAT
	#define OPMODE_CONFIG		0x80
	#define OPMODE_LISTEN		0x60
	#define OPMODE_LOOPBACK		0x40
	#define OPMODE_SLEEP		0x20
	#define OPMODE_NORMAL		0x00


	//RXBnCTRL
	#define RXM_RCV_ALL			0x60
	#define RXM_VALID_EXT		0x40
	#define RXM_VALID_STD		0x20
	#define RXM_VALID_ALL		0x00

	#define RXRTR_REMOTE		0x08
	#define RXRTR_NO_REMOTE		0x00

	#define BUKT_ROLLOVER		0x04
	#define BUKT_NO_ROLLOVER	0x00

	#define FILHIT0_FLTR_1		0x01
	#define FILHIT0_FLTR_0		0x00

	#define FILHIT1_FLTR_5		0x05
	#define FILHIT1_FLTR_4		0x04
	#define FILHIT1_FLTR_3		0x03
	#define FILHIT1_FLTR_2		0x02
	#define FILHIT1_FLTR_1		0x01
	#define FILHIT1_FLTR_0		0x00


	//TXBnCTRL
	#define MX_TXREQ_SEND		0x08
	#define MX_TXREQ_ABORT		0x00

	#define TXP_HIGHEST			0x03
	#define TXP_INTER_HIGH		0x02
	#define TXP_INTER_LOW		0x01
	#define TXP_LOWEST			0x00


	// *******************************************************************
	// *                  Register Bit Masks                             *
	// *******************************************************************

	#define DLC_0				0x00
	#define DLC_1				0x01
	#define DLC_2				0x02
	#define DLC_3				0x03
	#define DLC_4				0x04
	#define DLC_5				0x05
	#define DLC_6				0x06
	#define DLC_7				0x07
	#define DLC_8				0x08


	// *******************************************************************
	// *                  CAN SPI commands                               *
	// *******************************************************************

	#define CAN_RESET			0xC0
	#define CAN_READ			0x03
	#define CAN_WRITE			0x02
	#define CAN_RD_STATUS		0xA0
	#define CAN_BIT_MODIFY		0x05

	#define CAN_RTS				0x80
	#define CAN_RTS_TXB0		0x81
	#define CAN_RTS_TXB1		0x82
	//#define CAN_RTS_TXB2		0x83          // (ST) I think this is wrong..so I changed it to this:
	#define CAN_RTS_TXB2		0x84
	//#define CAN_RTS_TXB(i)		(0x80 + (0x01 << i))
	//NOTE: the above line does not work because the RHS of a shift cannot be a variable

	// (ST) I also added these for multiple requests...
	#define CAN_RTS_TXB01		0x83
	#define CAN_RTS_TXB02		0x85
	#define CAN_RTS_TXB12		0x86
	#define CAN_RTS_TXB012		0x87

	#define CAN_RX_STATUS		0xB0

	#define CAN_RD_RXBUF_ID(i)	(0x90 + (i*4))
	#define CAN_RD_RXBUF_DT(i)	(0x92 + (i*4))

	#define CAN_LD_TXBUF_ID(i)	(0x40 + (i*2))
	#define CAN_LD_TXBUF_DT(i)	(0x41 + (i*2))



	char CAN_MSG_DLC;
	char CAN_MSG_DATA[8];
	char MsgFlags = 0;

	#ifdef CAN_USE_EXID
	  char CAN_MSG_ID[4];
	#else
	  char CAN_MSG_ID[2];
	#endif

	char BF_MASK;


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

	//internal function implementations
	void SPI_Init()
	{
		//initialise spi
		set_bit(MX_CAN_TRIS,MX_SPI_SDI);
		clear_bit(MX_CAN_SDO_TRIS,MX_SPI_SDO);
		clear_bit(MX_CAN_TRIS,MX_SPI_SCK);
		clear_bit(MX_CAN_CS_TRIS,CAN_CHIPSEL);
		set_bit(MX_CAN_INT_TRIS,CAN_INTERRUPT);

		//disable the CAN chip select line
		set_bit(MX_CAN_CS_PORT, CAN_CHIPSEL);

		sspstat = 0;
		st_bit(sspstat, CKE);			//SMP = 0, CKE = 1

		#ifdef _BOOSTC
			#ifdef SSPCON							// SPI Low Speed for Initialise
				sspcon = 0;
				st_bit(sspcon, SSPEN);
			#endif
			#ifdef SSPCON1
				sspcon1 = 0;
				st_bit(sspcon1, SSPEN);
			#endif
		#endif

		#ifdef HI_TECH_C
			#ifdef sspcon							// SPI Low Speed for Initialise
				sspcon = 0;
				st_bit(sspcon, SSPEN);
			#endif
			#ifdef sspcon1
				sspcon1 = 0;
				st_bit(sspcon1, SSPEN);
			#endif
		#endif

		//get the mask for the BF bit for later use
		BF_MASK = CAN_MaskFromBit(BF);
	}


	char SPI_SendByte(char byte)
	{
		char retval = 0;

		//send the byte
		sspbuf = byte;

		//wait until data has been received (transmit complete)
		while ((sspstat & BF_MASK) == 0);

		//get received byte
		retval = sspbuf;

		return retval;
	}


	char CAN_MaskFromBit(char which_bit)
	{
		char retVal = 0;
		switch (which_bit)
		{
			case 0:
				retVal = 0x01;
				break;

			case 1:
				retVal = 0x02;
				break;

			case 2:
				retVal = 0x04;
				break;

			case 3:
				retVal = 0x08;
				break;

			case 4:
				retVal = 0x10;
				break;

			case 5:
				retVal = 0x20;
				break;

			case 6:
				retVal = 0x40;
				break;

			case 7:
				retVal = 0x80;
				break;
		}
		return (retVal);
	}


	void CAN_Reset()
	{
		//enable SPI
		clear_bit(MX_CAN_CS_PORT, CAN_CHIPSEL);

		SPI_SendByte(CAN_RESET);

		//disable SPI
		set_bit(MX_CAN_CS_PORT, CAN_CHIPSEL);

		//wait for the CAN device to complete its OST
		delay_us(20);
	}


	void CAN_Write(char addr, char data)
	{
		//enable SPI
		clear_bit(MX_CAN_CS_PORT, CAN_CHIPSEL);

		SPI_SendByte(CAN_WRITE);			//send a byte
		SPI_SendByte(addr);					//send the address
		SPI_SendByte(data);					//send the data

		//disable SPI
		set_bit(MX_CAN_CS_PORT, CAN_CHIPSEL);
	}


	char CAN_Read(char addr)
	{
		char data;

		//enable SPI
		clear_bit(MX_CAN_CS_PORT, CAN_CHIPSEL);

		SPI_SendByte(CAN_READ);				//read a byte
		SPI_SendByte(addr);					//send the address
		data = SPI_SendByte(0x5A);			//send a don't care byte

		//disable SPI
		set_bit(MX_CAN_CS_PORT, CAN_CHIPSEL);

		return (data);
	}


	void CAN_Config(char cfg)
	{
		char mode;
		char done = 0;

		while (done == 0)
		{
			CAN_Write(CANCTRL, cfg);

			Wdt_Delay_Ms(1);				//not sure if this is needed

			//read the config mode back
			mode = CAN_Read(MX_CANSTAT);

			//mask off the config bits
			mode = mode & 0xE0;

			if (mode == cfg)
			{
				//it has been set correctly
				done = 1;
			}
		}

		Wdt_Delay_Ms(1);				//not sure if this is needed
	}


	char CAN_ReadStatus()
	{
		char retval = 0;

		//enable SPI
		clear_bit(MX_CAN_CS_PORT, CAN_CHIPSEL);

		SPI_SendByte(CAN_RD_STATUS);		//read the status
		retval = SPI_SendByte(0x5A);		//send a don't care byte

		//disable SPI
		set_bit(MX_CAN_CS_PORT, CAN_CHIPSEL);

		return (retval);
	}


	char CAN_ReadRXStatus()
	{
		char retval = 0;

		//enable SPI
		clear_bit(MX_CAN_CS_PORT, CAN_CHIPSEL);

		SPI_SendByte(CAN_RX_STATUS);		//read the status
		retval = SPI_SendByte(0x5A);		//send a don't care byte

		//disable SPI
		set_bit(MX_CAN_CS_PORT, CAN_CHIPSEL);

		return (retval);
	}


	void CAN_BitModify(char addr, char mask, char data)
	{
		//enable SPI
		clear_bit(MX_CAN_CS_PORT, CAN_CHIPSEL);

		SPI_SendByte(CAN_BIT_MODIFY);		//bit modify
		SPI_SendByte(addr);					//send the address
		SPI_SendByte(mask);					//send the mask
		SPI_SendByte(data);					//send the data

		//disable SPI
		set_bit(MX_CAN_CS_PORT, CAN_CHIPSEL);
	}


	char CAN_ReadRX_ID_and_Data(char buffer)
	{
		//populates CAN_MSG_ID[], CAN_MSG_DLC, and CAN_MSG_DATA[], and returns CAN_MSG_DLC
		char idx = 0;

		if (buffer > CAN_MAX_RX_BUF)
		{
			return (0);
		}

		//enable SPI
		clear_bit(MX_CAN_CS_PORT, CAN_CHIPSEL);

		SPI_SendByte(CAN_RD_RXBUF_ID(buffer));		//read the RX ID

		CAN_MSG_ID[idx++] = SPI_SendByte(0x5A);		//read back SIDH

		CAN_MSG_ID[idx++] = SPI_SendByte(0x5A);		//read back SIDL

		sspbuf = 0x5A;						//send a don't care byte
		while ((sspstat & BF_MASK) == 0);	//wait until data has been received (transmit complete)
	  #ifdef CAN_USE_EXID
		CAN_MSG_ID[idx++] = sspbuf;			//read back EXID8
	  #endif

		sspbuf = 0x5A;						//send a don't care byte
		while ((sspstat & BF_MASK) == 0);	//wait until data has been received (transmit complete)
	  #ifdef CAN_USE_EXID
		CAN_MSG_ID[idx++] = sspbuf;			//read back EXID0
	  #endif

		CAN_MSG_DLC = SPI_SendByte(0x5A);			//read back DLC

		//now read the data (if there is any)
		if (CAN_MSG_DLC > 0)
		{
			CAN_MSG_DATA[0] = SPI_SendByte(0x5A);		//read back D0

			if (CAN_MSG_DLC > 1)
			{
				CAN_MSG_DATA[1] = SPI_SendByte(0x5A);			//read back D1

				if (CAN_MSG_DLC > 2)
				{
					CAN_MSG_DATA[2] = SPI_SendByte(0x5A);			//read back D2

					if (CAN_MSG_DLC > 3)
					{
						CAN_MSG_DATA[3] = SPI_SendByte(0x5A);			//read back D3

						if (CAN_MSG_DLC > 4)
						{
							CAN_MSG_DATA[4] = SPI_SendByte(0x5A);			//read back D4

							if (CAN_MSG_DLC > 5)
							{
								CAN_MSG_DATA[5] = SPI_SendByte(0x5A);			//read back D5

								if (CAN_MSG_DLC > 6)
								{
									CAN_MSG_DATA[6] = SPI_SendByte(0x5A);			//read back D6

									if (CAN_MSG_DLC > 7)
									{
										CAN_MSG_DATA[7] = SPI_SendByte(0x5A);			//read back D7
									}
								}
							}
						}
					}
				}
			}
		}

		//disable SPI
		set_bit(MX_CAN_CS_PORT, CAN_CHIPSEL);

		return (CAN_MSG_DLC);
	}


	void CAN_Init()
	{
		//Init SPI
		SPI_Init();

		//brief pause here
		Wdt_Delay_Ms(50);

		//Reset the CAN device
		CAN_Reset();

		//Put the CAN device into config mode
		CAN_Config(REQOP_CONFIG);

		//Initialise all the CAN device registers
		//enable SPI
		clear_bit(MX_CAN_CS_PORT, CAN_CHIPSEL);

		SPI_SendByte(CAN_WRITE);        //CAN write mode
		SPI_SendByte(0x00);             //start writting at address 0x00

		SPI_SendByte(RXF0SIDH_VAL);     // RXF0SIDH  0x00
		SPI_SendByte(RXF0SIDL_VAL);     // RXF0SIDL  0x01
		SPI_SendByte(RXF0EID8_VAL);     // RXF0EID8  0x02
		SPI_SendByte(RXF0EID0_VAL);     // RXF0EID0  0x03
		SPI_SendByte(RXF1SIDH_VAL);     // RXF1SIDH  0x04
		SPI_SendByte(RXF1SIDL_VAL);     // RXF1SIDL  0x05
		SPI_SendByte(RXF1EID8_VAL);     // RXF1EID8  0x06
		SPI_SendByte(RXF1EID0_VAL);     // RXF1EID0  0x07
		SPI_SendByte(RXF2SIDH_VAL);     // RXF2SIDH  0x08
		SPI_SendByte(RXF2SIDL_VAL);     // RXF2SIDL  0x09
		SPI_SendByte(RXF2EID8_VAL);     // RXF2EID8  0x0A
		SPI_SendByte(RXF2EID0_VAL);     // RXF2EID0  0x0B
		SPI_SendByte(BFPCTRL_VAL);      // BFPCTRL   0x0C
		SPI_SendByte(TXRTSCTRL_VAL);    // TXRTSCTRL 0x0D
		SPI_SendByte(MX_CANSTAT_VAL);   // MX_CANSTAT   0x0E
		SPI_SendByte(CANCTRL_VAL);      // CANCTRL   0x0F

		SPI_SendByte(RXF3SIDH_VAL);     // RXF3SIDH  0x10
		SPI_SendByte(RXF3SIDL_VAL);     // RXF3SIDL  0x11
		SPI_SendByte(RXF3EID8_VAL);     // RXF3EID8  0x12
		SPI_SendByte(RXF3EID0_VAL);     // RXF3EID0  0x13
		SPI_SendByte(RXF4SIDH_VAL);     // RXF4SIDH  0x14
		SPI_SendByte(RXF4SIDL_VAL);     // RXF4SIDL  0x15
		SPI_SendByte(RXF4EID8_VAL);     // RXF4EID8  0x16
		SPI_SendByte(RXF4EID0_VAL);     // RXF4EID0  0x17
		SPI_SendByte(RXF5SIDH_VAL);     // RXF5SIDH  0x18
		SPI_SendByte(RXF5SIDL_VAL);     // RXF5SIDL  0x19
		SPI_SendByte(RXF5EID8_VAL);     // RXF5EID8  0x1A
		SPI_SendByte(RXF5EID0_VAL);     // RXF5EID0  0x1B
		SPI_SendByte(0x00);             // TEC       0x1C
		SPI_SendByte(0x00);             // REC       0x1D
		SPI_SendByte(MX_CANSTAT_VAL);   // MX_CANSTAT   0x1E
		SPI_SendByte(CANCTRL_VAL);      // CANCTRL   0x1F

		SPI_SendByte(RXM0SIDH_VAL);     // RXM0SIDH  0x20
		SPI_SendByte(RXM0SIDL_VAL);     // RXM0SIDL  0x21
		SPI_SendByte(RXM0EID8_VAL);     // RXM0EID8  0x22
		SPI_SendByte(RXM0EID0_VAL);     // RXM0EID0  0x23
		SPI_SendByte(RXM1SIDH_VAL);     // RXM1SIDH  0x20
		SPI_SendByte(RXM1SIDL_VAL);     // RXM1SIDL  0x21
		SPI_SendByte(RXM1EID8_VAL);     // RXM1EID8  0x26
		SPI_SendByte(RXM1EID0_VAL);     // RXM1EID0  0x27
		SPI_SendByte(CNF3_VAL);         // CNF3      0x28
		SPI_SendByte(CNF2_VAL);         // CNF2      0x29
		SPI_SendByte(CNF1_VAL);         // CNF1      0x2A
		SPI_SendByte(CANINTE_VAL);      // CANINTE   0x2B
		SPI_SendByte(0x00);             // CANINTF   0x2C
		SPI_SendByte(0x00);             // EFLG      0x2D
		SPI_SendByte(MX_CANSTAT_VAL);   // MX_CANSTAT   0x2E
		SPI_SendByte(CANCTRL_VAL);      // CANCTRL   0x2F

		SPI_SendByte(TXB0CTRL_VAL);     // TXB0CTRL  0x30
		SPI_SendByte(TXB0SIDH_VAL);     // TXB0SIDH  0x31
		SPI_SendByte(TXB0SIDL_VAL);     // TXB0SIDL  0x32
		SPI_SendByte(TXB0EID8_VAL);     // TXB0EID8  0x33
		SPI_SendByte(TXB0EID0_VAL);     // TXB0EID0  0x34
		SPI_SendByte(TXB0DLC_VAL);      // TXB0DLC   0x35
		SPI_SendByte(TXB0DB0_VAL);      // TXB0DB0   0x36
		SPI_SendByte(TXB0DB1_VAL);      // TXB0DB1   0x37
		SPI_SendByte(TXB0DB2_VAL);      // TXB0DB2   0x38
		SPI_SendByte(TXB0DB3_VAL);      // TXB0DB3   0x39
		SPI_SendByte(TXB0DB4_VAL);      // TXB0DB4   0x3A
		SPI_SendByte(TXB0DB5_VAL);      // TXB0DB5   0x3B
		SPI_SendByte(TXB0DB6_VAL);      // TXB0DB6   0x3C
		SPI_SendByte(TXB0DB7_VAL);      // TXB0DB7   0x3D
		SPI_SendByte(MX_CANSTAT_VAL);   // MX_CANSTAT   0x3E
		SPI_SendByte(CANCTRL_VAL);      // CANCTRL   0x3F

		SPI_SendByte(TXB1CTRL_VAL);     // TXB1CTRL  0x40 Highest priority
		SPI_SendByte(TXB1SIDH_VAL);     // TXB1SIDH  0x41
		SPI_SendByte(TXB1SIDL_VAL);     // TXB1SIDL  0x42
		SPI_SendByte(TXB1EID8_VAL);     // TXB1EID8  0x43
		SPI_SendByte(TXB1EID0_VAL);     // TXB1EID0  0x44
		SPI_SendByte(TXB1DLC_VAL);      // TXB1DLC   0x45
		SPI_SendByte(TXB1DB0_VAL);      // TXB1DB0   0x46
		SPI_SendByte(TXB1DB1_VAL);      // TXB1DB1   0x47
		SPI_SendByte(TXB1DB2_VAL);      // TXB1DB2   0x48
		SPI_SendByte(TXB1DB3_VAL);      // TXB1DB3   0x49
		SPI_SendByte(TXB1DB4_VAL);      // TXB1DB4   0x4A
		SPI_SendByte(TXB1DB5_VAL);      // TXB1DB5   0x4B
		SPI_SendByte(TXB1DB6_VAL);      // TXB1DB6   0x4C
		SPI_SendByte(TXB1DB7_VAL);      // TXB1DB7   0x4D
		SPI_SendByte(MX_CANSTAT_VAL);   // MX_CANSTAT   0x4E
		SPI_SendByte(CANCTRL_VAL);      // CANCTRL   0x4F

		SPI_SendByte(TXB2CTRL_VAL);     // TXB2CTRL  0x50
		SPI_SendByte(TXB2SIDH_VAL);     // TXB2SIDH  0x51
		SPI_SendByte(TXB2SIDL_VAL);     // TXB2SIDL  0x52
		SPI_SendByte(TXB2EID8_VAL);     // TXB2EID8  0x53
		SPI_SendByte(TXB2EID0_VAL);     // TXB2EID0  0x54
		SPI_SendByte(TXB2DLC_VAL);      // TXB2DLC   0x55
		SPI_SendByte(TXB2DB0_VAL);      // TXB2DB0   0x56
		SPI_SendByte(TXB2DB1_VAL);      // TXB2DB1   0x57
		SPI_SendByte(TXB2DB2_VAL);      // TXB2DB2   0x58
		SPI_SendByte(TXB2DB3_VAL);      // TXB2DB3   0x59
		SPI_SendByte(TXB2DB4_VAL);      // TXB2DB4   0x5A
		SPI_SendByte(TXB2DB5_VAL);      // TXB2DB5   0x5B
		SPI_SendByte(TXB2DB6_VAL);      // TXB2DB6   0x5C
		SPI_SendByte(TXB2DB7_VAL);      // TXB2DB7   0x5D
		SPI_SendByte(MX_CANSTAT_VAL);   // MX_CANSTAT   0x5E
		SPI_SendByte(CANCTRL_VAL);      // CANCTRL   0x5F

		SPI_SendByte(RXB0CTRL_VAL);     // RXB0CTRL  0x60
		SPI_SendByte(0x00);             // RXB0SIDH  0x61
		SPI_SendByte(0x00);             // RXB0SIDL  0x62
		SPI_SendByte(0x00);             // RXB0EID8  0x63
		SPI_SendByte(0x00);             // RXB0EID0  0x64
		SPI_SendByte(0x00);             // RXB0DLC   0x65
		SPI_SendByte(0x00);             // RXB0DB0   0x66
		SPI_SendByte(0x00);             // RXB0DB1   0x67
		SPI_SendByte(0x00);             // RXB0DB2   0x68
		SPI_SendByte(0x00);             // RXB0DB3   0x69
		SPI_SendByte(0x00);             // RXB0DB4   0x6A
		SPI_SendByte(0x00);             // RXB0DB5   0x6B
		SPI_SendByte(0x00);             // RXB0DB6   0x6C
		SPI_SendByte(0x00);             // RXB0DB7   0x6D
		SPI_SendByte(MX_CANSTAT_VAL);   // MX_CANSTAT   0x6E
		SPI_SendByte(CANCTRL_VAL);      // CANCTRL   0x6F

		SPI_SendByte(RXB1CTRL_VAL);     // RXB1CTRL  0x70
		SPI_SendByte(0x00);             // RXB1SIDH  0x71
		SPI_SendByte(0x00);             // RXB1SIDL  0x72
		SPI_SendByte(0x00);             // RXB1EID8  0x73
		SPI_SendByte(0x00);             // RXB1EID0  0x74
		SPI_SendByte(0x00);             // RXB1DLC   0x75
		SPI_SendByte(0x00);             // RXB1DB0   0x76
		SPI_SendByte(0x00);             // RXB1DB1   0x77
		SPI_SendByte(0x00);             // RXB1DB2   0x78
		SPI_SendByte(0x00);             // RXB1DB3   0x79
		SPI_SendByte(0x00);             // RXB1DB4   0x7A
		SPI_SendByte(0x00);             // RXB1DB5   0x7B
		SPI_SendByte(0x00);             // RXB1DB6   0x7C
		SPI_SendByte(0x00);             // RXB1DB7   0x7D
		SPI_SendByte(MX_CANSTAT_VAL);   // MX_CANSTAT   0x7E
		SPI_SendByte(CANCTRL_VAL);      // CANCTRL   0x7F

		//disable SPI
		set_bit(MX_CAN_CS_PORT, CAN_CHIPSEL);

		//Put the CAN device into normal mode
		CAN_Config(REQOP_NORMAL);
	}


	void CAN_SendBuffer(char buffer)
	{
		if (buffer > CAN_MAX_TX_BUF)
		{
		   return;
		}

		char cmd = CAN_RTS;         //default value

		switch (buffer)
		{
		   case 0:
			   cmd = CAN_RTS_TXB0;
			   break;

		   case 1:
			   cmd = CAN_RTS_TXB1;
			   break;

		   case 2:
			   cmd = CAN_RTS_TXB2;
			   break;
		}
		//NOTE: this following didn't work:
		//cmd = CAN_RTS_TXB(buffer);

		//enable SPI
		clear_bit(MX_CAN_CS_PORT, CAN_CHIPSEL);

		SPI_SendByte(cmd);

		//disable SPI
		set_bit(MX_CAN_CS_PORT, CAN_CHIPSEL);
	}


	char CAN_CheckRx(char buffer)
	{
		//returns 1 if the buffer is full, 0 otherwise
		char rx_status;
		char status_mask;
		char retval = 0;

		if (buffer > CAN_MAX_RX_BUF)
		{
		   return (0);
		}


		if (buffer == 1)
		{
		   //status_mask = 0x02;       //if using CAN_ReadStatus
		   status_mask = 0x80;         //if using CAN_ReadRXStatus
		} else {
		   //status_mask = 0x01;       //if using CAN_ReadStatus
		   status_mask = 0x40;         //if using CAN_ReadRXStatus
		}

		//rx_status = CAN_ReadStatus();    //if using CAN_ReadStatus
		rx_status = CAN_ReadRXStatus();    //if using CAN_ReadRXStatus

		if ((rx_status & status_mask) != 0)
		{
		   retval = 1;

		   //now read in the id and data info
		   CAN_ReadRX_ID_and_Data(buffer);
		}

		return (retval);
	}


	char CAN_GetRxDataCount(char buffer)
	{
		return (CAN_MSG_DLC);
	}


	char CAN_GetRxData(char buffer, char index)
	{
		if (index > 7)
		{
		   return (0);
		}
		return (CAN_MSG_DATA[index]);
	}


	void CAN_SetTxData(char buffer, char data_cnt, char d0, char d1, char d2, char d3, char d4, char d5, char d6, char d7)
	{
		// Code_CAN_SetTxData
		if (buffer > CAN_MAX_TX_BUF)
		{
		   return;
		}

		if (data_cnt > 8)
		{
		   return;
		}

		char i;
		char dlc_addr = TXBxDLC(buffer);

		//enable SPI
		clear_bit(MX_CAN_CS_PORT, CAN_CHIPSEL);

		SPI_SendByte(CAN_WRITE);        //CAN write mode
		SPI_SendByte(dlc_addr);         //start writting at address 0x00
		SPI_SendByte(data_cnt);         //send the DLC value

		//now fill the data bytes...
		if (data_cnt > 0)
		{
		   SPI_SendByte(d0);
		   if (data_cnt > 1)
		   {
			   SPI_SendByte(d1);
			   if (data_cnt > 2)
			   {
				   SPI_SendByte(d2);
				   if (data_cnt > 3)
				   {
					   SPI_SendByte(d3);
					   if (data_cnt > 4)
					   {
						   SPI_SendByte(d4);
						   if (data_cnt > 5)
						   {
							   SPI_SendByte(d5);
							   if (data_cnt > 6)
							   {
								   SPI_SendByte(d6);
								   if (data_cnt > 7)
								   {
									   SPI_SendByte(d7);
								   }
							   }
						   }
					   }
				   }
			   }
		   }
		}

		//disable SPI
		set_bit(MX_CAN_CS_PORT, CAN_CHIPSEL);
	}


	void CAN_SetTxID(char buffer, unsigned short ID)
	{
		// Code_SetTxID
		if (buffer > CAN_MAX_TX_BUF)
		{
		   return;
		}

		char ID_L;
		char id_addr = TXBxSIDH(buffer);

		ID_L = ID;						//Store low byte of ID
		ID >>= 8;						//Shift ID high byte to low byte

		//enable SPI
		clear_bit(MX_CAN_CS_PORT, CAN_CHIPSEL);

		SPI_SendByte(CAN_WRITE);        //CAN write mode
		SPI_SendByte(id_addr);          //start writting at hi id address
		SPI_SendByte(ID);               //send the Hi ID value
		SPI_SendByte(ID_L);               //send the Lo ID value

		//disable SPI
		set_bit(MX_CAN_CS_PORT, CAN_CHIPSEL);
	}


	char CAN_GetRxIDLo(char buffer)
	{
		return (CAN_MSG_ID[1]);
	}


	char CAN_GetRxIDHi(char buffer)
	{
		return (CAN_MSG_ID[0]);
	}


	void CAN_CancelTx(char buffer)
	{
		if (buffer <= 2)
		{
			CAN_BitModify(TXBxCTRL(buffer), MX_TXREQ_SEND, 0x00);
		}
	}


	void CAN_SetFilter (unsigned short ID)
	{
		char ID_L;

		// Split ID into bytes
		ID_L = ID;
		ID = ID >> 8;

		//Put the CAN device into config mode
		CAN_Config(REQOP_CONFIG);

		//enable SPI
		clear_bit(MX_CAN_CS_PORT, CAN_CHIPSEL);

		SPI_SendByte(CAN_WRITE);       	//CAN write mode
		SPI_SendByte(0x00);				//start writting at address 0x00 (RXF0SIDH)

		SPI_SendByte(ID);     			// RXF0SIDH  0x00
		SPI_SendByte(ID_L);				// RXF0SIDL  0x01

		//disable SPI
		set_bit(MX_CAN_CS_PORT, CAN_CHIPSEL);

		//Put the CAN device into normal mode
		CAN_Config(REQOP_NORMAL);
	}


	void MIAC_Module_WR(unsigned short CAN_ID, unsigned short CMD_ID, char Count, char Start, char More)
	{
		char Cmd_L;

		Cmd_L = CMD_ID;
		CMD_ID >>= 8;
		CMD_ID &= 0x07;

		if (Start) CMD_ID |= 0x08;
		if (More) CMD_ID |= 0x10;

		if (Count > 6)
			Count = 8;
		else
			Count += 2;

		CAN_SetTxID(0, CAN_ID);
		CAN_SetTxData(0,Count,CMD_ID,Cmd_L,MIAC_CAN_TX[0],MIAC_CAN_TX[1],MIAC_CAN_TX[2],MIAC_CAN_TX[3],MIAC_CAN_TX[4],MIAC_CAN_TX[5]);
		CAN_SendBuffer(0);
	}

	char MIAC_Module_RD(unsigned short CAN_ID, unsigned short CMD_ID)
	{
		unsigned short Rx_ID;
		char MsgRx, MsgFlags;
		char DataCount;
		char Idx;
		char RetVal = 0xe0;

		if(CAN_CheckRx(0))		//Message received?
		{
			Rx_ID = (CAN_GetRxIDHi(0) << 8) | CAN_GetRxIDLo(0);		//Get CAN ID

			if(Rx_ID == CAN_ID)		//Expected CAN ID?
			{
				DataCount = CAN_GetRxDataCount(0);

				if(DataCount > 1)		//Minimum of 2 data bytes?
				{
					MsgFlags = CAN_GetRxData(0,0);		//Read msb of message ID

					Rx_ID = ((MsgFlags & 0x07) << 8) | CAN_GetRxData(0,1);		//Make message ID

					MsgFlags = MsgFlags & 0x18;		//Mask out message flags

					if(Rx_ID == CMD_ID)		//Expected message ID?
					{
						for(Idx = 2; Idx < DataCount; Idx++)		//Read data
						{
							MIAC_CAN_RX[Idx - 2] = CAN_GetRxData(0,Idx);
						}
						RetVal = (DataCount - 2) | MsgFlags;
					}else{
						RetVal = 0x80;		//Unexpected message ID
					}
				}else{
					RetVal = 0xa0;		//Insufficient data
				}
			}else{
				RetVal = 0xc0;		//Unexpected CAN ID
			}
		}
		return(RetVal);		//Return 0xe0 if no message received
	}

	char MIAC_Module_GetAck(unsigned short CAN_ID, unsigned short CMD_ID, char TimeOut)
	{
		char LoopCount = 0;
		char MsgAck;

//		CAN_SetFilter(CAN_ID);

		do
		{
			MsgAck = MIAC_Module_RD(CAN_ID, CMD_ID);

			if(MsgAck == 0xe0)
				delay_10us(10);
			LoopCount = LoopCount + 1;

			if(TimeOut == 255)		//Wait indefinitely
				LoopCount = 0;
		}
		while(((MsgAck & 0xe0) == 0xe0) && (LoopCount < TimeOut));

		return(MsgAck);
	}


// Duplicate MIAC I/O functions. Used by MIAC System when LED, Switch, and ADC components are used with the MIAC Master

	void MIAC_Master_RelayON(char RelayID)
	{
		if(RelayID && (RelayID < 5))
		{
			clear_bit(trisb, RelayID + 3);
			set_bit(portb, RelayID + 3);
		}
	}

	void MIAC_Master_RelayOFF(char RelayID)
	{
		if(RelayID && (RelayID < 5))
		{
			clear_bit(trisb, RelayID + 3);
			clear_bit(portb, RelayID + 3);
		}
	}

	void MIAC_Master_OutputON(char TransID)
	{
		if(TransID && (TransID < 5))
		{
			switch(TransID)
			{
				case(1):	trisc &= ~0x04;
							portc |= 0x04;
							break;
				case(2):	trisc &= ~0x01;
							portc |= 0x01;
							break;
				case(3):	trisc &= ~0x02;
							portc |= 0x02;
							break;
				case(4):	trisc &= ~0x40;
							portc |= 0x40;
							break;
			}
		}
	}


	void MIAC_Master_OutputOFF(char TransID)
	{
		if(TransID && (TransID < 5))
		{
			switch(TransID)
			{
				case(1):	trisc &= ~0x04;
							portc &= ~0x04;
							break;
				case(2):	trisc &= ~0x01;
							portc &= ~0x01;
							break;
				case(3):	trisc &= ~0x02;
							portc &= ~0x02;
							break;
				case(4):	trisc &= ~0x40;
							portc &= ~0x40;
							break;
			}
		}
	}

	char MIAC_Master_InputDIGITAL(char InputID)
	{
		char RetVal = 255;

		if(InputID && (InputID < 9))
		{
			switch(InputID)
			{
				case(1):	trisa |= 0x01;
							RetVal = ((porta & 0x01) == 0x01);
							break;
				case(2):	trisa |= 0x02;
							RetVal = ((porta & 0x02) == 0x02);
							break;
				case(3):	trisa |= 0x04;
							RetVal = ((porta & 0x04) == 0x04);
							break;
				case(4):	trisa |= 0x08;
							RetVal = ((porta & 0x08) == 0x08);
							break;
				case(5):	trise |= 0x01;
							RetVal = ((porte & 0x01) == 0x01);
							break;
				case(6):	trise |= 0x02;
							RetVal = ((porte & 0x02) == 0x02);
							break;
				case(7):	trise |= 0x04;
							RetVal = ((porte & 0x04) == 0x04);
							break;
				case(8):	trisb |= 0x04;
							RetVal = ((portb & 0x04) == 0x04);
							break;
			}
		}
		return(RetVal);
	}

	char MIAC_Master_InputANA(char InputID)
	{
		#define MIAC_MASTER_ADC_SAMP_TIME 40

		//set up ADC conversion
		char old_tris, cnt, tris_mask, chan_id;

		if(InputID && (InputID < 9))
		{
			chan_id = InputID;
			if (InputID >= 5) chan_id++;

			adcon2 = 0x03;
			adcon1 = 15 - chan_id;

			//store old tris value, and set the i/o pin as an input
			switch (InputID)
			{
				case(1):	old_tris = trisa;
							trisa |= 0x01;
							break;
				case(2):	old_tris = trisa;
							trisa |= 0x02;
							break;
				case(3):	old_tris = trisa;
							trisa |= 0x04;
							break;
				case(4):	old_tris = trisa;
							trisa |= 0x08;
							break;
				case(5):	old_tris = trise;
							trise |= 0x01;
							break;
				case(6):	old_tris = trise;
							trise |= 0x02;
							break;
				case(7):	old_tris = trise;
							trise |= 0x04;
							break;
				case(8):	old_tris = trisb;
							trisb |= 0x04;
							break;
			}

			//turn ADC on
			adcon0 = 0x01 | ((chan_id - 1) << 2);

			//wait the acquisition time
			cnt = 0;
			while (cnt < MIAC_MASTER_ADC_SAMP_TIME) cnt++;

			//begin conversion and wait until it has finished
			adcon0 = adcon0 | 0x02;
			while (adcon0 & 0x02);

			//restore old tris value, and reset adc registers
			if(InputID == 8)
			{
				trisb = old_tris;
			}
			else
			{
				if(InputID < 5)
				{
					trisa = old_tris;
				}
				else
				{
					trise = old_tris;
				}
			}
			adcon1 = 0x0f;
			adcon0 = 0x00;
		}

		return(adresh);
	}

	short MIAC_Master_InputANA10(char InputID)
	{
		short result;

		result = MIAC_Master_InputANA(InputID);
		result = result << 2;
		result = result | (adresl >> 6);

		return(result);
	}

#endif
