#include "project.h"


#define POT   GPIO3
#define POT_PORT  GPIOC

#define POT_CHANNEL ADC_CHANNEL13
#define VREF_CHANNEL  ADC_CHANNEL17

#define ADC_TIMEOUT 1000

static enum {
  WAIT_VREF,
  WAIT_POT
} state = WAIT_VREF;


static uint32_t adc_stamp;
static uint16_t pot, vref;

uint8_t pot_brightness = 0x8;


static void start_conversion (uint8_t ch)
{
  adc_stamp = ticks;
  adc_set_regular_sequence (ADC1, 1, &ch);
  adc_start_conversion_regular (ADC1);
}

static void calculate_and_set_brightness (void)
{
  static uint32_t spot, svref;
  uint32_t v;

  /* dumb IIR with 16x gain */
  spot *= 15;
  spot >>= 4;
  spot += pot ;

  svref *= 15;
  svref >>= 4;
  svref += vref  ;


  if (svref > 65535) svref = 65535;

  if (spot > 65535) spot = 65535;

  v = spot << 16;
  v /= svref;
  v <<= 8;
  v /= 12014;  // vref is 1.2v FSD is 3.3v, 15 brightness levels so (65536 * (3.3/1.2) /15 )

  v >>= 8;


  if (v > 15) v = 15;

  pot_brightness = v;
}


void adc_dispatch (void)
{
  uint32_t now = ticks;
  uint32_t ago;

  ago = now - adc_stamp;

  if (ago > ADC_TIMEOUT) {
    adc_off (ADC1);
    adc_power_on (ADC1);
    state = WAIT_VREF;
    start_conversion (VREF_CHANNEL);
    return;
  }

  if (!adc_eoc (ADC1))
    return;

  switch (state) {
  case WAIT_VREF:
    vref = adc_read_regular (ADC1);
    start_conversion (POT_CHANNEL);
    state = WAIT_POT;
    break;

  case WAIT_POT:
    pot = adc_read_regular (ADC1);
    start_conversion (VREF_CHANNEL);
    calculate_and_set_brightness();

  /* fall through */
  default:
    state = WAIT_VREF;
  }
}














void adc_init (void)
{
  rcc_periph_clock_enable (RCC_ADC1);

  MAP_ANALOG_INPUT (POT);

  adc_off (ADC1);
  adc_disable_scan_mode (ADC1);
  adc_enable_temperature_sensor();

  adc_set_single_conversion_mode (ADC1);
  adc_enable_temperature_sensor(); /*Enables reference*/
  adc_set_sample_time (ADC1, POT_CHANNEL, ADC_SMPR_SMP_480CYC);
  adc_set_sample_time (ADC1, VREF_CHANNEL, ADC_SMPR_SMP_480CYC);
  adc_enable_external_trigger_regular (ADC1, 0, ADC_CR2_EXTEN_DISABLED);
  adc_set_right_aligned (ADC1);
  adc_eoc_after_group (ADC1);

  adc_power_on (ADC1);
  adc_enable_temperature_sensor(); /*Enables reference*/

  state = WAIT_VREF;
  start_conversion (VREF_CHANNEL);
}