// rt-esp32-timeradc01
// https://techtutorialsx.com/2017/10/07/esp32-arduino-timer-interrupts/

// https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/freertos-smp.html


// JDN 2021



// ISR
hw_timer_t *timer = NULL;
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;

// Repetetive timer which takes care of sampling etc.
// 1-10kHz
void IRAM_ATTR
onTimer ()
{
  static int sampleVal;

  // FAKE PART
  sampleVal = 4;		// in real life read ADC converter aka Arduino way  sampleVal = analogRead(3); 

  portENTER_CRITICAL_ISR (&timerMux);	// for dataprotection on dual core

  saveADCsample (sampleVal);

  portEXIT_CRITICAL_ISR (&timerMux);

}

/* setup timer on ISR just above
    variable timerMicroSecCount set timer speed
    Can be used for sampling
*/

const int timerMicroSecCount = 1000;	// 1e6 = 1 sec

void
startCyclicTimerISR ()
{

  timer = timerBegin (0, 80, true);	// timer no 0 out of 4(0,1,2,3) divide 80 MHz timer with 80 -> 1 MHz timer
  timerAttachInterrupt (timer, &onTimer, true);
  timerAlarmWrite (timer, timerMicroSecCount, true);	// true: auto reload
  timerAlarmEnable (timer);	// gogo
}

///////
// OUR DATA
const int ECGBUF = 5000;	// 5 seconds - enough ?

unsigned short ecgBuf[ECGBUF];	// the buffer where we receive data from ISR

int ecgBufRd = 0, ecgBufWr = 0;	// Wr(writer) index for ISR, Rd(reader) index for you

volatile int nrInBuf = 0;	// how many elm in buffer

void
saveADCsample (int sampleVal)	// to be called from ISR
{
  // REAL PART PUT IN BUF
  // check for overflow - buffer full
  // degraded mode kan være reset af buffer system
  if (nrInBuf < ECGBUF)
    {				// plads ?
      nrInBuf++;
    }
  else
    {				// nope ingen pldas, overskrivning af aeldste/yngste/stoppe ?
      return;			// hvis du vil stopp med leverance1
      ecgBufRd++;
      ecgBufRd %= ECGBUF;
    }
  ecgBuf[ecgBufWr++] = sampleVal;
  ecgBufWr %= ECGBUF;		// wrap around  ecgBufWr  = ecgBufWr % ECGBUF

  // SKAL VI OVERSKRIVE GL DATA ELLER MISTE NYE DATA (midlertid stop af leverance)
  // can not hold more elements than in buffer - so limit count value

}


void
saveADCsample (int sampleVal)	// to be called from ISR
{
  // REAL PART PUT IN BUF
  // check for overflow - buffer full
  // degraded mode kan være reset af buffer system
  if (nrInBuf < ECGBUF)
    {				// plads ?
      nrInBuf++;
    }
  else
    {				// nope ingen pldas, overskrivning af aeldste/yngste/stoppe ?
      return;			// hvis du vil stopp med leverance1
      ecgBufRd++;
      ecgBufRd %= ECGBUF;
    }
  ecgBuf[ecgBufWr++] = sampleVal;
  ecgBufWr %= ECGBUF;		// wrap around  ecgBufWr  = ecgBufWr % ECGBUF

  // SKAL VI OVERSKRIVE GL DATA ELLER MISTE NYE DATA (midlertid stop af leverance)
  // can not hold more elements than in buffer - so limit count value

}

int
getAntalADCFromBuf (int *v, int antal)
{
  portENTER_CRITICAL (&timerMux);	// for dataprotection on dual core

  if (antal <= nrInBuf)
    {				// check if antal new sample in buffer, if yes get it and adjust buffer indeces
      while (antal--)
	{
	  *v = ecgBuf[ecgBufRd];
	  v++;
	  ecgBufRd++;
	  ecgBufRd %= ECGBUF;
	  nrInBuf--;
	}
      portEXIT_CRITICAL (&timerMux);
      return 0;			// ok
    }

  portEXIT_CRITICAL (&timerMux);
  return -1;			// no data
}


void
ecgBufInit ()
{
  ecgBufRd = 0;
  ecgBufWr = 0;			// Wr(writer) index for ISR, Rd(reader) index for you
  nrInBuf = 0;			// how many elm in buffer
  for (int i = 0; i < ECGBUF; i++)
    {
      ecgBuf[i] = 0;
    }
}

void
setup ()
{
  Serial.begin (115200);
  delay (2000);
  ecgBufInit ();
  startCyclicTimerISR ();
  // herfter korer system med interrupt
}

void
loop ()
{
  int v;
  int vv[10];

  if (0 == getAntalADCFromBuf (&(vv[0]), 7))
    {				// eller short cut (vv,7)
      //analyse af en antal elm  delay(12);
    }
  if (0 == getADCFromBuf (&v))
    {
      // analyse/buffering
      // varighed af kode
      // tidsstempel  NBNB: hvis bufferoverflow - saa gaar tidsberegning
      Serial.println (v);
    }
}
