/*
 * adc.c
 *
 *  Created on: Mar 3, 2012
 *      Author: qwer1
 */

#include "adc.h"
#include "config.h"

//ADC channels measuring order
const U8 adc_channels[] = {0,2,1,4,3,16};

//ADC samples
U16 adc_data[ADC_CHANNELS];

//number of samples in filter
#define ADC_FILT_SAMPLES  128
//number of bits in samples counter
#define ADC_FILT_BITS     7

//cold junction temperature (TC1047)
S16 t_cold = 200;
U8  t_cold_present = 0;

S16 t_int = 200;

//K-thermocouples temperature
S16 t_tc[T_TC_NUM];

void setup_adc(void) {
	GPIO_InitTypeDef GPIO_InitStructure;
	ADC_InitTypeDef  ADC_InitStructure;

	// initialize GPIO
	GPIO_StructInit(&GPIO_InitStructure);
	GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4;
	GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

	//configure ADC
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);

	ADC_StructInit(&ADC_InitStructure);
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
	ADC_InitStructure.ADC_NbrOfChannel = 1;
	ADC_Init(ADC1, &ADC_InitStructure);

	ADC_Cmd(ADC1, ENABLE);

	ADC_ResetCalibration(ADC1);
	while(ADC_GetResetCalibrationStatus(ADC1));

	ADC_StartCalibration(ADC1);
	while(ADC_GetCalibrationStatus(ADC1));

	//enable temperature sensor and reference
	ADC_TempSensorVrefintCmd( ENABLE );

	//ADC thread
	ptx_add( pt_adc, NULL, PTX_FLAG_RUN | PTX_FLAG_SYNC_1MS);
}



PT_THREAD( pt_adc( struct pt *pt, struct ptx *ptx ) ) {
	static U8 adc_channel;
	static U8 adc_filt_cnt;
	static U32 adc_sample_sum;

	PT_BEGIN(pt);
	while (1) {
		for (adc_channel=0; adc_channel<ADC_CHANNELS; adc_channel++) {
			ADC_RegularChannelConfig(ADC1, adc_channels[adc_channel], 1, ADC_SampleTime_41Cycles5);

			//reset ADC sum
			adc_sample_sum = 0;

			//accumulate ADC_FILT_SAMPLES samples
			for (adc_filt_cnt=0; adc_filt_cnt<ADC_FILT_SAMPLES; adc_filt_cnt++) {
				ADC_SoftwareStartConvCmd(ADC1, ENABLE);
				PT_WAIT_WHILE(pt, (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET));
				adc_sample_sum += ADC_GetConversionValue(ADC1);
				PTX_DELAY_MS(1);
			}

			//calculate next ADC sample
			U16 adc = adc_data[adc_channel] = (adc_data[adc_channel] + (adc_sample_sum >> ADC_FILT_BITS)) >> 1;

			if (adc_channel == T_TC_NUM) { //TC1047 channel
				//calculate ambient temperature (for cold-junction compensation)
				//if sensor not connected - assume t_cold = 20°C
				if (adc > 4000) {
					t_cold_present = 0;
				} else if (adc < 100) {
					t_cold = 200 + config.t_cold_corr;
				} else {
					t_cold = (t_cold + (((((S32)((adc * 3300UL) >> 12) - 500L) * 1250L) / (1750L - 500L)) + config.t_cold_corr)) / 2;
					t_cold_present = 1;
				}
			} else if (adc_channel == T_TC_NUM + 1) { //internal temperature sensor
				t_int = ((174968L - (adc * 100L)) / 53L) + 250 + config.t_cold_corr;
				if (!t_cold_present) t_cold = t_int;
			} else {
				//calculate thermocouple temperature
				U8 tc_num = adc_channel;
				//if sensor not connected - use error value
				if ((adc > 4000)/*||(adc < 30)*/) t_tc[tc_num] = -32768;
				else {
					if (t_tc[tc_num] == -32768)	t_tc[tc_num] = 0;
					t_tc[tc_num] = (t_tc[tc_num] + ((((S32)adc * 5120L) / 2652L) + t_cold + config.t_tc_corr[tc_num])) / 2;
					if (t_tc[tc_num] < 0) t_tc[tc_num] = 0;
				}
			}
		}
		PT_YIELD(pt);
	}
	PT_END(pt);
}
