/*
 * adc.c
 *
 *  Created on: 08.02.2019
 *      Author: julian
 */

#include "adc.h"
#include "main.h"

#include <avr/io.h>
#include <avr/interrupt.h>

// global adc instance
volatile adc_t adc;

static inline void adc_next() {
	do {
		adc.current_channel = (adc.current_channel+1)%8;

		if (!adc.current_channel) {
			adc.current_sample = adc.buffer.ptr-1;

			// update app state (remap channels)
			app.state.state.slider  = adc.buffer.ptr[4];
			app.state.state.poti[0] = adc.buffer.ptr[3];
			app.state.state.poti[1] = adc.buffer.ptr[2];
			app.state.state.poti[2] = adc.buffer.ptr[0];
			app.state.state.poti[3] = adc.buffer.ptr[1];
		}
	} while(!(adc.channel_mask & (1<<adc.current_channel)));

	if (adc.current_sample < (adc.buffer.ptr + adc.buffer.size)) {
		adc.current_sample++;
	}

	// set mux input
	ADMUX = adc.current_channel;
}

/* adc driver */
void adc_init(adc_buffer_t buffer, uint8_t mask) {
	if (!mask) {
		return;
	}

	adc.buffer = buffer;
	adc.current_sample = adc.buffer.ptr;
	adc.channel_mask = mask;
	adc.current_channel = 0;

	// find first channel
	while(!((1<<adc.current_channel) & mask)) {
		adc.current_channel++;
	}

	ADMUX  = 0;
	ADCSRA = (1<<ADATE) | (1<<ADEN) ; // enable adc, maximum prescaler value
}

void adc_start() {
	ADCSRA |= (1<<ADIE) | (1<<ADSC); // enable adc interrupt
}

void adc_stop( ){
	ADCSRA &= ~(1<<ADIE);
}

ISR(ADC_vect) {
	*adc.current_sample = ADC;
	adc_next();
}

