/*  FSM for ADC conversion
      ----------------
      |     IDLE     |
      ----------------
            |
            -INT2
            |
            |
      ----------------
      |  INIT_CONV   |<---------------------|
      ----------------                      |
            |                               |
            |                               |
            |                               |oversampling done
            |                               |
      ----------------       oversampling   |
      |  START_CONV  |<---------------------|
      ----------------   /\   in progress   |
            |             |                 |
            -INT_AD       |                 |
            |             |                 |
            |             |                 |
      ----------------    |                 |
      |   READ_CONV  |    |                 |
      ----------------    |                 |
            |-------------|!all adc done    |
            |                               |
all adc done|                               |
            |                               |
      ----------------                      |
      |    OUTPUT     |                     |
      ----------------                      |
            |                               |
            |                               |
            |                               |
      ----------------                      |
      |   DATA_DONE   |                     |
      ----------------                      |
            |                               |
            |--------------------------------

*/


#define NB_ADC 4
static int16 adc_vals[NB_ADC];

#define SAMPLING 6                  //0..6 oversample 1..2^6
#define OVER_SAMPLING 1<<SAMPLING   //1..64 oversampling value32

#define TW1 adc_vals[0]
#define TW2 adc_vals[1]
#define TW3 adc_vals[2]
#define TW4 adc_vals[3]

enum adc_state {
  IDLE,
  INIT_CONV,
  START_CONV,
  READ_CONV,
  OUTPUT,
  DATA_DONE,
  DELAY
};


static adc_state ad_state = IDLE;            //machine state for AD conversion operation
int adc_idx;
int adc_nb_read;

struct {
    unsigned char ADON  :1;
    unsigned char GODONE:1;
    unsigned char CHS0  :1;
    unsigned char CHS1  :1;
    unsigned char CHS2  :1;
    unsigned char CHS3  :1;
} ADCON0bits;
#locate ADCON0bits=0x0FC2



void thumbweel_init () {
  setup_adc_ports(AN0_TO_AN3);                     //setup adc on port AN0 - AN3
  setup_adc(ADC_CLOCK_DIV_64);

  printf("\r\nInit thumbweel done, oversampling==%u", OVER_SAMPLING);
}

int thumbweel_task(){
  int i;
  static int res = 0;

  switch (ad_state){
    case IDLE :
      thumbweel_init ();
      ad_state = INIT_CONV;
      break;

    case INIT_CONV:
      memset(adc_vals, 0, sizeof(adc_vals));  //reset stored ADC values

      adc_idx = 0;
      adc_nb_read = OVER_SAMPLING;
      ad_state = START_CONV;
      break;

    case START_CONV:
      //printf("\r\nStarting conv on %u", adc_idx);
      set_adc_channel(adc_idx);

      ad_state = READ_CONV;
      read_adc(ADC_START_ONLY);
      break;

    case READ_CONV :
      if ( !ADCON0bits.GODONE ) {
         adc_vals[adc_idx] += read_adc(ADC_READ_ONLY);
         //printf("\r\nConv done [%u]=%Lu", adc_idx, read_adc(ADC_READ_ONLY));
         if (++adc_idx == NB_ADC ){                 //select next ADC channel
           adc_idx = 0;
           ad_state = OUTPUT;
         }else{
           ad_state = START_CONV;
         }
      }
      break;

    case OUTPUT :
      if ( !(--adc_nb_read) ) {                 // adc_nb_read==0 -> oversampling done
        for (i=0;i<NB_ADC;++i)                  // all values are / by 32
          adc_vals[i]>>=SAMPLING;               // x>>=y, is the same as x=x>>y division par 32 ou 64 pour moyenner
        res = 1;
      }

      ad_state = DATA_DONE;
      break;

    case DATA_DONE :
      res = 0;
      if (!adc_nb_read)
        ad_state = INIT_CONV;
      else
        ad_state = START_CONV;
      break;

    case DELAY :
      break;

    default:
      printf("\r\nFSM error");
      break;

  } // end switch
  return res;
}




