/*********************************************************************
 *                 Flowcode ADC Type 28 Component Code
 *
 * File: PIC_ADC_28.c
 *
 * (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
 * -------+----+-----------------------------------------------------
 * 110607 | BR | Created
 * 050707 | ST | Fixes to code
 * 130309 | BR | Moved Functions from FCD files into Component code files
 * 170409 | BR | Added ReadAsString Function
 * 130509 | BR | Added % definitions to DefinesCode section
 * 160609 | BR | Removed NumBytes Parameter from String Function
 * 131109 | BR | Fixed the HITECH error outputs for an invalid setup
 * 260110 | BR | Fixed minor definitions bug between BoostC and HITECH
 * 220210 | BR | Added to allow 18FXXJ5X devices to function
 * 230311 | BR | Changed code to work for hitech and boostc without ifdefs
 * 260711 | BR | Fixed a bug that converted all of the port pins to analogue after a sample
 * 010811 | BR | Fixed a bug where the ADC was returning 0 due to an incorrect define
 ********************************************************************/

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

 Return & parameter types:
   void
   char
   short
   char*

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

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

[Settings]
CLSID={4FFA7653-1978-4FDA-8900-9DBF554C9255}
IsAnalogue=1
MultipleAllowed=1
Description=ADC Type 28 Flowcode Component

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

[MacroNames]
Count=5
1=SampleADC
2=ReadAsByte
3=ReadAsInt
4=ReadAsVoltage
5=ReadAsString

[MacroReturns]
1=void
2=char
3=short
4=float
5=char*

[MacroIsPrivate]
1=1
2=0
3=0
4=0
5=0

[MacroParameters_SampleADC]
Count=0

[MacroParamTypes_SampleADC]

[MacroParameters_ReadAsByte]
Count=0

[MacroParamTypes_ReadAsByte]

[MacroParameters_ReadAsInt]
Count=0

[MacroParamTypes_ReadAsInt]


[MacroParameters_ReadAsVoltage]
Count=0

[MacroParamTypes_ReadAsVoltage]


[MacroParameters_ReadAsString]
Count=0

[MacroParamTypes_ReadAsString]


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

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

/*DefinesCode_Start*/

/**** Macro Substitutions ****
%a = Which ADC Channel
%b = Acquisition time
%c = Conversion Speed
%d = VRef+ Option
%e = VRef Voltage x 0.01V
******************************/

/*DefinesCode_End*/

/*InitialisationCode_Start*/
/*InitialisationCode_End*/

/*InterruptCode_Start*/
/*InterruptCode_End*/

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

void SampleADC(void)
{
/*Macro_SampleADC_Start*/

/*******Supported Devices******************************************************************
// 18F65K22, 18F66K22, 18F67K22, 18F85K22, 18F86K22, 18F87K22,
******************************************************************************************/

	#define MX_ADC_CHANNEL		%a
	#define MX_ADC_SAMP_TIME 	%b
	#define MX_ADC_CONV_SP		%c
	#define MX_ADC_VREF_OPT		%d

	//set up ADC conversion
	char old_tris, cnt;
	adcon2 = (MX_ADC_CONV_SP & 0x07);

	//find appropriate bit
	#if (MX_ADC_CHANNEL == 0)
		#define MX_ADC_TRIS_REG  trisa
		#define MX_ADC_TRIS_MSK  0x01
		#define MX_ADC_ANSEL_REG ancon0
		#define MX_ADC_ANSEL_MSK 0x01
	#endif
	#if (MX_ADC_CHANNEL == 1)
		#define MX_ADC_TRIS_REG  trisa
		#define MX_ADC_TRIS_MSK  0x02
		#define MX_ADC_ANSEL_REG ancon0
		#define MX_ADC_ANSEL_MSK 0x02
	#endif
	#if (MX_ADC_CHANNEL == 2)
		#define MX_ADC_TRIS_REG  trisa
		#define MX_ADC_TRIS_MSK  0x04
		#define MX_ADC_ANSEL_REG ancon0
		#define MX_ADC_ANSEL_MSK 0x04
	#endif
	#if (MX_ADC_CHANNEL == 3)
		#define MX_ADC_TRIS_REG  trisa
		#define MX_ADC_TRIS_MSK  0x08
		#define MX_ADC_ANSEL_REG ancon0
		#define MX_ADC_ANSEL_MSK 0x08
		#if (MX_ADC_VREF_OPT != 0)
			#error "Target device is currently using AN3 for VREF+"
		#endif
	#endif
	#if (MX_ADC_CHANNEL == 4)
		#define MX_ADC_TRIS_REG  trisa
		#define MX_ADC_TRIS_MSK  0x20
		#define MX_ADC_ANSEL_REG ancon0
		#define MX_ADC_ANSEL_MSK 0x10
	#endif
	#if (MX_ADC_CHANNEL == 5)
		#define MX_ADC_TRIS_REG  trisf
		#define MX_ADC_TRIS_MSK  0x80
		#define MX_ADC_ANSEL_REG ancon0
		#define MX_ADC_ANSEL_MSK 0x20
	#endif
	#if (MX_ADC_CHANNEL == 6)
		#define MX_ADC_TRIS_REG  trisf
		#define MX_ADC_TRIS_MSK  0x02
		#define MX_ADC_ANSEL_REG ancon0
		#define MX_ADC_ANSEL_MSK 0x40
	#endif
	#if (MX_ADC_CHANNEL == 7)
		#define MX_ADC_TRIS_REG  trisf
		#define MX_ADC_TRIS_MSK  0x04
		#define MX_ADC_ANSEL_REG ancon0
		#define MX_ADC_ANSEL_MSK 0x80
	#endif
	#if (MX_ADC_CHANNEL == 8)
		#define MX_ADC_TRIS_REG  trisf
		#define MX_ADC_TRIS_MSK  0x08
		#define MX_ADC_ANSEL_REG ancon1
		#define MX_ADC_ANSEL_MSK 0x01
	#endif
	#if (MX_ADC_CHANNEL == 9)
		#define MX_ADC_TRIS_REG  trisf
		#define MX_ADC_TRIS_MSK  0x10
		#define MX_ADC_ANSEL_REG ancon1
		#define MX_ADC_ANSEL_MSK 0x02
	#endif
	#if (MX_ADC_CHANNEL == 10)
		#define MX_ADC_TRIS_REG  trisf
		#define MX_ADC_TRIS_MSK  0x20
		#define MX_ADC_ANSEL_REG ancon1
		#define MX_ADC_ANSEL_MSK 0x04
	#endif
	#if (MX_ADC_CHANNEL == 11)
		#define MX_ADC_TRIS_REG  trisf
		#define MX_ADC_TRIS_MSK  0x40
		#define MX_ADC_ANSEL_REG ancon1
		#define MX_ADC_ANSEL_MSK 0x08
	#endif
	#if (MX_ADC_CHANNEL == 12)
		#define MX_ADC_TRIS_REG  trish
		#define MX_ADC_TRIS_MSK  0x10
		#define MX_ADC_ANSEL_REG ancon1
		#define MX_ADC_ANSEL_MSK 0x10
	#endif
	#if (MX_ADC_CHANNEL == 13)
		#define MX_ADC_TRIS_REG  trish
		#define MX_ADC_TRIS_MSK  0x20
		#define MX_ADC_ANSEL_REG ancon1
		#define MX_ADC_ANSEL_MSK 0x20
	#endif
	#if (MX_ADC_CHANNEL == 14)
		#define MX_ADC_TRIS_REG  trish
		#define MX_ADC_TRIS_MSK  0x40
		#define MX_ADC_ANSEL_REG ancon1
		#define MX_ADC_ANSEL_MSK 0x40
	#endif
	#if (MX_ADC_CHANNEL == 15)
		#define MX_ADC_TRIS_REG  trish
		#define MX_ADC_TRIS_MSK  0x80
		#define MX_ADC_ANSEL_REG ancon1
		#define MX_ADC_ANSEL_MSK 0x80
	#endif
	#if (MX_ADC_CHANNEL == 16)
		#define MX_ADC_TRIS_REG  trisg
		#define MX_ADC_TRIS_MSK  0x10
		#define MX_ADC_ANSEL_REG ancon2
		#define MX_ADC_ANSEL_MSK 0x01
	#endif
	#if (MX_ADC_CHANNEL == 17)
		#define MX_ADC_TRIS_REG  trisg
		#define MX_ADC_TRIS_MSK  0x08
		#define MX_ADC_ANSEL_REG ancon2
		#define MX_ADC_ANSEL_MSK 0x02
	#endif
	#if (MX_ADC_CHANNEL == 18)
		#define MX_ADC_TRIS_REG  trisg
		#define MX_ADC_TRIS_MSK  0x04
		#define MX_ADC_ANSEL_REG ancon2
		#define MX_ADC_ANSEL_MSK 0x04
	#endif
	#if (MX_ADC_CHANNEL == 19)
		#define MX_ADC_TRIS_REG  trisg
		#define MX_ADC_TRIS_MSK  0x02
		#define MX_ADC_ANSEL_REG ancon2
		#define MX_ADC_ANSEL_MSK 0x08
	#endif
	#if (MX_ADC_CHANNEL == 20)
		#define MX_ADC_TRIS_REG  trish
		#define MX_ADC_TRIS_MSK  0x08
		#define MX_ADC_ANSEL_REG ancon2
		#define MX_ADC_ANSEL_MSK 0x10
	#endif
	#if (MX_ADC_CHANNEL == 21)
		#define MX_ADC_TRIS_REG  trish
		#define MX_ADC_TRIS_MSK  0x04
		#define MX_ADC_ANSEL_REG ancon2
		#define MX_ADC_ANSEL_MSK 0x20
	#endif
	#if (MX_ADC_CHANNEL == 22)
		#define MX_ADC_TRIS_REG  trish
		#define MX_ADC_TRIS_MSK  0x02
		#define MX_ADC_ANSEL_REG ancon2
		#define MX_ADC_ANSEL_MSK 0x40
	#endif
	#if (MX_ADC_CHANNEL == 23)
		#define MX_ADC_TRIS_REG  trish
		#define MX_ADC_TRIS_MSK  0x01
		#define MX_ADC_ANSEL_REG ancon2
		#define MX_ADC_ANSEL_MSK 0x80
	#endif

	//sanity check
	#ifndef MX_ADC_TRIS_REG
		#error "ADC Type 28 conversion code error - please contact technical support"
	#endif

	//store old tris value, and set the i/o pin as an analogue input
	old_tris = MX_ADC_TRIS_REG;
	MX_ADC_TRIS_REG = MX_ADC_TRIS_REG | MX_ADC_TRIS_MSK;
	MX_ADC_ANSEL_REG = MX_ADC_ANSEL_REG | MX_ADC_ANSEL_MSK;

	//turn ADC on
	adcon0 = 0x01 | (MX_ADC_CHANNEL << 2);

	//assign VREF functionality
	#if (MX_ADC_VREF_OPT != 0)
		st_bit(adcon1, VCFG0);
	#endif

	//wait the acquisition time
	cnt = 0;
	while (cnt < MX_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
	MX_ADC_TRIS_REG = old_tris;
	MX_ADC_ANSEL_REG = 0x00;
	adcon0 = 0x00;

	#undef MX_ADC_TRIS_REG
	#undef MX_ADC_TRIS_MSK
	#undef MX_ADC_ANSEL_REG
	#undef MX_ADC_ANSEL_MSK
	#undef MX_ADC_SAMP_TIME
	#undef MX_ADC_CHANNEL
	#undef MX_ADC_CONV_SP
	#undef MX_ADC_VREF_OPT

/*Macro_SampleADC_End*/
}




char ReadAsByte(void)
{
/*Macro_ReadAsByte_Start*/

	SampleADC();
	return adresh;

/*Macro_ReadAsByte_End*/
}



short ReadAsInt(void)
{
/*Macro_ReadAsInt_Start*/

	short iRetVal;

	SampleADC();

	iRetVal = (adresh << 4);
	iRetVal = iRetVal | (adresl >> 4);

	return (iRetVal);

/*Macro_ReadAsInt_End*/
}




float ReadAsVoltage()
{
/*Macro_ReadAsVoltage_Start*/


	int iSample;
	float fSample, fVoltage, fVperDiv;

	#define MX_ADC_VREF_V		%e

	iSample = ReadAsInt();											//Read as 10-bit Integer

	fVoltage = float32_from_int32(MX_ADC_VREF_V);					//Convert reference voltage count to floating point (0 - 500 x 10mV)
	fVoltage = float32_mul(fVoltage, 0.01);							//Convert reference voltage count to actual voltage (0 - 5)
	fVperDiv = float32_mul(fVoltage, 0.000976);						//Convert actual voltage to voltage per division (VRef / 1024)
	fSample = float32_from_int32(iSample);							//Convert to floating point variable
	fVoltage = float32_mul(fSample, fVperDiv);						//Calculate floating point voltage

	#undef MX_ADC_VREF_V
	return (fVoltage);

/*Macro_ReadAsVoltage_End*/
}



void ReadAsString(char* FCR_RETVAL, char FCR_RETVAL_SIZE)
{
/*Macro_ReadAsString_Start*/

	float fVoltage;

	fVoltage = ReadAsVoltage();
	FCI_FLOAT_TO_STRING(fVoltage, 2, FCR_RETVAL, FCR_RETVAL_SIZE);	//Convert to String

/*Macro_ReadAsString_End*/
}