/*
 * Copyright (C) 2019      Kai Ludwig, DG4KLU
 * Copyright (C) 2019-2023 Roger Clark, VK3KYY / G4KYF
 *
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
 *    in the documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * 4. Use of this source code or binary releases for commercial purposes is strictly forbidden. This includes, without limitation,
 *    incorporation in a commercial product or incorporation into a product or project which allows commercial use.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include "interfaces/adc.h"
#include "functions/settings.h"
#include "interfaces/batteryAndPowerManagement.h"
#include "functions/ticks.h"


const int TEMPERATURE_DECIMAL_RESOLUTION = 1000000;
const int CUTOFF_VOLTAGE_UPPER_HYST = 100;
const int CUTOFF_VOLTAGE_LOWER_HYST = 80;
const int BATTERY_MAX_VOLTAGE = 150;

//lookup table to convert linear Voltage values between 1 and 255 to dBs relative to 1 with a resolution of 0.2dB.  Values in tabble are dbs * 5 to use all of the available byte range.
//calculated using dBs= (20 * Log10(index)) * 5
const uint8_t PointTwodBs[] =
{
		0,   0,   30,  48,  60,  70,  78,  85,  90,  95,  100, 104, 108, 111, 115, 118,
		120, 123, 126, 128, 130, 132, 134, 136, 138, 140, 141, 143, 145, 146, 148, 149,
		151, 152, 153, 154, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167,
		168, 169, 170, 171, 172, 172, 173, 174, 175, 176, 176, 177, 178, 179, 179, 180,
		181, 181, 182, 183, 183, 184, 185, 185, 186, 186, 187, 188, 188, 189, 189, 190,
		190, 191, 191, 192, 192, 193, 193, 194, 194, 195, 195, 196, 196, 197, 197, 198,
		198, 199, 199, 200, 200, 200, 201, 201, 202, 202, 203, 203, 203, 204, 204, 205,
		205, 205, 206, 206, 206, 207, 207, 208, 208, 208, 209, 209, 209, 210, 210, 210,
		211, 211, 211, 212, 212, 212, 213, 213, 213, 214, 214, 214, 215, 215, 215, 216,
		216, 216, 216, 217, 217, 217, 218, 218, 218, 218, 219, 219, 219, 220, 220, 220,
		220, 221, 221, 221, 221, 222, 222, 222, 223, 223, 223, 223, 224, 224, 224, 224,
		225, 225, 225, 225, 226, 226, 226, 226, 226, 227, 227, 227, 227, 228, 228, 228,
		228, 229, 229, 229, 229, 229, 230, 230, 230, 230, 231, 231, 231, 231, 231, 232,
		232, 232, 232, 232, 233, 233, 233, 233, 233, 234, 234, 234, 234, 234, 235, 235,
		235, 235, 235, 236, 236, 236, 236, 236, 237, 237, 237, 237, 237, 237, 238, 238,
		238, 238, 238, 239, 239, 239, 239, 239, 239, 240, 240, 240, 240, 240, 240, 241
};


volatile uint16_t adcVal[NUM_ADC_CHANNELS][NUM_ADC_SAMPLES];
volatile uint8_t adcIndex = 0;
volatile uint8_t adcSampleIndex = 0;
static volatile uint32_t micAvg = 0;

static const int AVERAGE_BATTERY_VOLTAGE_SAMPLE_WINDOW = 60.0f;// 120 secs = Sample window * BATTERY_VOLTAGE_TICK_RELOAD in milliseconds
static const int BATTERY_VOLTAGE_STABILISATION_TIME = 1500;// time in PIT ticks for the battery voltage from the ADC to stabilise

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
	if (hadc->Instance == ADC1)
	{
		adcVal[adcIndex][adcSampleIndex] = HAL_ADC_GetValue(&hadc1);

		if (adcIndex == 3) // mic
		{
			volatile int mAvg = 0;

			for (uint32_t i = 0; i < (NUM_ADC_SAMPLES - 1); i++)
			{
				mAvg += adcVal[3][i];
			}

			micAvg = (mAvg >> 3); // NUM_ADC_SAMPLES == 8
		}

		adcIndex++;
		if (adcIndex > (NUM_ADC_CHANNELS - 1))
		{
			batteryVoltage = ((int)adcVal[2][adcSampleIndex] / 21.3f) + ((nonVolatileSettings.batteryCalibration & 0x0F) - 5);
			if (ticksGetMillis() < BATTERY_VOLTAGE_STABILISATION_TIME)
			{
				averageBatteryVoltage = batteryVoltage;
			}
			else
			{
				averageBatteryVoltage = (averageBatteryVoltage * (AVERAGE_BATTERY_VOLTAGE_SAMPLE_WINDOW - 1) + batteryVoltage) / AVERAGE_BATTERY_VOLTAGE_SAMPLE_WINDOW;
			}

			adcIndex = 0;
			adcSampleIndex = (adcSampleIndex + 1) % NUM_ADC_SAMPLES;
		}

		HAL_ADC_Start_IT(&hadc1);
	}
}


int adcGetMicRow(void)
{
	return (int) adcVal[0][0];		//doesn't need averaging so just use one of the recent conversions
}

int adcGetMicCol(void)
{
	return (int) adcVal[1][0];		//doesn't need averaging so just use one of the recent conversions
}

int adcGetBatteryVoltage(void)
{
	return batteryVoltage;			//doesn't need averaging so just use the most recent conversion
}


int adcGetVOX(void)
{
	//	convert to 0.2dB steps relative to 1
	return (int)PointTwodBs[MIN(255, micAvg)];
}

int adcGetVHFRSSI(void)
{
	int avg = 0;

	for (int i = 0; i < (NUM_ADC_SAMPLES - 1); i++)
	{
		avg = avg + adcVal[4][i];
	}

	return (avg / NUM_ADC_SAMPLES) >> 4;                  //RSSI was 8 bits on at1846s
}

int adcGetUHFRSSI(void)
{
	int avg = 0;

	for (int i = 0; i< (NUM_ADC_SAMPLES - 1); i++)
	{
		avg = avg + adcVal[5][i];
	}

	return (avg / NUM_ADC_SAMPLES) >> 4;                   //RSSI was 8 bits on at1846s
}

int adcGetVHFNoise(void)
{
	int avg = 0;

	for (int i = 0; i < (NUM_ADC_SAMPLES - 1); i++)
	{
		avg = avg + adcVal[6][i];
	}

	return (avg / NUM_ADC_SAMPLES) >> 4;                   //Noise was 8 bits on at1846s. Bring the noise reading into roughly the same range.
}

int adcGetUHFNoise(void)
{
	int avg = 0;

	for (int i = 0; i < (NUM_ADC_SAMPLES - 1); i++)
	{
		avg = avg + adcVal[7][i];
	}

	return (avg / NUM_ADC_SAMPLES) >> 4;                   //Noise was 8 bits on at1846s. Bring the noise reading into roughly the same range.
}

int getTemperature(void)
{
	const int tV25 = 943;					// ADC Value at 25 degrees from data sheet (0.76V with 12 Bit ADC ref=3V3)
    const int tslope = 31;	                //Slope from datasheet ADC Counts *10

    return (((adcVal[8][0] - tV25) * 100) / tslope) + 250 + (nonVolatileSettings.temperatureCalibration * 5);

}






