/* NonVolatile.c */

#include "NonVolatile.h"
#include "Constant.h"
#include "Volatile.h"

/*---- DEFINES --------------------------------------------------------------------------------------------*/
#define rtInf                          (100000000000000000.000000)
#define rtMinusInf                     (-100000000000000000.000000)
#ifndef __FAR_POINTER

/* Define as empty */
#define __FAR_POINTER
#endif

/*---- CONSTANTS ------------------------------------------------------------------------------------------*/
#include <Pragma_Section_Start_rodata_romcals.h>

const __SECTION_RODATA_ROMCALS__ NonVolatile_T NonVolatileDefault = {
  NV_MAGIC_NUMBER,
  0x0000,
  0x0000,
  12,                                  /* CityID_CAN_1 */
};

#include <Pragma_Section_End_rodata.h>

/*---- SERIAL EEPROM VARIABLES ----------------------------------------------------------------------------*/
/* Uninitialised EE Variables */
#include <Pragma_Section_Start_bss_ee_bss_engcode.h>

NonVolatile_T __SECTION_BSS_EEBSSENGCODE__ NonVolatileStorage;

#include <Pragma_Section_End_bss.h>

/* Initialised EE Variables */
#include <Pragma_Section_Start_data_ee_data_engcode.h>

uint8_T __SECTION_DATA_EEDATAENGCODE__ IsFirstApplicationBoot = 0xFF;

/* Name: NonVolatileRestoreOnStartup ClassID:ENUMVAR StorageID:FLASH Access:RW4+RW3+RW2+RW1 TypeID:UINT1 CType:uint1
   Struct:NonVolatileRestoreOnStartup  Mask:FFFFFFFF Gain:1.0 Offset:0.0 Exp:1.0 Min:0 Max:1 Format:1.0
   EnumDec:E_NVRestore UpdateID:BACKGND Group:"System | NonVolatile Storage | NonVolatile Storage Config"
   Help:"Selects whether to restore from factory defaults on next startup" */
uint8_T __SECTION_DATA_EEDATAENGCODE__ NonVolatileRestoreOnStartup = 0;/* defaults to restore from eeprom */

/* Name: NonVolatileRestoreOnFirstStartup ClassID:ENUMVAR StorageID:FLASH Access:RW4+RW3+RW2+RW1 TypeID:UINT1 CType:uint1
   Struct:NonVolatileRestoreOnFirstStartup  Mask:FFFFFFFF Gain:1.0 Offset:0.0 Exp:1.0 Min:0 Max:1 Format:1.0
   EnumDec:E_NVRestore UpdateID:BACKGND Group:"System | NonVolatile Storage | NonVolatile Storage Config"
   Help:"Selects whether to restore from factory defaults the first time an application boots" */
uint8_T __SECTION_DATA_EEDATAENGCODE__ NonVolatileRestoreOnFirstStartup = 1;

#include <Pragma_Section_End_data.h>

/*---- RAM VARIABLES --------------------------------------------------------------------------------------*/
#include <Pragma_Section_Start_bss_ramcals.h>

NonVolatile_T __SECTION_BSS_RAMCALS__ NonVolatileWork;

#include <Pragma_Section_End_bss.h>

/*---- CODE SPACE -----------------------------------------------------------------------------------------*/
#include <Pragma_Section_Start_text_code.h>
#include <Pragma_Section_End_data.h>
#include <Pragma_Section_End_bss.h>

/* Name: NonVolatileFormatID ClassID:VAR StorageID:RAM Access:RO4+RO3+RO2+RO1 TypeID:UINT4 CType:NonVolatile_T Struct:NonVolatileWork.NonVolatileFormatID
   Mask:FFFFFFFF Gain:1.0 Offset:0.0 Exp:1.0 Min:0 Max:4294967295 Format:8.0 UpdateID:BACKGND Group:"System | NonVolatile Storage"
   Help:"Unique identifier of the NonVolatile memory format.  Used to validate whether stored variables are in the correct form for the program" */

/* Name: NonVolatileStatus ClassID:ENUMVAR StorageID:RAM Access:RO4+RO3+RO2+RO1 TypeID:UINT1 CType:uint1 Struct:NonVolatileStatus Mask:FFFFFFFF
   Gain:1.0 Offset:0.0 Exp:1.0 Min:0 Max:6 Format:1.0 UpdateID:BACKGND
   Group:"System | NonVolatile Storage" Help:"Indicates how NonVolatile memory was loaded"  EnumDec:E_NVStatus */
uint8_T NonVolatileStatus = 0;

/* Name: NonVolatileCRC ClassID:VAR StorageID:RAM Access:RO4+RO3+RO2+RO1 TypeID:UINT4 CType:uint4 Struct:NonVolatileCRC  Mask:FFFFFFFF
   Gain:1.0 Offset:0.0 Exp:1.0 Min:0
   Max:65535 Format:1.0 UpdateID:BACKGND Group:"System | NonVolatile Storage" Help:"Calculated NonVolatile CRC" */
uint32_T NonVolatileCRC = 0;

/* Name: MotoHawkModelSecondsInUse ClassID:VAR StorageID:RAM Access:RO4+RO3+RO2+RO1 TypeID:UINT4 CType:NonVolatile_T Struct:NonVolatileWork.MotoHawkModelSecondsInUse
   Mask:FFFFFFFF Gain:1.0 Offset:0.0 Exp:1.0 Min:0 Max:4294967295 Format:8.0 UpdateID:BACKGND
   Group:"System | Version"  Help:"Total runtime of this MotoHawk software model"  Units:seconds */
void MotoHawkModelSecondsInUseTick(void)
{
  NonVolatileWork.MotoHawkModelSecondsInUse++;
}

uint16_T calculate_crc(void *pointer, uint32_T number_bytes, uint16_T icrc)
{
  uint32_T bitmask;
  uint32_T mdx;
  uint8_T *pointer1 = (uint8_T *) pointer;
  for (mdx=0; mdx < number_bytes; mdx++) {
    bitmask = 1 << 7;
    do {
      if (!(icrc & 0x8000) ^ !(*pointer1 & bitmask)) {
        icrc <<= 1;
        icrc ^= 0x8005;
      } else {
        icrc <<= 1;
      }
    } while ( bitmask >>= 1);

    pointer1++;
  }

  return icrc;
}

void RestoreDefaultNonVolatile(void)
{
  uint16_T crc = 0xFFFF;
  DISABLE();
  MemReadSynch(&NonVolatileWork, &NonVolatileDefault, sizeof(NonVolatile_T));
  crc = calculate_crc((uint8_T *)&NonVolatileWork + 12,
                      sizeof(NonVolatile_T) - 12, crc);
  NonVolatileWork.crc = crc;
  NonVolatileCRC = NonVolatileWork.crc;
  UNDISABLE();
}

void OpenNonVolatile(void)
{
  uint32_T storedNonVolatileFormatID = 0;
  uint8_T firstApplicationBoot = 0;
  uint8_T restoreFactoryDefaults = 0;
  uint8_T restoreFactoryDefaultsFirstBoot = 0;
  MemReadSynch(&firstApplicationBoot, &IsFirstApplicationBoot, sizeof
               (IsFirstApplicationBoot));
  MemReadSynch(&restoreFactoryDefaults, &NonVolatileRestoreOnStartup, sizeof
               (NonVolatileRestoreOnStartup));
  MemReadSynch(&restoreFactoryDefaultsFirstBoot,
               &NonVolatileRestoreOnFirstStartup, sizeof
               (NonVolatileRestoreOnFirstStartup));
  MemReadSynch(&storedNonVolatileFormatID,
               &(NonVolatileStorage.NonVolatileFormatID), sizeof
               (NonVolatileStorage.NonVolatileFormatID));
  if ((firstApplicationBoot && restoreFactoryDefaultsFirstBoot) ||
      restoreFactoryDefaults) {
    NonVolatileStatus = NV_LOADING_FACTORY;
    RestoreDefaultNonVolatile();
    restoreFactoryDefaults = 0;
    MemWriteSynch(&NonVolatileRestoreOnStartup, &restoreFactoryDefaults, sizeof
                  (NonVolatileRestoreOnStartup));
    NonVolatileStatus = NV_LOADED_FACTORY_USER_CMD;
  } else if (storedNonVolatileFormatID != NonVolatileDefault.NonVolatileFormatID)
  {
    NonVolatileStatus = NV_LOADING_FACTORY;
    RestoreDefaultNonVolatile();
    NonVolatileStatus = NV_LOADED_FACTORY_BAD_MAGIC;
  } else {
    extern uint16_T calculate_crc(void *pointer1, uint32_T number_bytes,
      uint16_T icrc);
    uint16_T icrc = 0xFFFFu;
    uint32_T *work_ptr = (uint32_T *) &NonVolatileWork;
    uint32_T * __FAR_POINTER storage_ptr = (uint32_T * __FAR_POINTER) &
      NonVolatileStorage;
    uint32_T word_count = sizeof(NonVolatile_T) / 4 - 3;
    uint32_T final_byte_count = sizeof(NonVolatile_T) % 4;
    uint32_T tmp_word;
    uint32_T i;
    NonVolatileStatus = NV_LOADING_EEPROM;
    work_ptr += 3;
    storage_ptr += 3;
    for (i=0; i < word_count; i++) {
      MemReadSynch(&tmp_word, storage_ptr, sizeof(tmp_word));
      DISABLE();
      *work_ptr = tmp_word;
      UNDISABLE();
      icrc = calculate_crc(&tmp_word, sizeof(tmp_word), icrc);
      work_ptr++;
      storage_ptr++;
    }

    if (final_byte_count > 0) {
      MemReadSynch(&tmp_word, storage_ptr, final_byte_count);
      DISABLE();
      *work_ptr = tmp_word;
      UNDISABLE();
      icrc = calculate_crc(&tmp_word, final_byte_count, icrc);
    }

    NonVolatileCRC = icrc;
    MemReadSynch(&NonVolatileWork.crc, &(NonVolatileStorage.crc), sizeof
                 (NonVolatileStorage.crc));
    if (NonVolatileCRC != NonVolatileWork.crc) {
      NonVolatileStatus = NV_LOADING_FACTORY;
      RestoreDefaultNonVolatile();
      NonVolatileStatus = NV_LOADED_FACTORY_BAD_CRC;
    } else {
      MemReadSynch(&NonVolatileWork.MotoHawkModelSecondsInUse,
                   &(NonVolatileStorage.MotoHawkModelSecondsInUse), sizeof
                   (NonVolatileStorage.MotoHawkModelSecondsInUse));
      NonVolatileWork.NonVolatileFormatID = storedNonVolatileFormatID;
      NonVolatileStatus = NV_LOADED_EEPROM;
    }
  }

  if (firstApplicationBoot) {
    firstApplicationBoot = 0;
    MemWriteSynch(&IsFirstApplicationBoot, &firstApplicationBoot, sizeof
                  (IsFirstApplicationBoot));
  }
}

void StoreNonVolatile(void)
{
  extern uint16_T calculate_crc(void *pointer1, uint32_T number_bytes, uint16_T
    icrc);
  uint16_T icrc = 0xFFFFu;
  uint32_T *work_ptr = (uint32_T *) &NonVolatileWork;
  uint32_T * __FAR_POINTER storage_ptr = (uint32_T *__FAR_POINTER) &
    NonVolatileStorage;
  uint32_T word_count = sizeof(NonVolatile_T) / 4 - 3;
  uint32_T final_byte_count = sizeof(NonVolatile_T) % 4;
  uint32_T tmp_word;
  static uint32_T tmp_word2;
  uint8_T oldStatus = NonVolatileStatus;
  uint32_T i;
  NonVolatileStatus = NV_STORING_EEPROM;
  work_ptr += 3;
  storage_ptr += 3;
  for (i=0; i < word_count; i++) {
    DISABLE();
    tmp_word = *work_ptr;
    UNDISABLE();
    MemReadSynch(&tmp_word2, storage_ptr, sizeof(tmp_word2));
    if (tmp_word != tmp_word2) {
      MemWriteSynch(storage_ptr, &tmp_word, sizeof(tmp_word));
    }

    icrc = calculate_crc(&tmp_word, sizeof(tmp_word), icrc);
    work_ptr++;
    storage_ptr++;
  }

  if (final_byte_count > 0) {
    DISABLE();
    tmp_word = *work_ptr;
    UNDISABLE();
    MemReadSynch(&tmp_word2, storage_ptr, final_byte_count);
    if (tmp_word != tmp_word2) {
      MemWriteSynch(storage_ptr, &tmp_word, final_byte_count);
    }

    icrc = calculate_crc(&tmp_word, final_byte_count, icrc);
  }

  NonVolatileCRC = icrc;
  MemWriteSynch(&NonVolatileStorage.MotoHawkModelSecondsInUse,
                &NonVolatileWork.MotoHawkModelSecondsInUse, sizeof
                (NonVolatileWork.MotoHawkModelSecondsInUse));
  MemWriteSynch(&NonVolatileStorage.NonVolatileFormatID,
                &NonVolatileDefault.NonVolatileFormatID, sizeof
                (NonVolatileWork.NonVolatileFormatID));
  MemWriteSynch(&NonVolatileStorage.crc, &NonVolatileCRC, sizeof(NonVolatileCRC));
  NonVolatileStatus = oldStatus;
}

/*---- END OF FILE ----------------------------------------------------------------------------------------*/
