
#include <stdint.h>
#include <stddef.h>       /* NULL pointer */
#include <stdio.h>

#include "scmt.h"
#include "scmt_config.h"
#include "scmt_checkpoint.h"

#if PRINT_INFO
  #include <rst_register.h> /* Access to mode pin register */
  #include <mem_io.h>       /* Access to mode pin register */
#endif /* PRINT_INFO */


#define xstr(a) str(a)
#define str(a) #a

/* Structure to hold the log data. */
typedef struct {
  uint32_t counter; /* Value of SCMT counter */
  char * note;      /* String is stored as pointer! Pointer must be valid during runtime! */
  uint32_t data;    /* Arbitrary data to add to log */
} checkpoint_t;
checkpoint_t time_checkpoints[TIME_CHECKPOINTS_MAX];

/* If SCMT has a start value other than zero, we'll keep two slots free to inform the user about the offset within the print function */
#if (SCMT_START_VALUE == 0)
uint32_t time_checkpoints_index = 0;
#else
uint32_t time_checkpoints_index = 2;
#endif

/* Store a checkpoint: Fetch current counter value and store it together with a pointer to a static string as well as arbitrary data */
void store_time_checkpoint(char * note, uint32_t data)
{
    if (time_checkpoints_index < TIME_CHECKPOINTS_MAX) {
        time_checkpoints[time_checkpoints_index].counter = scmt_module_read();
        time_checkpoints[time_checkpoints_index].note = note;
        time_checkpoints[time_checkpoints_index].data = data;
    }
    time_checkpoints_index++;
}


#if (0 == (MEASURE_TIME_NOPRINT))
/* Print checkpoints */
void print_time_checkpoints(void)
{
    uint32_t i;

    {PRINTFN(MODULE"=================\r\n");}

#if PRINT_INFO
    /* First, provide some information about the environment */
    {PRINTFN(MODULE"MODEMR[1:0]: 0x%x 0x%x\r\n", mem_read32(RST_MODEMR1), mem_read32(RST_MODEMR0) );}

    {PRINTFN(MODULE"Timer: '" xstr(TIMER_FUNC) "'\r\n");}
    {PRINTFN(MODULE"- freq: %.3f kHz\r\n", (TIMER_FREQ)/1000.0f);}
    {PRINTFN(MODULE"- resolution: 1 tick = %.4f ms\r\n", 1000.0/(TIMER_FREQ));}
#endif /* PRINT_INFO */

    /* In case of unsufficient storage for checkpoints, inform about it */
    if (time_checkpoints_index >= TIME_CHECKPOINTS_MAX) {
        {PRINTFN(MODULE"Internal number of checkpoints exceeded reserved space: %i of %i\r\n", time_checkpoints_index, TIME_CHECKPOINTS_MAX);}
    }

    /* In case of non-zero SCMT start value, inform about it */
  #if (SCMT_START_VALUE != 0)
        time_checkpoints[0].counter = 0;
        time_checkpoints[0].note = "Reset Release!";
        time_checkpoints[1].counter = SCMT_START_VALUE;
        time_checkpoints[1].note = "Timer started here with manual offset relative to reset release!";
  #endif

    /* Print log in CSV style */
    {PRINTFN(MODULE"CSV; timer_ticks; total_time[ms]; delta_time[ms]; data; comment\r\n" );}
    for (i=0; i<time_checkpoints_index; i++) {

        /* Some projects don't have float handling activated in the compiler.
           In this case you have to calculate the times later in the spreadsheets */
#if PRINT_FLOAT
        float ms = time_checkpoints[i].counter*1000.0/(TIMER_FREQ);
        float ms_delta = 0.0;
        if (i>0) {
            ms_delta = ms - time_checkpoints[i-1].counter*1000.0/(TIMER_FREQ);
        }

        // ==> "E:ICUMX:CP:   364; 2.77; 2.77; 0; init_done"
        {PRINTFN(MODULE"CP; %u; %f; %f; %u; %s\r\n", time_checkpoints[i].counter, ms, ms_delta, time_checkpoints[i].data, time_checkpoints[i].note );}
#else
        {PRINTFN(MODULE"CP; %u; --; --; %u; %s\r\n", time_checkpoints[i].counter, time_checkpoints[i].data, time_checkpoints[i].note );}
#endif

    }

    /* Timer verification.
       Sample calculation:
       SCIF is running with 921600 Baud. 8N1 => 0.0108 ms / bit.
       Sending 20 characters should take 28 timer ticks of SCMT
       As SCIF has a 16-stage FIFO, send at least 16 characters before start of measurements */
#if 0 != TIMER_TEST_VS_BAUD
    {
        uint32_t start = 0, stop = 0;
        const char teststr[] = "ExecutingTimerTestExecutingTimerTestExecutingTimerTest!\r\n"; /* 57 characters */
        const float charrate = (TIMER_TEST_VS_BAUD)/10.0; /* 8N1: 10 cycles per character */
        const float expected_ms = sizeof(teststr)*1000.0/(charrate);
        float measured_ms;

        {PRINTFN(MODULE"=================\r\n");}
        {PRINTFN(MODULE"FillingFifoForTimerTestFillingFifoForTimerTest - ");}
        start = (TIMER_FUNC)();
        {local_printf(teststr);}
        stop = (TIMER_FUNC)();
        measured_ms = (stop-start)*1000.0/(TIMER_FREQ);

        {PRINTFN(MODULE"(Printing the test took %5i ticks / %7.2f ms / expected: %7.2f ms  -  %s)\r\n", stop-start, measured_ms, expected_ms, ((measured_ms/expected_ms < 1.3) && (measured_ms/expected_ms > 0.9))?"OK":"ERROR");}
    }
#endif /* TIMER_TEST_VS_BAUD */
    {PRINTFN(MODULE"=================\r\n");}

}
#else //(MEASURE_TIME_NOPRINT) == 0
void print_time_checkpoints(void) {}
#endif //(MEASURE_TIME_NOPRINT) == 0

