// https://github.com/greiman/SdFat




/* SD-kort SETUP:
  CS -> 5
  DI -> 23 (MOSI)
  VCC -> 3.3V
  SCK -> 18
  GND -> GND
  D0 -> 19 (MISO)
  CD -> Nada
  https://www.youtube.com/watch?v=fPvW-dtB6i0
*/

QueueHandle_t msgQ;
SemaphoreHandle_t syncSem;

#include <SPI.h>
#include "SD.h"
#include "FS.h"


#define SD_CS 5			//CS pin til ESP32


#define BSIZE 1000
int bufToPrint[BSIZE];		// buffer for data to be printed

// no of buffers in msgQ
#define NRBUF 3

// NRCHUNKS == number og BSIZE samples
#define NROFCHUNKS 10		//200 sekunder
#define NROFCHUNKSBETWEENFLUSH 50

const char fileName[] = "/data2.txt";

volatile int nrChunks = 0, nrChunksBetweenFlush = 0;

File file;

void IRAM_ATTR
ISRtick ()
{

  static BaseType_t xHigherPriorityTaskWoken;

  xHigherPriorityTaskWoken = pdFALSE;
  xSemaphoreGiveFromISR (syncSem, &xHigherPriorityTaskWoken);	//kick sampler

  if (xHigherPriorityTaskWoken)
    {
      portYIELD_FROM_ISR ();
    }
}

void
tSampler (void *parameter)
{
  static int ekgBuf[BSIZE];
  static int bufIndex = 0;

  for (;;)
    {

      if (xSemaphoreTake (syncSem, (TickType_t) 1000) == pdTRUE)	// time for sampling ?
	{
	  // yep
	  ekgBuf[bufIndex] = analogRead (A0);
	  bufIndex++;

	  if (BSIZE <= bufIndex)
	    {			// buf full ? then tx it by msgQ
	      bufIndex = 0;
	      while (pdTRUE != xQueueSend (msgQ, (void *) ekgBuf, 1))	// loop fordi jeg ikke vil tabe beskedder. Den SKAL sendes
		{
		  // you might hang here if Q is full !
		}
	    }
	}
    }
}


void
tFiler (void *parameter)
{
  int adcV;
  int whichBuf = 0;

  for (;;)
    {
      if (xQueueReceive (msgQ, bufToPrint, (TickType_t) 100) == pdTRUE)	// get a chunk from tSampler
	{
	  if (nrChunks < NROFCHUNKS)
	    {			// lenght of your experiment

	      // 1: fast binary, 0: slow ascii ( you  can see what is in file by eyes
#if 0				//Hvis 0 så printer den ascii
	      //Serial.println(millis()); // for test only
	      file.write ((uint8_t *) bufToPrint, sizeof (int) * BSIZE);	// BINARY !!!
#else
	      //the slow one in ascii
	      // comment out
	      file.println ("Hej");
	      Serial.println ("Hej test");
	      for (int i = 0; i < BSIZE; i++)
		file.println (bufToPrint[i]);	//ascii print to bu
#endif
	      nrChunks++;
	      nrChunksBetweenFlush++;

	      // saving from time to time to be sure
	      if (NROFCHUNKSBETWEENFLUSH <= nrChunksBetweenFlush)
		{
		  nrChunksBetweenFlush = 0;
		  //file.flush();
		  file.close ();
		  file = SD.open (fileName, FILE_WRITE);
		}
	    }
	  else
	    {
	      //file.flush();
	      file.close ();
	      Serial.println ("Data opsamling slut");
	      vTaskDelay (100);
	      vTaskDelete (NULL);	// end of story. NB loop will not be active
	      //while(1);
	      //Timer disable
	      //STOP
	    }
	}

    }
}

void
initSD ()
{

  // Initialize SD card
  if (!SD.begin (SD_CS))
    {
      Serial.print ("SD card mount failed");

      // what next ??? hm
      while (1);		// freezze here and stayyyy here
    }

  uint8_t cardType = SD.cardType ();

  if (cardType == CARD_NONE)
    {
      Serial.println ("No SD card attached");
      while (1);		// stay here forever
    }

  file = SD.open (fileName, FILE_WRITE);	// JDN Fjernet FILE https://www.mischianti.org/2021/03/28/how-to-use-sd-card-with-esp32-2/

  if (!file)
    {
      Serial.print ("cant open file for write");
      while (1);
    }
  Serial.println ("SD KORT ER OK");
  //file.println("EKG DATA v 0.97");

  // JDN INGENG GRUND TIL AT LUKKE FIL _: VI SKAL TIL AT LOGGE  file.close();

  delay (1000);
}


hw_timer_t *timer = NULL;

// we do use a timer to do 1 kHz sampling - fra kurset /Jens
void
configTimer ()
{
  timer = timerBegin (0, 80, true);
  // 0 -> er et ID nummer (vi har 4 timer ialt)
  //80 MHz neddelt med 80 ->  1 micro sekunds ticks
  // true -> flag true to count on the rising edge, false to count on the falling edge

  timerAttachInterrupt (timer, ISRtick, true);
  // timer -> er vores pointer til timer-objektet
  // &onTimer -> adressen på den funktion vi ønsker at kalder hver gang timeren aktiveres
  // true -> betyder at timeren tæller på en rising edge af et clock-signal (og ikke på et level-shift)

  timerAlarmWrite (timer, 1000, true);
  // timer -> er vores pointer til timer-objektet
  // 1000 ticks -> 1 ms -> fs = 1000 Hz
  // 2000 ticks -> 2 ms -> fs = 500 Hz
  // true -> autoreload true vil gøre timeren automatisk klar til næste interrupt
  timerAlarmEnable (timer);
}

void
setup ()
{

  Serial.begin (115200);
  delay (1000);

  initSD ();

  msgQ = xQueueCreate (NRBUF, BSIZE * sizeof (int));
  syncSem = xSemaphoreCreateBinary ();
  Serial.println ("kommer vi forbi");
  delay (1000);

  // high prio task sampler
  xTaskCreatePinnedToCore (tFiler, "tFiler", 4000, NULL,
			   (configMAX_PRIORITIES - 2), NULL, 0);
  xTaskCreatePinnedToCore (tSampler, "t1sampler", 4000, NULL,
			   (configMAX_PRIORITIES - 1), NULL, 0);

  /*                                                             ^--  ´core (0or 1 on esp32)
     ^------  handle to task code
     ^---------- priority 0(lowest) to  (configMAX_PRIORITIES-1)
     ^---------------- pointer to parameter to be used as pParm in task
     ^--------------------- amoont of stak to be allocated
     ^--------------------------- name
     ^---------------------------------- function to be used as code for task
   */

  //Venter på start på knap

  configTimer ();		// this will start the show

  vTaskDelay (100);
  vTaskDelete (NULL);		// end of story. NB loop will not be active
}


void
loop ()
{
}
