/*
 * adc.c
 *
 * Created: 20.02.2019 20:46:32
 *  Author: jens
 */ 

#include <stddef.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include "adc.h"
#include "message.h"

static volatile uint8_t adc_ch = 0;
static Fifo *g_pFifo = NULL;
static Fifo g_conversionFifo;
static int conversionBusy = 0;

ISR(ADC_vect)
{
	conversionBusy = 0;
	int16_t value_low = (int16_t)ADCL;
	int16_t value_high = (int16_t)ADCH;
	ADCSRA |= (1<<ADIF);
	int16_t value = value_high << 8 | value_low;

	Msg_t msg = 
	{
		.code = AdcComplete,
		.m.adc.ch = adc_ch,
		.m.adc.data = value,
	};
	fifo_push(g_pFifo, &msg);
	if (!fifo_isEmpty(&g_conversionFifo))
	{
		uint8_t ch;
		fifo_pop(&g_conversionFifo, &ch);
		adc_start_conversion(ch);
	}
}

void adc_init(Fifo *pFifo)
{
	g_pFifo = pFifo;
	fifo_init(&g_conversionFifo, 16, sizeof(uint8_t), "ConvFifo");
	PRR &= ~(1 << PRADC);
	ADCSRA |= (1 << ADEN) | 7;
}

void adc_start_conversion(uint8_t ch)
{
	ADMUX = (ADMUX & 0xF0) | (ch & 0x0F) | (1 << REFS0);
	ADCSRA |= (1 << ADSC) | (1 << ADIE);
	adc_ch = ch & 0x0F;
	conversionBusy = 1;
}

void adc_enqueue_conversion(uint8_t ch)
{
	if (!conversionBusy)
	{
		adc_start_conversion(ch);
	}
	else
	{
		fifo_push(&g_conversionFifo, &ch);
	}
}
