/*
 * @file    mcp3208.c
 * @brief   MCP3208 external ADC chip implementation. Not really used right now.
 *
 * @date Aug 12, 2013
 * @author Andrey Belomutskiy, (c) 2012-2016
 */

#include "main.h"

#if EFI_MCP_3208 || defined(__DOXYGEN__)
#include "mcp3208.h"
#include "pin_repository.h"

McpAdcState *hack;

static int adcEventCounter = 0;
static int adcErrorCounter = 0;

static int getValue(McpAdcState *state, int channel) {
	return state->results[channel] & 4095;
}

int getMcp3208adc(int channel) {
	return getValue(hack, channel);
}

static int getNextChannel(void) {
	return adcEventCounter % 2;
}

static void spiCallback(SPIDriver *spip) {
	spiUnselectI(spip);
	adcEventCounter++;

	McpAdcState *state = hack;

	int withError = 0;

	if (state->rx_buff[0] != 255) {
		withError = 1;
		//fatal("ADC: first byte");
	}

	if ((state->rx_buff[1] & 0xE0) != 0xE0) {
		withError = 1;
		//fatal("ADC: second byte");
	}

	if (!withError) {
//		unsigned char upperByte = state->rx_buff[1] & 0b00001111;
		int result = (state->rx_buff[0] << 16) + (state->rx_buff[1] << 8) + state->rx_buff[2];
		state->results[state->requestedChannel] = result;
	} else {
		adcErrorCounter++;
	}

	requestAdcValueI(state, getNextChannel());
}

static const SPIConfig spicfg = { spiCallback,
/* HW dependent part.*/
MCP3208_CS_PORT,
MCP3208_CS_PIN,
//SPI_CR1_MSTR |
		SPI_CR1_BR_0 | SPI_CR1_BR_1 | SPI_CR1_BR_2
//		SPI_CR1_BR_1 | SPI_CR1_BR_2
		};

static void createRequest(McpAdcState *state, int channel) {
	efiAssertVoid(channel < 8, "Invalid ADC channel");

	state->requestedChannel = channel;

	state->tx_buff[0] = 0x06 + (channel >> 2);
	state->tx_buff[1] = (channel & 3) << 6;
}

void requestAdcValue(McpAdcState *state, int channel) {
	createRequest(state, channel);

	spiSelect(state->driver);
	spiStartExchange(state->driver, 3, state->tx_buff, state->rx_buff);
	// SPI unselect is in the callback
}

void requestAdcValueI(McpAdcState *state, int channel) {
	createRequest(state, channel);

	spiSelectI(state->driver);
	spiStartExchangeI(state->driver, 3, state->tx_buff, state->rx_buff);
	// SPI unselect is in the callback
}

void adc_in_out(McpAdcState *state) {

//	chThdSleepMilliseconds(10);

	int result = state->results[0];

//	int v = result;
	unsigned r = 0;
//
//	while (v >>= 1)
//		r++;
//
//	unsigned int f;
//	if (r < 12) {
//		f = -1;
//	} else {
//		f = result >> (r - 12);
//		f = f & 4095;
//	}

	int errRatio = 1000 * adcErrorCounter / adcEventCounter;

	print("c/e %7d/%7d/%4d  result %5d r=%d ", adcEventCounter, adcErrorCounter, errRatio, result, r);

	unsigned int f0 = getValue(state, 0);
	print("ch0=%d adj %d    ", f0, f0 * 5000 / 4096);
	unsigned int f1 = getValue(state, 1);
	print("ch1=%d adj %d\r\n", f1, f1 * 5000 / 4096);
}

void init_adc_mcp3208(McpAdcState *state, SPIDriver *driver) {

//	initSpiModules();

	state->driver = driver;
	state->tx_buff[2] = 0;

	hack = state;

	mySetPadMode("ext adc chip select", MCP3208_CS_PORT, MCP3208_CS_PIN, PAL_STM32_MODE_OUTPUT);


	spiStart(driver, &spicfg);
}

#endif /* EFI_MCP_3208 */
