


#include "saveTiming.h"

#include "nvram.h"
#include "main.h"

#include "libIgnTiming/timing.H"

extern void watchdogWrite();

// define tags for items
static const uint8_t TIMING_OFFSET_TAG = 1; // timing offset tag
static const uint8_t TIMING_LOW_TAG = 0x10;
static const uint8_t VACUUM_LOW_TAG = 0x30;
static const uint8_t MAP_BASE_TAG = 0x50;
static const uint8_t MAP_ROW_OFFSET = 0x10;
static const uint8_t UINT16_LOW_OFFSET = 0x10;
static const uint8_t UINT16_HIGH_OFFSET = 0x00; // nothing but it looks tidier

/// @brief Load 16 bit data from two tagged byte items
/// @param baseTag Tag to use for indexing
/// @param data pointer to data to load value into
/// @return true if succeeded
static uint8_t load_uint16_t(uint8_t baseTag, uint16_t *data)
{
    nvram_info_t *found_high = find_nvram_data(baseTag+ UINT16_HIGH_OFFSET);
    if (!found_high)
        return 0;
    nvram_info_t *found_low = find_nvram_data(baseTag + UINT16_LOW_OFFSET);
    if (found_low)
        return 0;
    *data = (found_high->data.val << 8) | (found_low->data.val);
    return 1;
}

/// @brief Save 16 bit data in two tagged byte items
/// @param baseTag
/// @param data data to write 
static void save_uint16_t(uint8_t baseTag, uint16_t data)
{
    nvram_info_t info;
    info.data.tag = baseTag + UINT16_HIGH_OFFSET;
    info.data.val = data >> 8;
    write_nvram_data(info);
    info.data.tag = baseTag + UINT16_LOW_OFFSET;
    info.data.val = data & 0xFF;
    write_nvram_data(info);
}

///@brief load the timing info in from NVRAM
void loadTimingInfoFromNvram()
{
    uint8_t missingData = 0;

    nvram_info_t *found = find_nvram_data(TIMING_OFFSET_TAG);
    if (found)
        setTimingAdjust(found->data.val);
    else
        missingData = 1;

    // load in timing map column heading values
    for (int i = 0; i < MAX_RPM_POINTS; i++)
    {
        uint16_t val;
        uint8_t found = load_uint16_t(TIMING_LOW_TAG + i, &val);
        if (found)
            setRpmMap(i, val);
        else
            missingData = 1;
    }

    // load in vacuum map row heading values
    for (int i = 0; i < MAX_VACUUM_POINTS; i++)
    {
        uint16_t val;
        uint8_t found = load_uint16_t(VACUUM_LOW_TAG + i, &val);
        if (found)
            setVacuumMap(i, val);
        else
            missingData = 1;
    }

    for (int i = 0; i < MAX_VACUUM_POINTS; i++)
    {
        uint8_t tag_base = i * MAP_ROW_OFFSET + MAP_BASE_TAG;
        for (int j = 0; j < MAX_RPM_POINTS; j++)
        {
            found = find_nvram_data(tag_base + j);
            if (found)
                setTiming(i, j, found->data.val);
            else
                missingData = 1;
        }
    }

    if (missingData)
        saveTimingInfoToNvram();
}

/// @brief Save timing info to NVRAM : this relies on the 
void saveTimingInfoToNvram()
{
    nvram_info_t info;
    info.data.tag = TIMING_OFFSET_TAG;
    info.data.val = getTimingAdjust();
    watchdogWrite(); 
    write_nvram_data(info);

       // load in timing map column heading values
    for (int i = 0; i < MAX_RPM_POINTS; i++)
    {
        uint16_t val = getRpmMap(i);
        save_uint16_t(TIMING_LOW_TAG + i, val);
    }

    // load in vacuum map row heading values
    for (int i = 0; i < MAX_VACUUM_POINTS; i++)
    {
        uint16_t val = getVacuumMap(i);
        watchdogWrite(); 
        save_uint16_t(VACUUM_LOW_TAG + i, val);
    }

    // save all the data values 
    for (int i = 0; i < MAX_VACUUM_POINTS; i++)
    {
        uint8_t tag_base = i * MAP_ROW_OFFSET+MAP_BASE_TAG;
        for (int j = 0; j < MAX_RPM_POINTS; j++)
        {
            info.data.val = getTiming(i,j);
            info.data.tag = tag_base + j;
            watchdogWrite(); 
            write_nvram_data(info);
           
        }
    }
}