//#include "options.h"
//#define FLASHCHIP_C
//#include "drivers/flash/flashchip.h"
#include "core/config.h"
#include "crc32.h"
#include "app/nfm/nfm_base_excls.h"
#include "string.h"  
#include "drivers/flash/base/extmem_flash.h"
//------------------------------------------------------------------------------
#pragma location=".cache"
static uint8_t g_RomBuffer [ CONFIG_FLASHMEM_CACHE_SIZE ];
        
typedef enum
{
  RomBufCache_undefined,
  RomBufCache_CommonHeader,
  RomBufCache_FactoryChrzHeader,
  RomBufCache_TCompHeader,
  RomBufCache_User1ChrzHeader,
  RomBufCache_User2ChrzHeader,
  RomBufCache_User3ChrzHeader,  
} 
eRomBufCache_t;

static eRomBufCache_t g_RomBuffer_Cache = RomBufCache_undefined;
//------------------------------------------------------------------------------
//const sNFMMemory_ChrzTableMatrix_2Port_t tableMatrix_SC2543_2xPort_NFM_2543_v1 =
//{
//    DECLARE_CHRZTABLETYPE_2PORT(14),
//    
//    .Single = 
//    {
//       /* Port A */
//       .aArray[ ePortComb_A - ePortComb_MIN_SINGLE_2Port ] =           
//       {
//          .aBaseIndex[ ePortStateId_Short - ePortStateId_MIN_SINGLE_2Port ] = 1,  // Short
//          .aBaseIndex[ ePortStateId_Open  - ePortStateId_MIN_SINGLE_2Port ] = 3,  // Open
//          .aBaseIndex[ ePortStateId_Load  - ePortStateId_MIN_SINGLE_2Port ] = 5,  // Load
//          .aBaseIndex[ ePortStateId_Load2 - ePortStateId_MIN_SINGLE_2Port ] =15,  // Load2
//          .aBaseIndex[ ePortStateId_Open2 - ePortStateId_MIN_SINGLE_2Port ] =17,  // Open2
//       },  
//       
//       /* Port B */
//       .aArray[ ePortComb_B - ePortComb_MIN_SINGLE_2Port ] =  
//       {                        
//          .aBaseIndex[ ePortStateId_Short - ePortStateId_MIN_SINGLE_2Port ] = 2,  // Short
//          .aBaseIndex[ ePortStateId_Open  - ePortStateId_MIN_SINGLE_2Port ] = 4,  // Open
//          .aBaseIndex[ ePortStateId_Load  - ePortStateId_MIN_SINGLE_2Port ] = 6,  // Load
//          .aBaseIndex[ ePortStateId_Load2 - ePortStateId_MIN_SINGLE_2Port ] =16,  // Load2
//          .aBaseIndex[ ePortStateId_Open2 - ePortStateId_MIN_SINGLE_2Port ] =18,  // Open2
//       },          
//    },
//    
//    .Thru = 
//    {
//       /* Thru A-B */
//       .aArrays[ ePortComb_AB - ePortComb_MIN_THRU_2Port ] =                      // Thru AB
//       {                                                                    
//          .aBaseIndex[ ePortStateId_S11 - ePortStateId_MIN_THRU_2Port ] = 7,      // S11
//          .aBaseIndex[ ePortStateId_S21 - ePortStateId_MIN_THRU_2Port ] = 8,      // S21
//          .aBaseIndex[ ePortStateId_S12 - ePortStateId_MIN_THRU_2Port ] = 9,      // S12
//          .aBaseIndex[ ePortStateId_S22 - ePortStateId_MIN_THRU_2Port ] = 10,     // S22
//       },
//    },
//    
//    .Check = 
//    {
//       .sArray =                                                            // Check State
//       {
//          .aBaseIndex[ ePortStateId_S11 - ePortStateId_MIN_CHECK_2Port ] = 11,    // S11
//          .aBaseIndex[ ePortStateId_S21 - ePortStateId_MIN_CHECK_2Port ] = 12,    // S21
//          .aBaseIndex[ ePortStateId_S12 - ePortStateId_MIN_CHECK_2Port ] = 13,    // S12
//          .aBaseIndex[ ePortStateId_S22 - ePortStateId_MIN_CHECK_2Port ] = 14,    // S22
//       }
//    },
//};
//
//const sNFMMemory_ChrzTableMatrix_2Port_t tableMatrix_SC2543_2xPort_NFM_2543_v2 =
//{
//    DECLARE_CHRZTABLETYPE_2PORT(14),
//    
//    .Single = 
//    {
//       /* Port A */
//       .aArray[ ePortComb_A - ePortComb_MIN_SINGLE_2Port ] =           
//       {
//          .aBaseIndex[ ePortStateId_Short - ePortStateId_MIN_SINGLE_2Port ] = 1,  // Short
//          .aBaseIndex[ ePortStateId_Open  - ePortStateId_MIN_SINGLE_2Port ] = 3,  // Open
//          .aBaseIndex[ ePortStateId_Load  - ePortStateId_MIN_SINGLE_2Port ] = 5,  // Load
//          .aBaseIndex[ ePortStateId_Load2 - ePortStateId_MIN_SINGLE_2Port ] =15,  // Load2
//          .aBaseIndex[ ePortStateId_Open2 - ePortStateId_MIN_SINGLE_2Port ] =17,  // Open2
//       },  
//       
//       /* Port B */
//       .aArray[ ePortComb_B - ePortComb_MIN_SINGLE_2Port ] =  
//       {                        
//          .aBaseIndex[ ePortStateId_Short - ePortStateId_MIN_SINGLE_2Port ] = 2,  // Short
//          .aBaseIndex[ ePortStateId_Open  - ePortStateId_MIN_SINGLE_2Port ] = 4,  // Open
//          .aBaseIndex[ ePortStateId_Load  - ePortStateId_MIN_SINGLE_2Port ] = 6,  // Load
//          .aBaseIndex[ ePortStateId_Load2 - ePortStateId_MIN_SINGLE_2Port ] =16,  // Load2
//          .aBaseIndex[ ePortStateId_Open2 - ePortStateId_MIN_SINGLE_2Port ] =18,  // Open2
//       },          
//    },
//    
//    .Thru = 
//    {
//       /* Thru A-B */
//       .aArrays[ ePortComb_AB - ePortComb_MIN_THRU_2Port ] =                      // Thru AB
//       {                                                                    
//          .aBaseIndex[ ePortStateId_S11 - ePortStateId_MIN_THRU_2Port ] = 7,      // S11
//          .aBaseIndex[ ePortStateId_S21 - ePortStateId_MIN_THRU_2Port ] = 8,      // S21
//          .aBaseIndex[ ePortStateId_S12 - ePortStateId_MIN_THRU_2Port ] = 9,      // S12
//          .aBaseIndex[ ePortStateId_S22 - ePortStateId_MIN_THRU_2Port ] = 10,     // S22
//       },
//    },
//    
//    .Check = 
//    {
//       .sArray =                                                            // Check State
//       {
//          .aBaseIndex[ ePortStateId_S11 - ePortStateId_MIN_CHECK_2Port ] = 11,    // S11
//          .aBaseIndex[ ePortStateId_S21 - ePortStateId_MIN_CHECK_2Port ] = 12,    // S21
//          .aBaseIndex[ ePortStateId_S12 - ePortStateId_MIN_CHECK_2Port ] = 13,    // S12
//          .aBaseIndex[ ePortStateId_S22 - ePortStateId_MIN_CHECK_2Port ] = 14,    // S22
//       }
//    },
//};

#define NFMBASE_FLASH_MAKEADDRESS_USERBANK0( addr )      ( 0x00000000 | (addr) )  // (addr + AT45FLASH_MINIMUM_ADDRESS)
#define NFMBASE_FLASH_MAKEADDRESS_USERBANK1( addr )      ( 0x80000000 | (addr) )  // (addr - FLASH_USERBANK_0_SIZE)
#define NFMBASE_FLASH_USERBANK0_CHECK( addr )            (!(0x80000000 & (addr) ))
#define NFMBASE_FLASH_USERBANK1_CHECK( addr )            (( 0x80000000 & (addr) ))

#define NFMBASE_FLASH_MIN_ADDRESS                        ( ExtMemHandle.pFlashProperties->minAddress )
#define NFMBASE_FLASH_MAX_ADDRESS                        ( ExtMemHandle.pFlashProperties->maxAddress )
#define NFMBASE_FLASH_BANK0_SIZE                         ( ExtMemHandle.pBanksProperties->factoryBankSize )
#define NFMBASE_FLASH_BANK1_SIZE                         ( ExtMemHandle.pBanksProperties->userBankSize )
#define NFMBASE_FLASH_BANK0_ADDRESS                      ( NFMBASE_FLASH_MIN_ADDRESS )
#define NFMBASE_FLASH_BANK1_ADDRESS                      ( NFMBASE_FLASH_BANK0_ADDRESS + NFMBASE_FLASH_BANK0_SIZE )

#define NFMBASE_FLASH_USERBANK0_MAKEREALADDRESS( addr )  (( (addr) & 0x7FFFFFFF ) + NFMBASE_FLASH_BANK0_ADDRESS )
#define NFMBASE_FLASH_USERBANK1_MAKEREALADDRESS( addr )  (( (addr) & 0x7FFFFFFF ) + NFMBASE_FLASH_BANK1_ADDRESS )
#define NFMBASE_FLASH_MAKEREALADDRESS( addr )            (\
                                                          (NFMBASE_FLASH_USERBANK0_CHECK(addr))\
                                                          ?(\
                                                          NFMBASE_FLASH_USERBANK0_MAKEREALADDRESS(addr)\
                                                          ):(\
                                                            (NFMBASE_FLASH_USERBANK1_CHECK(addr))\
                                                            ?(\
                                                            NFMBASE_FLASH_USERBANK1_MAKEREALADDRESS(addr)\
                                                            ):(\
                                                            0\
                                                            )\
                                                          ))


//const sNFMMemoryProfile_t memProfile_SC2543v1_ADRF_NFM2543_v1 =
//{
//    .BaseAddr_TComp              = NFMBASE_FLASH_MAKEADDRESS_USERBANK0(MEMORY_OFFSET_BLOCK_THERMHEADER_SC2543),
//    .BaseAddr_Chrz[ eChFactory ] = NFMBASE_FLASH_MAKEADDRESS_USERBANK0(MEMORY_OFFSET_BLOCK_DATAHEADER_SC2543),
//    .BaseAddr_Chrz[ eChUser1   ] = NFMBASE_FLASH_MAKEADDRESS_USERBANK1(MEMORY_OFFSET_BLOCK_USER1DATA_SC2543),
//    .BaseAddr_Chrz[ eChUser2   ] = NFMBASE_FLASH_MAKEADDRESS_USERBANK1(MEMORY_OFFSET_BLOCK_USER2DATA_SC2543),
//    .BaseAddr_Chrz[ eChUser3   ] = NFMBASE_FLASH_MAKEADDRESS_USERBANK1(MEMORY_OFFSET_BLOCK_USER3DATA_SC2543),
//    .BaseAddr_Settings = SETTINGS_ADDR_SC2543,
//    .Size_Settings = SETTINGS_SIZE_SC2543,
//    .tbls_2Port = &tableMatrix_SC2543_2xPort_NFM_2543_v1
//};
    
//const sNFMMemoryProfile_t memProfile_NFM =
//{
//    .BaseAddr_TComp              = NFMBASE_FLASH_MAKEADDRESS_USERBANK0(MEMORY_OFFSET_BLOCK_THERMHEADER_SC2543),
//    .BaseAddr_Chrz[ eChFactory ] = NFMBASE_FLASH_MAKEADDRESS_USERBANK0(MEMORY_OFFSET_BLOCK_DATAHEADER_SC2543),
//    .BaseAddr_Chrz[ eChUser1   ] = NFMBASE_FLASH_MAKEADDRESS_USERBANK1(MEMORY_OFFSET_BLOCK_USER1DATA_SC2543),
//    .BaseAddr_Chrz[ eChUser2   ] = NFMBASE_FLASH_MAKEADDRESS_USERBANK1(MEMORY_OFFSET_BLOCK_USER2DATA_SC2543),
//    .BaseAddr_Chrz[ eChUser3   ] = NFMBASE_FLASH_MAKEADDRESS_USERBANK1(MEMORY_OFFSET_BLOCK_USER3DATA_SC2543),
//    .BaseAddr_Settings = SETTINGS_ADDR_SC2543,
//    .Size_Settings = SETTINGS_SIZE_SC2543,
//    .tbls_2Port = &tableMatrix_SC2543_2xPort_NFM_2543_v2
//};   

const sSwitchMemoryProfile_t memProfile_SW = 
{
    .BaseAddr_SwTable  = NFMBASE_FLASH_MAKEADDRESS_USERBANK0(MEMORY_OFFSET_BLOCK_THERMHEADER_SC2543),
    .BaseAddr_Table[ eChValues ] = NFMBASE_FLASH_MAKEADDRESS_USERBANK1(MEMORY_OFFSET_BLOCK_USER1DATA_SC2543),
    .BaseAddr_Settings = SETTINGS_ADDR_SC2543,
    .Size_Settings = SETTINGS_SIZE_SC2543,
};
        
//------------------------------------------------------------------------------
// Set Flash Memory Bank0 Write-Protection
bool NFM_ROM_SetMemoryProtectStatus_Bank0( bool desiredStatus )
{
    return ExtMemHandle.BankProtect( extmem_bank_factory, desiredStatus );    
}
//------------------------------------------------------------------------------
// Get Flash Memory Bank0 Write-Protection status
bool NFM_ROM_GetMemoryProtectStatus_Bank0()
{
    bool status = false;

    if( ExtMemHandle.CheckBankProtect( extmem_bank_factory, &status ) )
    {
        return status;  // report with the actual protection status
    }

    return false; // error, but report that bank is unprotected
}
//------------------------------------------------------------------------------
static sEcalHeaderCRC_t * romGetCommonHeader( uint8_t * buffer, size_t size )
{
  if( NULL == buffer || size < sizeof(sEcalHeaderCRC_t) ) 
    return NULL;

  /*
  size_t baseAddr = FLASH_USERBANK_0_ADDR;

         baseAddr += MEMORY_OFFSET_BLOCK_COMMON;
  */ 
  
  size_t baseAddr = NFMBASE_FLASH_MAKEREALADDRESS( NFMBASE_FLASH_MAKEADDRESS_USERBANK0( MEMORY_OFFSET_BLOCK_COMMON ) );
  
  if( FLASH_SUCCESS( flash_read( baseAddr, buffer, sizeof(sEcalHeaderCRC_t) ) ) )
  {
      return (sEcalHeaderCRC_t*)buffer;
  }

  return NULL;
}

// ------------------------------------------------------------------------------
const sEcalHeader_t * NFM_ROM_GetCommonHeader( uint8_t * buffer, size_t size )
{
  sEcalHeaderCRC_t * hdrcrc;
  TCRC crc;
  bool cacheUsed = false;
  
  if( NULL == buffer ) 
  { 
      cacheUsed = true;
      
      if( RomBufCache_CommonHeader == g_RomBuffer_Cache )
      {
          hdrcrc = (sEcalHeaderCRC_t*)g_RomBuffer;
          goto L_NFM_ROM_GetCommonHeader_AlreadyCached;
      }
      
      buffer = (uint8_t*)g_RomBuffer; 
      size = sizeof(g_RomBuffer);
  }

  if( NULL == buffer || size < sizeof(sEcalHeaderCRC_t) ) 
  {      
      return NULL;
  }
  
  if( cacheUsed )
  {  
      g_RomBuffer_Cache = RomBufCache_undefined;
  }
  
  hdrcrc = romGetCommonHeader( buffer, size );

  if( NULL == hdrcrc )
  {      
      return NULL;
  }  

  crc = ICRC32;

  crc = CRC32( crc, (const unsigned char*)hdrcrc, sizeof(sEcalHeader_t) ); 

  if( crc != hdrcrc->CRCValue )
  {      
      return NULL;
  }   
  
  if( cacheUsed )
  {
      g_RomBuffer_Cache = RomBufCache_CommonHeader;
  }    
   
L_NFM_ROM_GetCommonHeader_AlreadyCached:
  
  return (sEcalHeader_t *)hdrcrc;
}

//const sTableHeader_t * SW_ROM_GetCommonHeader( uint8_t * buffer, size_t size )
//{
//  sTableHeaderCRC_t * hdrcrc;
//  TCRC crc;
//  bool cacheUsed = false;
//  
//  if( NULL == buffer ) 
//  { 
//      cacheUsed = true;
//      
//      if( RomBufCache_CommonHeader == g_RomBuffer_Cache )
//      {
//          hdrcrc = (sTableHeaderCRC_t*)g_RomBuffer;
//          goto L_SW_ROM_GetCommonHeader_AlreadyCached;
//      }
//      
//      buffer = (uint8_t*)g_RomBuffer; 
//      size = sizeof(g_RomBuffer);
//  }
//
//  if( NULL == buffer || size < sizeof(sTableHeaderCRC_t) ) 
//  {      
//      return NULL;
//  }
//  
//  if( cacheUsed )
//  {  
//      g_RomBuffer_Cache = RomBufCache_undefined;
//  }
//  
//  hdrcrc = romSwGetCommonHeader( buffer, size );
//
//  if( NULL == hdrcrc )
//  {      
//      return NULL;
//  }  
//
//  crc = ICRC32;
//
//  crc = CRC32( crc, (const unsigned char*)hdrcrc, sizeof(sTableHeader_t) ); 
//
//  if( crc != hdrcrc->CRCValue )
//  {      
//      return NULL;
//  }   
//  
//  if( cacheUsed )
//  {
//      g_RomBuffer_Cache = RomBufCache_CommonHeader;
//  }    
//   
//L_SW_ROM_GetCommonHeader_AlreadyCached:
//  
//  return (sTableHeader_t *)hdrcrc;
//}
// ------------------------------------------------------------------------------
// ------------------------------------------------------------------------------
// ------------------------------------------------------------------------------
static sEcalDataHeaderCRC_t * romGetDataHeader( size_t baseAddr, uint8_t * buffer, size_t size )
{
  if( NULL == buffer || size < sizeof(sEcalDataHeaderCRC_t) ) 
    return NULL;
  
  if( FLASH_SUCCESS( flash_read( baseAddr, buffer, sizeof(sEcalDataHeaderCRC_t) ) ) )
  {  
      return (sEcalDataHeaderCRC_t*)buffer;
  } 
      
  return NULL;    
}

static sTableTablePoint_t * romGetDataPoint( size_t baseAddr, uint8_t * buffer, size_t size )
{
  if( NULL == buffer || size < sizeof(sTableTablePoint_t) ) 
    return NULL;
  
  if( FLASH_SUCCESS( flash_read( baseAddr, buffer, sizeof(sTableTablePoint_t) ) ) )
  {  
      return (sTableTablePoint_t*)buffer;
  } 
      
  return NULL;    
}

static bool romSetDataPoint( size_t baseAddr, uint8_t * buffer, size_t size )
{
  if( NULL == buffer || size < sizeof(sTableTablePoint_t) ) 
    return NULL;
  
  NFMClass->methods.xMemoryProtection.disable();
  if( FLASH_SUCCESS( flash_write( baseAddr, buffer, sizeof(sTableTablePoint_t), fwm_safewrite ) ) )
  {
      NFMClass->methods.xMemoryProtection.enable();
      return true;
  }
  NFMClass->methods.xMemoryProtection.enable();
  
  return NULL;    
}
// ------------------------------------------------------------------------------
const sEcalDataHeader_t * NFM_ROM_GetDataHeader( eChrz_t tableId, uint8_t * buffer, size_t size )
{
  extern NFMClassEx_t * NFMClassExtended;
  
  sEcalDataHeaderCRC_t * hdrcrc;
  hdrcrc = (sEcalDataHeaderCRC_t*)g_RomBuffer;
  //TCRC crc;
  //bool cacheUsed = false;
  //size_t baseAddr = 0;
  
//  eRomBufCache_t cacheId = RomBufCache_undefined;
//  
//  switch( tableId )
//  {  
//      case eChFactory : cacheId = RomBufCache_FactoryChrzHeader; break;
//      case eChUser1   : cacheId = RomBufCache_User1ChrzHeader  ; break;
//      case eChUser2   : cacheId = RomBufCache_User2ChrzHeader  ; break;
//      case eChUser3   : cacheId = RomBufCache_User3ChrzHeader  ; break;
//  }
//  
//  if( NULL == buffer ) 
//  { 
//      cacheUsed = true;
//      
//      if( cacheId == g_RomBuffer_Cache && RomBufCache_undefined != g_RomBuffer_Cache )
//      {
//          hdrcrc = (sEcalDataHeaderCRC_t*)g_RomBuffer;
//          goto L_NFM_ROM_GetDataHeader_AlreadyCached;
//      }
//      
//      buffer = (uint8_t*)g_RomBuffer; 
//      size = sizeof(g_RomBuffer); 
//  }
//  
//  if( NULL == NFMClassExtended->private.properties.memProfile )
//  {  
//      return NULL;
//  }
//  
//  baseAddr = NFMBASE_FLASH_MAKEREALADDRESS( NFMClassExtended->
//               private.properties.memProfile->
//                  BaseAddr_Chrz[ (tableId%eCh_MAX) ] ); 
//
//  if( NULL == buffer || size < sizeof(sEcalDataHeaderCRC_t) ) 
//  {
//      return NULL;
//  }  
//
//  if( cacheUsed )
//  {  
//      g_RomBuffer_Cache = RomBufCache_undefined;
//  }  
//
//  hdrcrc = romGetDataHeader( baseAddr, buffer, size );
//
//  if( NULL == hdrcrc )
//  {
//      return NULL;
//  }    
//
//  crc = ICRC32;
//
//  crc = CRC32( crc, (const unsigned char*)hdrcrc, sizeof(sEcalDataHeader_t) ); 
//
//  if( crc != hdrcrc->CRCValue )
//  {
//      return NULL;
//  }   
//  
//  if( cacheUsed )
//  {
//      g_RomBuffer_Cache = cacheId;
//  }
//  
//L_NFM_ROM_GetDataHeader_AlreadyCached:
//  
  return (sEcalDataHeader_t *)hdrcrc;
}
// ------------------------------------------------------------------------------
// -Table Header functions ------------------------------------------------------
// ------------------------------------------------------------------------------
static sTableHeaderCRC_t * romSetTableHeader( uint8_t * buffer, size_t size )
{
  if( NULL == buffer || size < sizeof(sTableHeaderCRC_t) )
      return NULL;
    
  size_t baseAddr = NFMBASE_FLASH_MAKEREALADDRESS( NFMBASE_FLASH_MAKEADDRESS_USERBANK0( MEMORY_OFFSET_BLOCK_THERMHEADER_SC2543 ) );
  
  NFMClass->methods.xMemoryProtection.disable();
  if( FLASH_SUCCESS( flash_write( baseAddr, buffer, sizeof(sTableHeaderCRC_t), fwm_safewrite ) ) )
  {
      NFMClass->methods.xMemoryProtection.enable();
      return (sTableHeaderCRC_t*)buffer;
  }
  NFMClass->methods.xMemoryProtection.enable();

  return NULL;
}

static sTableHeaderCRC_t * romGetTableHeader( uint8_t * buffer, size_t size )
{
  if( NULL == buffer || size < sizeof(sTableHeaderCRC_t) )
    return NULL;
    
  size_t baseAddr = NFMBASE_FLASH_MAKEREALADDRESS( NFMBASE_FLASH_MAKEADDRESS_USERBANK0( MEMORY_OFFSET_BLOCK_THERMHEADER_SC2543 ) );
    
  if( FLASH_SUCCESS( flash_read( baseAddr, buffer, sizeof(sTableHeaderCRC_t) ) ) )
  {
      return (sTableHeaderCRC_t*)buffer;
  }

  return NULL;
}

static bool SW_Validate_Table_Header_CRC ( sTableHeaderCRC_t * hdrcrc )
{
    TCRC crc;
    crc = ICRC32;
    crc = CRC32( crc, (const unsigned char*)hdrcrc, sizeof(sTableHeader_t) );
    return hdrcrc->CRCValue == crc ;
}

sTableHeaderCRC_t * SW_ROM_GetTableHeader()
{
  uint8_t * buffer = (uint8_t*)g_RomBuffer; 
  size_t size = sizeof(g_RomBuffer);
  if( NULL == buffer || size < sizeof(sTableHeaderCRC_t) ) 
  {      
      return false;
  }
  
  g_RomBuffer_Cache = RomBufCache_undefined;
  
  return romGetTableHeader( buffer, size );
}

bool SW_ROM_ChangeTableHeader( sTableHeaderCRC_t * hdrcrc )
{
  extern NFMClassEx_t * NFMClassExtended;
  if(hdrcrc == NULL) return false;
  
  uint8_t * buffer = (uint8_t*)g_RomBuffer; 
  size_t size = sizeof(g_RomBuffer);
  
  if( NULL == buffer || size < sizeof(sTableHeaderCRC_t) ) 
  {      
      return false;
  }
  
  g_RomBuffer_Cache = RomBufCache_undefined;

  // Посчитать crc данных в таблице
  TCRC dataCrc;
  dataCrc = ICRC32;
  for(int i = 0; i < hdrcrc->Hdr.blocks; i++)
  {
      size_t baseAddr = NFMBASE_FLASH_MAKEREALADDRESS( NFMClassExtended->
                                                        private.properties.memProfile->
                            BaseAddr_Table[ (eChValues%eChValues_MAX) ] + i * hdrcrc->Hdr.size );
      sTableTablePoint_t TablePoint;
      romGetDataPoint( baseAddr, (uint8_t *)&TablePoint, sizeof(sTableTablePoint_t) );
      dataCrc = CRC32( dataCrc, (const unsigned char*)&TablePoint, sizeof(sTableTablePoint_t) ); 
  }
  
  // Считаем crc хидера
  TCRC crc;
  crc = ICRC32;
  crc = CRC32( crc, (const unsigned char*)hdrcrc, sizeof(sTableHeader_t) ); 
  hdrcrc->CRCValue = crc;

  hdrcrc = romSetTableHeader( (uint8_t *)hdrcrc, sizeof(sTableHeaderCRC_t) );
  
  if( !SW_Validate_Table_Header_CRC( hdrcrc ) )
  {    
      // invalid common header
      // so, create new common header
      hdrcrc = (sTableHeaderCRC_t*)buffer;
      memset(hdrcrc, 0x00, sizeof(sTableHeaderCRC_t));
      return false;
  }

  return true;
}

uint16_t SW_ROM_GetNumberOfPoints()
{
    sTableHeaderCRC_t * TableHeader = SW_ROM_GetTableHeader();
    
    if( NULL == TableHeader)
    {
        return 0;
    }
    
    return SW_Validate_Table_Header_CRC( TableHeader ) ? TableHeader->Hdr.blocks : 0;
}
// ------------------------------------------------------------------------------
// - Table Data functions -------------------------------------------------------
// ------------------------------------------------------------------------------
// ------------------------------------------------------------------------------
bool SW_ROM_SetDataPoint ( eChunks_t tableId, sTableTablePoint_t * TablePoint )
{
    extern NFMClassEx_t * NFMClassExtended;
    if(NULL == TablePoint ||
       NULL == NFMClassExtended->private.properties.memProfile)
    {
        return false;
    }
    
    sTableHeaderCRC_t * TableHeader = SW_ROM_GetTableHeader();
    
    if( NULL == TableHeader)
    {
        return false;
    }
    
//    if( !SW_Validate_Table_Header_CRC( TableHeader ) )
//    {
//        memset(TableHeader, 0x00, sizeof(sTableHeaderCRC_t));
//        SW_ROM_ChangeTableHeader( TableHeader );
//        return false;
//    }
    
    size_t baseAddr = NFMBASE_FLASH_MAKEREALADDRESS( NFMClassExtended->
                                                    private.properties.memProfile->
                        BaseAddr_Table[ (tableId%eChValues_MAX) ] + TableHeader->Hdr.size );
    romSetDataPoint( baseAddr, (uint8_t *)TablePoint, sizeof(sTableTablePoint_t) );
    TableHeader->Hdr.blocks++;
    TableHeader->Hdr.size = TableHeader->Hdr.blocks * sizeof(sTableTablePoint_t);
    
    if( !SW_ROM_ChangeTableHeader( TableHeader ) )
    {
        return false;
    }
    
    return true;
}

const bool SW_ROM_GetDataPoint( eChunks_t tableId, uint8_t point_number, uint8_t * buffer, size_t size )
{
  extern NFMClassEx_t * NFMClassExtended;
  
  sTableTablePoint_t * TablePoint;
  bool cacheUsed = false;
  size_t baseAddr = 0;
  
  eRomBufCache_t cacheId = RomBufCache_undefined;
  
  if( NULL == buffer ) 
  { 
      cacheUsed = true;
      
      if( cacheId == g_RomBuffer_Cache && RomBufCache_undefined != g_RomBuffer_Cache )
      {
          TablePoint = (sTableTablePoint_t*)g_RomBuffer;
          goto L_NFM_ROM_GetDataHeader_AlreadyCached;
      }
      
      buffer = (uint8_t*)g_RomBuffer; 
      size = sizeof(g_RomBuffer); 
  }
  
  if( NULL == NFMClassExtended->private.properties.memProfile )
  {  
      return NULL;
  }
  
  baseAddr = NFMBASE_FLASH_MAKEREALADDRESS( NFMClassExtended->
               private.properties.memProfile->
                  BaseAddr_Table[ (tableId%eChValues_MAX) ] + point_number * sizeof(sTableTablePoint_t) ); 

  if( NULL == buffer || size < sizeof(sTableTablePoint_t) ) 
  {
      return NULL;
  }  

  if( cacheUsed )
  {  
      g_RomBuffer_Cache = RomBufCache_undefined;
  }  

  // Проверка на доступность значения во flash
  sTableHeaderCRC_t * TableHeader = SW_ROM_GetTableHeader();
  if( point_number >= TableHeader->Hdr.blocks ||
       !SW_Validate_Table_Header_CRC( TableHeader ) )
  {
      memset(TableHeader, 0x00, sizeof(sTableHeaderCRC_t));
      SW_ROM_ChangeTableHeader( TableHeader );
      return false;
  }
    
  if( NULL == TableHeader ||
     point_number >= TableHeader->Hdr.blocks)
  {
      return false;
  } 
  
  TablePoint = romGetDataPoint( baseAddr, buffer, size );

  if( NULL == TablePoint )
  {
      return NULL;
  }    

  if( cacheUsed )
  {
      g_RomBuffer_Cache = cacheId;
  }
  
L_NFM_ROM_GetDataHeader_AlreadyCached:
  
  return true;
}

uint32_t SW_ROM_Get_Table_crc( eChunks_t tableId )
{
    sTableHeaderCRC_t * TableHeader = SW_ROM_GetTableHeader();
    
    if( NULL == TableHeader)
    {
        return NULL;
    }
    
    TCRC crc;
    crc = ICRC32;
    sTableTablePoint_t TablePoint;
    
    for(int i = 0; i < TableHeader->Hdr.blocks; i++)
    {
        SW_ROM_GetDataPoint( tableId, i, (uint8_t *)&TablePoint, sizeof(sTableTablePoint_t) );
        crc = CRC32( crc, (const unsigned char*)&TablePoint, sizeof(sTableTablePoint_t) );
    }
    
    return crc;
}

bool SW_ROM_Set_Table_crc ( uint32_t crc )
{
    sTableHeaderCRC_t * TableHeader = SW_ROM_GetTableHeader();
    
    if( NULL == TableHeader)
    {
        return false;
    }
    TableHeader->table_crc = crc;
    TableHeader = romSetTableHeader( (uint8_t *)TableHeader, sizeof(sTableHeaderCRC_t) );
    if( NULL == TableHeader)
    {
        return false;
    }
    return true;
}

bool SW_ROM_Check_Table_crc()
{
    sTableHeaderCRC_t * TableHeader = SW_ROM_GetTableHeader();
    
    if( NULL == TableHeader)
    {
        return NULL;
    }
    
    uint32_t crc = SW_ROM_Get_Table_crc( eChValues );
    
    return TableHeader->table_crc == crc;
}

bool SW_ROM_Table_Clear()
{
    sTableHeaderCRC_t * TableHeader = SW_ROM_GetTableHeader();
    
    if( NULL == TableHeader)
    {
        return false;
    }
    memset(TableHeader, 0x00, sizeof(sTableHeaderCRC_t) );
    TableHeader = romSetTableHeader( (uint8_t *)TableHeader, sizeof(sTableHeaderCRC_t) );
    if( NULL == TableHeader)
    {
        return false;
    }
    return true;
}
// ------------------------------------------------------------------------------
// ------------------------------------------------------------------------------
// ------------------------------------------------------------------------------
static sEcalHeaderCRC_t * romSetCommonHeader( uint8_t * buffer, size_t size )
{
  if( NULL == buffer || size < sizeof(sEcalHeaderCRC_t) ) 
    return NULL;

  /*
  size_t baseAddr = FLASH_USERBANK_0_ADDR;

         baseAddr += MEMORY_OFFSET_BLOCK_COMMON;
  */
  size_t baseAddr = NFMBASE_FLASH_MAKEREALADDRESS( NFMBASE_FLASH_MAKEADDRESS_USERBANK0( MEMORY_OFFSET_BLOCK_COMMON ) );
  
  if( FLASH_SUCCESS( flash_write( baseAddr, buffer, sizeof(sEcalHeaderCRC_t), fwm_safewrite ) ) )
  {
      return (sEcalHeaderCRC_t*)buffer;
  }

  return NULL;
}
// ------------------------------------------------------------------------------
bool NFM_ROM_ChangeModel( eNFMModel_t modelId )
{
  sEcalHeaderCRC_t * hdrcrc;
  TCRC crc;

  uint8_t * buffer = (uint8_t*)g_RomBuffer; 
  size_t size = sizeof(g_RomBuffer);
  
  if( NULL == buffer || size < sizeof(sEcalHeaderCRC_t) ) 
  {      
      return false;
  }
  
  g_RomBuffer_Cache = RomBufCache_undefined;
  
  hdrcrc = romGetCommonHeader( buffer, size );

  if( NULL == hdrcrc )
  {    
      // invalid common header
      // so, create new common header
      hdrcrc = (sEcalHeaderCRC_t*)buffer;
      
      memset( hdrcrc->Hdr.SN, '0', sizeof(hdrcrc->Hdr.SN) );
      memset( hdrcrc->Hdr.Reserved1, 0, sizeof(hdrcrc->Hdr.Reserved1) );
      memset( hdrcrc->Hdr.Reserved2, 0, sizeof(hdrcrc->Hdr.Reserved2) );
  }  
  
  hdrcrc->Hdr.DeviceID = (uint8_t)modelId;

  crc = ICRC32;

  crc = CRC32( crc, (const unsigned char*)hdrcrc, sizeof(sEcalHeader_t) ); 

  hdrcrc->CRCValue = crc;
  
  hdrcrc = romSetCommonHeader( buffer, size );
  
  if( NULL == hdrcrc )
  {
      return false;
  }

  return true;
}

//// ------------------------------------------------------------------------------
bool NFM_ROM_ChangeSerialNumber( const char * serial )
{
  sEcalHeaderCRC_t * hdrcrc;
  TCRC crc;

  uint8_t * buffer = (uint8_t*)g_RomBuffer; 
  size_t size = sizeof(g_RomBuffer);
  
  if( NULL == buffer || size < sizeof(sEcalHeaderCRC_t) ) 
  {      
      return false;
  }
  
  g_RomBuffer_Cache = RomBufCache_undefined;
  
  hdrcrc = romGetCommonHeader( buffer, size );

  if( NULL == hdrcrc )
  {    
      // invalid common header
      // so, create new common header
      hdrcrc = (sEcalHeaderCRC_t*)buffer;
      
      memset( hdrcrc->Hdr.SN, '0', sizeof(hdrcrc->Hdr.SN) );
      memset( hdrcrc->Hdr.Reserved1, 0, sizeof(hdrcrc->Hdr.Reserved1) );
      memset( hdrcrc->Hdr.Reserved2, 0, sizeof(hdrcrc->Hdr.Reserved2) );
  }  
  
  memcpy(hdrcrc->Hdr.SN, serial, sizeof(hdrcrc->Hdr.SN));

  crc = ICRC32;

  crc = CRC32( crc, (const unsigned char*)hdrcrc, sizeof(sEcalHeader_t) ); 

  hdrcrc->CRCValue = crc;
  
  hdrcrc = romSetCommonHeader( buffer, size );
  
  if( NULL == hdrcrc )
  {
      return false;
  }

  return true;
}
// ------------------------------------------------------------------------------
// ------------------------------------------------------------------------------
// ------------------------------------------------------------------------------
static sEcalTCompHeaderCRC_t * romGetTCompHeader( uint8_t * buffer, size_t size )
{
  extern NFMClassEx_t * NFMClassExtended;
  
  if( NULL == buffer || size < sizeof(sEcalTCompHeaderCRC_t) ) 
    return NULL;

  if( NULL == NFMClassExtended->private.properties.memProfile )
    return NULL;
  
//  size_t baseAddr = NFMBASE_FLASH_MAKEREALADDRESS( NFMClassExtended->private.properties.memProfile->BaseAddr_TComp );
//  
//  if( FLASH_SUCCESS( flash_read( baseAddr, buffer, sizeof(sEcalTCompHeaderCRC_t) ) ) )
//  {
//      return (sEcalTCompHeaderCRC_t*)buffer;
//  }
  
  return NULL;
}
// ------------------------------------------------------------------------------
const sEcalTCompHeader_t * NFM_ROM_GetTCompHeader( uint8_t * buffer, size_t size )
{
  sEcalTCompHeaderCRC_t * hdrcrc;
  TCRC crc;
  bool cacheUsed = false;
  
  if( NULL == buffer ) 
  { 
      cacheUsed = true;
      
      if( RomBufCache_TCompHeader == g_RomBuffer_Cache )
      {
          hdrcrc = (sEcalTCompHeaderCRC_t*)g_RomBuffer;
          goto L_NFM_ROM_GetTCompHeader_AlreadyCached;
      }
      
      buffer = (uint8_t*)g_RomBuffer; 
      size = sizeof(g_RomBuffer);       
  }

  if( NULL == buffer || size < sizeof(sEcalTCompHeaderCRC_t) ) 
  {
      return NULL;
  }    

  if( cacheUsed )
  {  
      g_RomBuffer_Cache = RomBufCache_undefined;
  }  
  
  hdrcrc = romGetTCompHeader( buffer, size );

  if( NULL == hdrcrc )
  {
      return NULL;
  }    

  crc = ICRC32;

  crc = CRC32( crc, (const unsigned char*)hdrcrc, sizeof(sEcalTCompHeader_t) ); 

  if( crc != hdrcrc->CRCValue )
  {
      return NULL;
  }   
  
  if( cacheUsed )
  {
      g_RomBuffer_Cache = RomBufCache_TCompHeader;
  }

L_NFM_ROM_GetTCompHeader_AlreadyCached:
  return (sEcalTCompHeader_t *)hdrcrc;
}
// ------------------------------------------------------------------------------
// ------------------------------------------------------------------------------
// ------------------------------------------------------------------------------
size_t NFM_ROM_GetChrzTableIndex( ePortComb_t portCombination, ePortStateId_t portState )
{
//    extern NFMClassEx_t * NFMClassExtended;
//    
//    if(    ePortComb_MAX <= portCombination
//        || ePortComb_UNDEFINED == portCombination
//        || ePortStateId_MAX <= portState
//        || ePortStateId_UNDEFINED == portState
//      )    
//    {
//        return (NFM_CHRZ_TABLEIDX_INVALID);
//    }
//    
//    if( 
//         NULL == NFMClassExtended->private.properties.memProfile
//      || NULL == NFMClassExtended->private.properties.memProfile->tbls_raw )
//    {
//        return (NFM_CHRZ_TABLEIDX_INVALID);
//    }
//           
//    const sNFMMemory_ChrzTableMatrix_XPort_t * tableProfile_XPort = NFMClassExtended->private.properties.memProfile->tbls_raw;
//    const sNFMMemory_ChrzTableMatrix_2Port_t * tableProfile_2Port = NFMClassExtended->private.properties.memProfile->tbls_2Port;
//    const sNFMMemory_ChrzTableMatrix_4Port_t * tableProfile_4Port = NFMClassExtended->private.properties.memProfile->tbls_4Port;
//    
//    if(   ePortComb_MIN_SINGLE_XPort <= portCombination
//       && ePortComb_MAX_SINGLE_XPort >= portCombination )
//    {
//        switch(tableProfile_XPort->Header.ChrzTableType.eType)
//        {
//            case eNfmChrzTable2Port:
//            {
//                if(   ePortComb_MIN_SINGLE_2Port <= portCombination
//                   && ePortComb_MAX_SINGLE_2Port >= portCombination )
//                {
//                   if(   ePortStateId_MIN_SINGLE_2Port <= portState
//                      && ePortStateId_MAX_SINGLE_2Port >= portState )
//                   {
//                                  return tableProfile_2Port->Single.aArray[ 
//                                    (size_t)(portCombination - ePortComb_MIN_SINGLE_2Port) 
//                      ].aBaseIndex [
//                                    (size_t)(portState - ePortStateId_MIN_SINGLE_2Port)
//                      ];
//                   }
//                }
//            }
//            break;
//            case eNfmChrzTable4Port:
//            {
//                if(   ePortComb_MIN_SINGLE_4Port <= portCombination
//                   && ePortComb_MAX_SINGLE_4Port >= portCombination )
//                {
//                   if(   ePortStateId_MIN_SINGLE_4Port <= portState
//                      && ePortStateId_MAX_SINGLE_4Port >= portState )
//                   {
//                      return tableProfile_4Port->Single.aArray[ 
//                        (size_t)(portCombination - ePortComb_MIN_SINGLE_4Port) 
//                      ].aBaseIndex [
//                        (size_t)(portState - ePortStateId_MIN_SINGLE_4Port)
//                      ];
//                   }
//                }
//            }
//            break;
//        }
//        
//        return 0; // unsupported characterization table type
//    }
//    else
//    if(   ePortComb_MIN_THRU_XPort <= portCombination
//       && ePortComb_MAX_THRU_XPort >= portCombination )
//    {
//        switch(tableProfile_XPort->Header.ChrzTableType.eType)
//        {
//            case eNfmChrzTable2Port:
//            {
//               if(   ePortComb_MIN_THRU_2Port <= portCombination
//                  && ePortComb_MAX_THRU_2Port >= portCombination )
//               {
//                   if(   ePortStateId_MIN_THRU_2Port <= portState
//                      && ePortStateId_MAX_THRU_2Port >= portState )
//                   {
//                       return tableProfile_2Port->Thru.aArrays[
//                         (size_t)(portCombination - ePortComb_MIN_THRU_2Port) 
//                       ].aBaseIndex [
//                         (size_t)(portState - ePortStateId_MIN_THRU_2Port)
//                       ];
//                   }
//               }
//            }
//            break;
//            case eNfmChrzTable4Port:
//            {
//               if(   ePortComb_MIN_THRU_4Port <= portCombination
//                  && ePortComb_MAX_THRU_4Port >= portCombination )
//               {
//                   if(   ePortStateId_MIN_THRU_4Port <= portState
//                      && ePortStateId_MAX_THRU_4Port >= portState )
//                   {
//                       return tableProfile_4Port->Thru.aArrays[
//                         (size_t)(portCombination - ePortComb_MIN_THRU_4Port) 
//                       ].aBaseIndex [
//                         (size_t)(portState - ePortStateId_MIN_THRU_4Port)
//                       ];    
//                   }
//               }  
//            }
//            break;
//        }
//        
//        return 0; // unsupported characterization table type
//    }  
//    else
//    if( ePortComb_CHECK == portCombination )
//    {
//       if(   ePortStateId_MIN_CHECK_XPort <= portState
//          && ePortStateId_MAX_CHECK_XPort >= portState )
//       {
//          switch(tableProfile_XPort->Header.ChrzTableType.eType)
//          {
//              case eNfmChrzTable2Port:
//              {
//                 if(   ePortStateId_MIN_CHECK_2Port <= portState
//                    && ePortStateId_MAX_CHECK_2Port >= portState )
//                 {
//                        return tableProfile_2Port->Check.sArray
//                          .aBaseIndex[ 
//                          (size_t)(portState - ePortStateId_MIN_CHECK_2Port)
//                        ];
//                 }
//              }
//              break;
//              case eNfmChrzTable4Port:
//              {
//                 if(   ePortStateId_MIN_CHECK_4Port <= portState
//                    && ePortStateId_MAX_CHECK_4Port >= portState )
//                 {
//                        return tableProfile_4Port->Check.sArray
//                          .aBaseIndex[ 
//                          (size_t)(portState - ePortStateId_MIN_CHECK_4Port)
//                        ];    
//                 }
//              } 
//              break;
//          }
//          
//          return 0; // unsupported characterization table type
//       }
//    } 
    
    return (NFM_CHRZ_TABLEIDX_INVALID);
}

size_t NFM_ROM_GetTCompTableIndex( ePortComb_t portCombination, ePortStateId_t portState )
{
    extern NFMClassEx_t * NFMClassExtended;
    
    return NFMClassExtended->private.methods.memory.getChrzTableIndex( portCombination, portState );
}
// ------------------------------------------------------------------------------
// ------------------------------------------------------------------------------
// ------------------------------------------------------------------------------
// NFM_ROM_ReadChrzTableHeader:
// Reads the characterization table header by port combination (e.g. A,B, CD, CHECK),
// the port state (LOAD, SHORT, S11...), amount of points in the table (@nPoints) and
// the sector identifier (@sectorId).
// The amount of points must be retrieved before the call and passed into the function.
// You can use NFM_ROM_GetDataHeader() for this purpose.
// The table will be validated by calculating CRC.
// The function returns the base address of the table only in case
// all the conditions listed below are valid:
// - current device model has valid memory profile;
// - tableIdx is valid and not exceed the maximum table index for current memory profile;
// - nPoints is non-zero;
// - pHeader is non-NULL;
// - talbe has valid CRC;
// Otherwise, the function returns 0.
size_t NFM_ROM_ReadChrzTableHeader(   eChrz_t sectorId,
                                      ePortComb_t portCombination, 
                                      ePortStateId_t portState,
                                      size_t nPoints,   // @nPoints = amount of points in the table
                                      sEcalChrzTableHeader_t * pHeader,
                                      unsigned int * pErrCode
                                  )
{
   extern NFMClassEx_t * NFMClassExtended;
   
//   size_t tableIdx = NFM_CHRZ_TABLEIDX_INVALID;
//   
//   if( 
//         NULL == NFMClassExtended->private.properties.memProfile
//      || NULL == NFMClassExtended->private.properties.memProfile->tbls_raw
//      || NULL == pHeader
//      || 0 == nPoints 
//      || NULL == pErrCode  
//     )
//   {
//       if( NULL != pErrCode )
//           *pErrCode = ERR_NFMGETPOINTS_INVAL;
//             
//       // Invalid parameters or model properties
//       return 0;
//   }
//   
//   /*
//   const sNFMMemory_ChrzTableMatrix_XPort_t * tableProfile = NFMClassExtended->private.properties->memProfile->tbls_raw;
//
//   if( tableIdx > tableProfile->Header.maxTableIdx )
//   {
//       // invalid table index
//       return 0;
//   }      
//   */
//         
//   // Validate the combination of @portCombination, @portState and
//   // validate the @portCombination and @portState itself.
//   // Retrieve the table index (ordered index)   
//   tableIdx = NFMClassExtended->private.methods.memory.getChrzTableIndex( portCombination, portState );
//   
//   if( NFM_CHRZ_TABLEIDX_INVALID == tableIdx )
//   {       
//       *pErrCode = ERR_NFMGETPOINTS_INVAL;
//       
//       // Invalid combination or value
//       return 0;
//   }
//   
//   // Retireve the table index offset
//   size_t tableOffset = NFM_CHRZ_TABLEIDX_2_OFFSET( tableIdx );
//   
//   // Calculate the table offset
//   tableOffset *= SIZE_CHRZ_TABLE( nPoints );
//   
//   // shift the offset by the characterization main header
//   tableOffset += SIZE_CHRZ_HEADER;
//   
//   // add the base address of characterization sector to the table offset
//   // to get absolute address
//   tableOffset += NFMBASE_FLASH_MAKEREALADDRESS( NFMClassExtended->
//                   private.properties.memProfile->
//                     BaseAddr_Chrz[ (sectorId%eCh_MAX) ] ); 
//   
//   // Validate the table
//   {
//      // use internal buffer
//      g_RomBuffer_Cache = RomBufCache_undefined;
//      
//      size_t nBytes = SIZE_CHRZ_TABLE( nPoints ) - SIZE_CHRZ_TCRC;
//      size_t baseAddr = tableOffset;
//      
//      uint8_t * buffer = g_RomBuffer;
//      size_t bufferSize = sizeof(g_RomBuffer);
//      
//      TCRC crc = ICRC32;
//      
//      while( nBytes > 0 )
//      {
//          if( bufferSize > nBytes )
//          {
//              bufferSize = nBytes;
//          }
//          
//          if( ! FLASH_SUCCESS( flash_read( baseAddr, buffer, bufferSize ) ) )
//          {
//              *pErrCode = ERR_NFMGETPOINTS_IO;
//              
//              // i/o error
//              return 0;
//          }
//        
//          baseAddr += bufferSize;
//          nBytes -= bufferSize;
//          
//          crc = CRC32( crc, buffer, bufferSize ); 
//      }
//      
//      if( ! FLASH_SUCCESS( flash_read( baseAddr, buffer, SIZE_CHRZ_TCRC ) ) )
//      {
//          *pErrCode = ERR_NFMGETPOINTS_IO;
//          
//          // i/o error
//          return 0;
//      }
//      else if( *((TCRC*)buffer) != crc )
//      {
//          *pErrCode = ERR_NFMGETPOINTS_INVTBL;
//          
//          // crc error
//          return 0;
//      }
//   }
//   
//   // actually read the header
//   if( ! FLASH_SUCCESS( flash_read( tableOffset, (uint8_t*)pHeader, SIZE_CHRZ_THDR ) ) )
//   {
//       *pErrCode = ERR_NFMGETPOINTS_IO;
//       
//       // i/o error
//       return 0;
//   }
//   
//   *pErrCode = ERR_NFMGETPOINTS_NOERR;
//   
//   return tableOffset;
   return 0;
}
// ------------------------------------------------------------------------------
// ------------------------------------------------------------------------------
// ------------------------------------------------------------------------------
// NFM_ROM_ReadChrzTablePoints:
// Loads the characterization data points from the memory.
// The input parameters - only @pContext, which contains all required information:
// - @.TableAddress = depends on the selected memory segment and the selected table
// - @.nCount = amount of points to load
// - @.nStartPoint = the offset in "points" of starting point
// - @.pDataArray = the memory buffer to fill with the data
// Note: this structure must be initialized firstly by @NFM_ROM_ReadChrzTableHeader()
// call (aka @NFMClassExtended->private.methods.memory.getChrzTableHeader() )
size_t NFM_ROM_ReadChrzTablePoints( /*const*/ sNFMGetPoints_t * pContext )
{
   // check the input parameters
   if(    NULL == pContext
       || 0 == pContext->in.nCount
       || NULL == pContext->in.pDataArray
       || 0 == pContext->out.nPoints
       || 0 == pContext->out.TableAddress )
   {
       if( NULL != pContext )
           pContext->svc.errCode = ERR_NFMGETPOINTS_INVAL;
         
       return 0; // error
   }
   
   // initialize the first requested point offset
   size_t  
   //  by the table address
   pointOffset  = pContext->out.TableAddress;     
   //  and shift it by the table header size  
   pointOffset += SIZE_CHRZ_THDR;   
   //  and shift it by the size of skipped points
   pointOffset += pContext->in.nStartPoint * SIZE_CHRZ_TPNT;
   
   // use internal buffer
   g_RomBuffer_Cache = RomBufCache_undefined;
   
   // read the points contineously
   for( size_t n = 0; n < pContext->in.nCount; (void)n )
   {
        // calculate amount of points available to be cached
        size_t nPointsRead = sizeof(g_RomBuffer) / SIZE_CHRZ_TPNT;
        
        // limit amount of points to be read by the number of required points
        if( nPointsRead > (pContext->in.nCount-n) )
        {
            nPointsRead = (pContext->in.nCount-n);
        }
        
        // actually read the points
        if( ! FLASH_SUCCESS( flash_read(            // Read the points
               pointOffset,                                 //  with the specified offset of current point
               g_RomBuffer,                                 //   into the internal buffer,
               nPointsRead * SIZE_CHRZ_TPNT                 //    and read only @nPointsRead points
              )) 
          )
        {
            pContext->svc.errCode = ERR_NFMGETPOINTS_IO;
            // i/o error
            return 0;
        }
        
        // cast the buffer @g_RomBuffer to the [sEcalChrzTablePoint_t] array
        const sEcalChrzTablePoint_t * pComplexPoints = (sEcalChrzTablePoint_t*)g_RomBuffer;
                
        // Convert each of @nPointsRead data points from 24-bit format into the double format        
        for( size_t iPoint = 0; iPoint < nPointsRead; ++iPoint )
        {
            // magnitude
            {
                int32_t data24bit;  // 24-bit value in the memory is signed value
                
                {
                    uint32_t U_data24bit; 
                    // Retrieve the 24-bit data of magnitude
                    U_data24bit  = ((uint32_t)pComplexPoints[iPoint].Magn)  <<  0;  // low 16-bits
                    U_data24bit |= ((uint32_t)pComplexPoints[iPoint].Magn2) << 16;  // high 8-bits
                    
                    // check the sign bit
                    if( U_data24bit & (1<<23) )
                    {
                        // negative value
                        U_data24bit ^= 0xFFFFFF;
                        U_data24bit += 0x000001;
                        
                        // convert to signed variable
                        data24bit = -((int32_t)U_data24bit);
                    }                    
                    else
                    {                        
                        // positive value
                      
                        // convert to signed variable
                        data24bit = ((int32_t)U_data24bit);
                    }
                }
                
                // Convert the 24-bit data into the double
                // 24-bit data is amount of descrettes of ((max-min)/16777215)
                // where @min and @max is a magintude value in 0.01dB discrettes
                
              //#define MAGN24_2_DOUBLE(data24bit,min,max) (((data24bit) / (double)16777215.0f) * ((double)( (max) - (min) ) / (double)100.0f))
                #define MAGN24_2_DOUBLE(data24bit,min,max) ( (data24bit) * ((((double)( (max) - (min) )) / ((double)100.0)) / (double)16777215.0) + (((double)( (max) + (min) )) / 200.0))
                // store the result into the output double array
                pContext->in.pDataArray[ n + iPoint ].magn = MAGN24_2_DOUBLE( data24bit, pContext->out.min, pContext->out.max );
            } 
            
            // phase
            {
                int32_t data24bit = 0;  // 24-bit value in the memory is signed value
                
                {
                    uint32_t U_data24bit; 
                    // Retrieve the 24-bit data of phase
                    U_data24bit  = ((uint32_t)pComplexPoints[iPoint].Angle)  <<  0;  // low 16-bits
                    U_data24bit |= ((uint32_t)pComplexPoints[iPoint].Angle2) << 16;  // high 8-bits
                 
                    // check the sign bit
                    if( U_data24bit & (1<<23) )
                    {
                        // negative value
                        U_data24bit ^= 0xFFFFFF;
                        U_data24bit += 0x000001;
                        
                        // convert to signed variable
                        data24bit = -((int32_t)U_data24bit);
                    }
                    else
                    {                        
                        // positive value
                      
                        // convert to signed variable
                        data24bit = ((int32_t)U_data24bit);
                    }
                }
                // Convert the 24-bit data into the double
                // 24-bit data is amount of descrettes of (PI/0x7FFFFF)
                #define PI  (3.141592653589793238462643)
                #define R2D (180.0/PI)
                #define PHAS24_2_DOUBLE(data24bit) (((data24bit) / (double)8388607.0f) * (double)(PI))
                #define PHAS_RAD_2_DEG( rad ) ((rad)*(R2D))

                // store the result into the output double array
                pContext->in.pDataArray[ n + iPoint ].phase = PHAS_RAD_2_DEG(PHAS24_2_DOUBLE( data24bit ));
            }           
        }
        
        // decrease amount of points to read
        n += nPointsRead;
        
        // shift the address
        pointOffset += nPointsRead * SIZE_CHRZ_TPNT;
   }
   
   pContext->svc.errCode = ERR_NFMGETPOINTS_NOERR;
   
   // return amount of points
   return pContext->in.nCount;
}
// ------------------------------------------------------------------------------
// ------------------------------------------------------------------------------
// ------------------------------------------------------------------------------

// NFM_ROM_GetTCompMagnTableHeader:
// Reads the thermocompensation magnitude table header by port combination (e.g. A,B, CD, CHECK),
// the port state (LOAD, SHORT, S11...), amount of points in the table (@nPoints) and
// the sector identifier (@sectorId).
// The amount of points must be retrieved before the call and passed into the function.
// You can use NFM_ROM_GetTCompHeader() for this purpose.
// The table will be validated by calculating CRC.
// The function returns the base address of the table only in case
// all the conditions listed below are valid:
// - current device model has valid memory profile;
// - tableIdx is valid and not exceed the maximum table index for current memory profile;
// - nPoints is non-zero;
// - pHeader is non-NULL;
// - talbe has valid CRC;
// Otherwise, the function returns 0.
size_t NFM_ROM_GetTCompMagnTableHeader( ePortComb_t portCombination, ePortStateId_t portState,
                                        size_t nPoints, sEcalTCompTableMagnHeader_t * pHeader,
                                        unsigned int * pErrCode
                                      )
{
   extern NFMClassEx_t * NFMClassExtended;
   
   return 0;
//   size_t tableIdx = NFM_CHRZ_TABLEIDX_INVALID;
//   
//   if( 
//         NULL == NFMClassExtended->private.properties.memProfile
//      || NULL == NFMClassExtended->private.properties.memProfile->tbls_raw
//      || NULL == pHeader
//      || 0 == nPoints )
//   {
//       if( NULL != pErrCode )
//           *pErrCode = ERR_NFMGETPOINTS_INVAL;
//       
//       // Invalid parameters or model properties
//       return 0;
//   }
//   
//   /*
//   const sNFMMemory_ChrzTableMatrix_XPort_t * tableProfile = NFMClassExtended->private.properties->memProfile->tbls_raw;
//
//   if( tableIdx > tableProfile->Header.maxTableIdx )
//   {
//       // invalid table index
//       return 0;
//   }      
//   */
//         
//   // Validate the combination of @portCombination, @portState and
//   // validate the @portCombination and @portState itself.
//   // Retrieve the table index (ordered index)   
//   tableIdx = NFMClassExtended->private.methods.memory.getTCompTableIndex( portCombination, portState );
//   
//   if( NFM_CHRZ_TABLEIDX_INVALID == tableIdx )
//   {
//       *pErrCode = ERR_NFMGETPOINTS_INVAL;
//       
//       // Invalid combination or value
//       return 0;
//   }
//   
//   // Retireve the table index offset
//   size_t tableOffset = NFM_TCOMP_MAGN_TABLEIDX_2_OFFSET( tableIdx );
//   
//   // Calculate the table offset
//   tableOffset *= SIZE_TCOMP_MAGN_TABLE( nPoints );
//   
//   // shift the offset by the thermocompensation main header
//   tableOffset += SIZE_TCOMP_HEADER;
//   
//   // add the base address of thermocompensation sector to the table offset
//   // to get absolute address
//   tableOffset += NFMBASE_FLASH_MAKEREALADDRESS( NFMClassExtended->
//                   private.properties.memProfile->
//                     BaseAddr_TComp ); 
//   
//   // Validate the table
//   {
//      // use internal buffer
//      g_RomBuffer_Cache = RomBufCache_undefined;
//      
//      size_t nBytes = SIZE_TCOMP_MAGN_TABLE( nPoints ) - SIZE_TCOMP_TCRC;
//      size_t baseAddr = tableOffset;
//      
//      uint8_t * buffer = g_RomBuffer;
//      size_t bufferSize = sizeof(g_RomBuffer);
//      
//      TCRC crc = ICRC32;
//      
//      while( nBytes > 0 )
//      {
//          if( bufferSize > nBytes )
//          {
//              bufferSize = nBytes;
//          }
//          
//          if( ! FLASH_SUCCESS( flash_read( baseAddr, buffer, bufferSize ) ) )
//          {
//              *pErrCode = ERR_NFMGETPOINTS_IO;
//              
//              // i/o error
//              return 0;
//          }
//        
//          baseAddr += bufferSize;
//          nBytes -= bufferSize;
//          
//          crc = CRC32( crc, buffer, bufferSize ); 
//      }
//      
//      if( ! FLASH_SUCCESS( flash_read( baseAddr, buffer, SIZE_TCOMP_TCRC ) ) )
//      {
//          *pErrCode = ERR_NFMGETPOINTS_IO;
//          
//          // i/o error
//          return 0;
//      }
//      else if( *((TCRC*)buffer) != crc )
//      {
//          *pErrCode = ERR_NFMGETPOINTS_INVTBL;
//          
//          // crc error
//          return 0;
//      }
//   }
//   
//   // actually read the header
//   if( ! FLASH_SUCCESS( flash_read( tableOffset, (uint8_t*)pHeader, SIZE_TCOMP_MAGN_THDR ) ) )
//   {
//       *pErrCode = ERR_NFMGETPOINTS_IO;
//       
//       // i/o error
//       return 0;
//   }
//   
//   *pErrCode = ERR_NFMGETPOINTS_NOERR;
//   
//   return tableOffset;
}

// NFM_ROM_GetTCompPhaseTableHeader:
// Reads the thermocompensation phase table header by port combination (e.g. A,B, CD, CHECK),
// the port state (LOAD, SHORT, S11...), amount of points in the table (@nPoints) and
// the sector identifier (@sectorId).
// The amount of points must be retrieved before the call and passed into the function.
// You can use NFM_ROM_GetTCompHeader() for this purpose.
// The table will be validated by calculating CRC.
// The function returns the base address of the table only in case
// all the conditions listed below are valid:
// - current device model has valid memory profile;
// - tableIdx is valid and not exceed the maximum table index for current memory profile;
// - nPoints is non-zero;
// - pHeader is non-NULL;
// - talbe has valid CRC;
// Otherwise, the function returns 0.
size_t NFM_ROM_GetTCompPhaseTableHeader( ePortComb_t portCombination, ePortStateId_t portState,
                                        size_t nPoints, sEcalTCompTablePhaseHeader_t * pHeader,
                                        unsigned int * pErrCode
                                       )
{
   extern NFMClassEx_t * NFMClassExtended;
   
//   size_t tableIdx = NFM_CHRZ_TABLEIDX_INVALID;
//   
//   if( 
//         NULL == NFMClassExtended->private.properties.memProfile
//      || NULL == NFMClassExtended->private.properties.memProfile->tbls_raw
//      || NULL == pHeader
//      || 0 == nPoints 
//      || NULL == pErrCode  
//     )
//   {
//       if( NULL != pErrCode )
//           *pErrCode = ERR_NFMGETPOINTS_INVAL;
//       
//       // Invalid parameters or model properties
//       return 0;
//   }
//   
//   /*
//   const sNFMMemory_ChrzTableMatrix_XPort_t * tableProfile = NFMClassExtended->private.properties->memProfile->tbls_raw;
//
//   if( tableIdx > tableProfile->Header.maxTableIdx )
//   {
//       // invalid table index
//       return 0;
//   }      
//   */
//         
//   // Validate the combination of @portCombination, @portState and
//   // validate the @portCombination and @portState itself.
//   // Retrieve the table index (ordered index)   
//   tableIdx = NFMClassExtended->private.methods.memory.getTCompTableIndex( portCombination, portState );
//   
//   if( NFM_CHRZ_TABLEIDX_INVALID == tableIdx )
//   {
//       *pErrCode = ERR_NFMGETPOINTS_INVAL;
//       
//       // Invalid combination or value
//       return 0;
//   }
//   
//   // Retireve the table index offset
//   size_t tableOffset = NFM_TCOMP_PHASE_TABLEIDX_2_OFFSET( tableIdx );
//   
//   // Calculate the table offset
//   tableOffset *= SIZE_TCOMP_PHASE_TABLE( nPoints );
//   
//   // shift the offset by the thermocompensation main header
//   tableOffset += SIZE_TCOMP_HEADER;
//   
//   // add the base address of thermocompensation sector to the table offset
//   // to get absolute address
//   tableOffset += NFMBASE_FLASH_MAKEREALADDRESS( NFMClassExtended->
//                   private.properties.memProfile->
//                     BaseAddr_TComp ); 
//   
//   // Validate the table
//   {
//      // use internal buffer
//      g_RomBuffer_Cache = RomBufCache_undefined;
//      
//      size_t nBytes = SIZE_TCOMP_PHASE_TABLE( nPoints ) - SIZE_TCOMP_TCRC;
//      size_t baseAddr = tableOffset;
//      
//      uint8_t * buffer = g_RomBuffer;
//      size_t bufferSize = sizeof(g_RomBuffer);
//      
//      TCRC crc = ICRC32;
//      
//      while( nBytes > 0 )
//      {
//          if( bufferSize > nBytes )
//          {
//              bufferSize = nBytes;
//          }
//          
//          if( ! FLASH_SUCCESS( flash_read( baseAddr, buffer, bufferSize ) ) )
//          {
//              *pErrCode = ERR_NFMGETPOINTS_IO;
//              
//              // i/o error
//              return 0;
//          }
//        
//          baseAddr += bufferSize;
//          nBytes -= bufferSize;
//          
//          crc = CRC32( crc, buffer, bufferSize ); 
//      }
//      
//      if( ! FLASH_SUCCESS( flash_read( baseAddr, buffer, SIZE_TCOMP_TCRC ) ) )
//      {
//          *pErrCode = ERR_NFMGETPOINTS_IO;
//          
//          // i/o error
//          return 0;
//      }
//      else if( *((TCRC*)buffer) != crc )
//      {
//          *pErrCode = ERR_NFMGETPOINTS_INVTBL;
//          
//          // crc error
//          return 0;
//      }
//   }
//   
//   // actually read the header
//   if( ! FLASH_SUCCESS( flash_read( tableOffset, (uint8_t*)pHeader, SIZE_TCOMP_PHASE_THDR ) ) )
//   {
//       *pErrCode = ERR_NFMGETPOINTS_IO;
//       
//       // i/o error
//       return 0;
//   }
//   
//   *pErrCode = ERR_NFMGETPOINTS_NOERR;
//   
//   return tableOffset;
   return 0;
}
                                         
size_t NFM_ROM_GetTCompMagnPoints( /*const*/ sNFMGetPoints_t * pContext )
{
   // check the input parameters
   if(    NULL == pContext
       || 0 == pContext->in.nCount
       || NULL == pContext->in.pDataArray
       || 0 == pContext->out.nPoints
       || 0 == pContext->out.TableAddress )
   {
       if( NULL != pContext )
           pContext->svc.errCode = ERR_NFMGETPOINTS_INVAL;
       
       return 0; // error
   }
   
   // initialize the first requested point offset
   size_t  
   //  by the table address
   pointOffset  = pContext->out.TableAddress;     
   //  and shift it by the table header size  
   pointOffset += SIZE_TCOMP_MAGN_THDR;   
   //  and shift it by the size of skipped points
   pointOffset += pContext->in.nStartPoint * SIZE_TCOMP_MAGN_TPNT;
   
   // use internal buffer
   g_RomBuffer_Cache = RomBufCache_undefined;
   
   // read the points contineously
   for( size_t n = 0; n < pContext->in.nCount; (void)n )
   {
        // calculate amount of points available to be cached
        size_t nPointsRead = sizeof(g_RomBuffer) / SIZE_TCOMP_MAGN_TPNT;
        
        // limit amount of points to be read by the number of required points
        if( nPointsRead > (pContext->in.nCount-n) )
        {
            nPointsRead = (pContext->in.nCount-n);
        }
        
        // actually read the points
        if( ! FLASH_SUCCESS( flash_read(            // Read the points
               pointOffset,                                 //  with the specified offset of current point
               g_RomBuffer,                                 //   into the internal buffer,
               nPointsRead * SIZE_TCOMP_MAGN_TPNT           //    and read only @nPointsRead points
              )) 
          )
        {
            pContext->svc.errCode = ERR_NFMGETPOINTS_IO;
            
            // i/o error
            return 0;
        }
        
        // cast the buffer @g_RomBuffer to the [sEcalChrzTablePoint_t] array
        const sEcalTCompTableMagnPoint_t * pComplexPoints = (sEcalTCompTableMagnPoint_t*)g_RomBuffer;
        
      
        // Convert each of @nPointsRead data points from 24-bit format into the double format        
        for( size_t iPoint = 0; iPoint < nPointsRead; ++iPoint )
        {
            // thermocompensation magnitude
            {
                // Convert the 16-bit data into the double
                // 16-bit data is amount of descrettes of ((max-min)/65536)
                // where @min and @max is a magintude value in 0.01dB/C discrettes              
              
                double max = (double)(pContext->out.max) / 100.0;
                double min = (double)(pContext->out.min) / 100.0;
                double mean = (min + max) / 2.0;

                // Note: each point is signed 16-bit integer
                // store the result into the output double array
                pContext->in.pDataArray[ n + iPoint ].phase = 0; // not used
                pContext->in.pDataArray[ n + iPoint ].magn 
                  = mean + (double)pComplexPoints[iPoint].Magn * (max - min) / 65535.0;
            }
            /*
            {
                // Convert the 16-bit data into the double
                // 16-bit data is amount of descrettes of ((max-min)/65536)
                // where @min and @max is a magintude value in 0.01dB/C discrettes              
                #define MAGN16_DISCRETTE(min,max)    ((( (double)(max) - (double)(min) )) / ((double)6553500.0))
                #define MAGN16_MEAN(min,max)         ((( (double)(max) + (double)(min) )) / ((double)200.0))

                // Note: each point is signed 16-bit integer
                // store the result into the output double array
                pContext->in.pDataArray[ n + iPoint ].phase = 0; // not used
                pContext->in.pDataArray[ n + iPoint ].magn = 
                  MAGN16_MEAN( pContext->out.min, pContext->out.max ) +
                    ((double)(pComplexPoints[iPoint].Magn)) *
                      MAGN16_DISCRETTE( pContext->out.min, pContext->out.max );
            }
            */
        }
        
        // decrease amount of points to read
        n += nPointsRead;
        
        // shift the address
        pointOffset += nPointsRead * SIZE_TCOMP_MAGN_TPNT;
   }
   
   pContext->svc.errCode = ERR_NFMGETPOINTS_NOERR;
   
   // return amount of points
   return pContext->in.nCount;
}

size_t NFM_ROM_GetTCompPhasePoints( /*const*/ sNFMGetPoints_t * pContext )
{
   // check the input parameters
   if(    NULL == pContext
       || 0 == pContext->in.nCount
       || NULL == pContext->in.pDataArray
       || 0 == pContext->out.nPoints
       || 0 == pContext->out.TableAddress )
   {
       if( NULL != pContext )
           pContext->svc.errCode = ERR_NFMGETPOINTS_INVAL;
       
       return 0; // error
   }
   
   // initialize the first requested point offset
   size_t  
   //  by the table address
   pointOffset  = pContext->out.TableAddress;     
   //  and shift it by the table header size  
   pointOffset += SIZE_TCOMP_PHASE_THDR;   
   //  and shift it by the size of skipped points
   pointOffset += pContext->in.nStartPoint * SIZE_TCOMP_PHASE_TPNT;
   
   // use internal buffer
   g_RomBuffer_Cache = RomBufCache_undefined;
   
   // read the points contineously
   for( size_t n = 0; n < pContext->in.nCount; (void)n )
   {
        // calculate amount of points available to be cached
        size_t nPointsRead = sizeof(g_RomBuffer) / SIZE_TCOMP_PHASE_TPNT;
        
        // limit amount of points to be read by the number of required points
        if( nPointsRead > (pContext->in.nCount-n) )
        {
            nPointsRead = (pContext->in.nCount-n);
        }
        
        // actually read the points
        if( ! FLASH_SUCCESS( flash_read(            // Read the points
               pointOffset,                                 //  with the specified offset of current point
               g_RomBuffer,                                 //   into the internal buffer,
               nPointsRead * SIZE_TCOMP_PHASE_TPNT          //    and read only @nPointsRead points
              )) 
          )
        {
            pContext->svc.errCode = ERR_NFMGETPOINTS_IO;
            
            // i/o error
            return 0;
        }
        
        // cast the buffer @g_RomBuffer to the [sEcalChrzTablePoint_t] array
        const sEcalTCompTablePhasePoint_t * pComplexPoints = (sEcalTCompTablePhasePoint_t*)g_RomBuffer;
        
      
        // Convert each of @nPointsRead data points from 16-bit format into the double format        
        for( size_t iPoint = 0; iPoint < nPointsRead; ++iPoint )
        {
            // thermocompensation phase
            {
                // Convert the 16-bit data into the double
                // 16-bit data is amount of descrettes of ((max-min)/65536)
                // where @min and @max is a magintude value in 0.01deg/C discrettes
              
                double max = (double)(pContext->out.max) / 100.0;
                double min = (double)(pContext->out.min) / 100.0;
                double mean = (min + max) / 2.0;
                
                // Note: each point is signed 16-bit integer
                // store the result into the output double array
                pContext->in.pDataArray[ n + iPoint ].magn = 0; // not used
                pContext->in.pDataArray[ n + iPoint ].phase 
                  = mean + (double)(pComplexPoints[iPoint].Phase) * (max - min) / 65535.0;
            }
            /*
            {
                // Convert the 16-bit data into the double
                // 16-bit data is amount of descrettes of ((max-min)/65536)
                // where @min and @max is a magintude value in 0.01deg/C discrettes
              //#define PHASE16_DISCRETTE(min,max)    (((double)( (max) - (min) )) / ((double)6553500.0))
              //#define PHASE16_MEAN(min,max)         (((double)( (max) + (min) )) / ((double)200.0))
                #define PHASE16_DISCRETTE(min,max)    ((( (double)(max) - (double)(min) )) / ((double)6553500.0))
                #define PHASE16_MEAN(min,max)         ((( (double)(max) + (double)(min) )) / ((double)200.0))
                
                // Note: each point is signed 16-bit integer
                // store the result into the output double array
                pContext->in.pDataArray[ n + iPoint ].magn = 0; // not used
                pContext->in.pDataArray[ n + iPoint ].phase = 
                  PHASE16_MEAN( pContext->out.min, pContext->out.max ) +
                    ((double)(pComplexPoints[iPoint].Phase)) *
                      PHASE16_DISCRETTE( pContext->out.min, pContext->out.max );
            }
            */
        }
        
        // decrease amount of points to read
        n += nPointsRead;
        
        // shift the address
        pointOffset += nPointsRead * SIZE_TCOMP_PHASE_TPNT;
   }
   
   pContext->svc.errCode = ERR_NFMGETPOINTS_NOERR;
   
   // return amount of points
   return pContext->in.nCount;
}

size_t NFM_ROM_ReadDeviceSettings( uint8_t * buffer, size_t nOffset, size_t nBytesToRead )
{
  extern NFMClassEx_t * NFMClassExtended;
  const sSwitchMemoryProfile_t * memProfile = NFMClassExtended->private.properties.memProfile;
  
  if( NULL != NFMClassExtended->private.properties.memProfile )
  if( 0 < memProfile->Size_Settings )
  {
      if( (NULL != buffer) && (nOffset < memProfile->Size_Settings) && (0 < nBytesToRead) )
      {        
          size_t baseAddr = NFMBASE_FLASH_MAKEREALADDRESS( (nOffset) + NFMClassExtended->private.properties.memProfile->BaseAddr_Settings );
          
          if( FLASH_SUCCESS( flash_read( baseAddr, buffer, nBytesToRead ) ) )
          {
              return nBytesToRead;
          }
      }
  }

  return 0; // failed
}

size_t NFM_ROM_GetDeviceSettingsSize()
{
  extern NFMClassEx_t * NFMClassExtended;
  const sSwitchMemoryProfile_t * memProfile = NFMClassExtended->private.properties.memProfile;
  
  if( NULL != NFMClassExtended->private.properties.memProfile )
  {
      return memProfile->Size_Settings;
  }

  return 0; // failed
}

bool NFM_ROM_ValidateUserSettings()
{
    if( sizeof(sNFMSettingsBlockCrc_t) == NFM_ROM_GetDeviceSettingsSize() )
    {
        sNFMSettingsBlockCrc_t sSettingsBlock;

        if( NFM_ROM_ReadDeviceSettings( (uint8_t*)&sSettingsBlock,
                                       0,
                                       sizeof(sSettingsBlock) ) )
        {
            TCRC crc = ICRC32;
            crc = CRC32( crc, (uint8_t *)&sSettingsBlock.settings, sizeof(sSettingsBlock.settings));
            if(crc != sSettingsBlock.CRCValue)
            {
                return false;
            }
        }
    }
    else 
        return false;
    return true;
}

size_t NFM_ROM_WriteDeviceSettings( uint8_t * buffer, size_t nOffset, size_t nBytesToWrite )
{
  extern NFMClassEx_t * NFMClassExtended;
  const sSwitchMemoryProfile_t * memProfile = NFMClassExtended->private.properties.memProfile;
  
  if( NULL != NFMClassExtended->private.properties.memProfile )
  if( 0 < memProfile->Size_Settings )
  {
      if( (NULL != buffer) && (nOffset < memProfile->Size_Settings) && (0 < nBytesToWrite) )
      {        
          size_t baseAddr = NFMBASE_FLASH_MAKEREALADDRESS( (nOffset) + NFMClassExtended->private.properties.memProfile->BaseAddr_Settings );
          
          if( FLASH_SUCCESS( flash_write( baseAddr, buffer, nBytesToWrite, fwm_safewrite ) ) )
          {
              return nBytesToWrite;
          }
      }
  }

  return 0; // failed
}

//////
//////TECALTCOMPHEADERCRC  * __ROM_GetTermHeader( char * buffer, unsigned int buffersize, unsigned int address )
//////{
//////  if( buffer == NULL || buffersize < sizeof(TECALTCOMPHEADERCRC) ) return NULL;
//////
//////  //read_flash( address, buffer, sizeof(TECALTCOMPHEADERCRC) );
//////  BREAKPOINT;
//////  
//////  return (TECALTCOMPHEADERCRC*)buffer;
//////}
//////
//////// ------------------------------------------------------------------------------                                                              ------
//////
//////TECALTCOMPHEADER * ROM_GetTermHeader( char * buffer, unsigned int buffersize )
//////{
//////  char * recievebuffer = buffer;
//////
//////  //---------------------------------
//////  if( LastReadAddress != ROM_TERM_COMP_ADDR )  // пїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅ пїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ
//////          BufferChached = 0;  // пїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ
//////  else
//////          BufferChached = 1; // пїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅ пїЅпїЅпїЅ ROM SPI 
//////  //---------------------------------
//////  if( recievebuffer == NULL ) {   // пїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ ROMHeaderBuffer
//////          recievebuffer = (char*)&ROMHeaderBuffer; 
//////          buffersize = SPIROMHeaderBufferSize; // !!! пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ TECALTCOMPHEADERCRC !!!
//////          LastReadAddress = ROM_TERM_COMP_ADDR; 
//////  }  
//////  else 
//////  {  BufferChached = 0;  // пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ, пїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ, пїЅпїЅ пїЅпїЅпїЅпїЅпїЅ ROMHeaderBuffer
//////     if( INT(recievebuffer)%sizeof(unsigned int) ) return NULL; // not aligment . 
//////  }
//////  //---------------------------------
//////  /*- RET -*/if( recievebuffer == NULL || buffersize < sizeof(/*CRC*/TECALTCOMPHEADERCRC/*CRC*/) ) return NULL;
//////  //---------------------------------
//////  TECALTCOMPHEADERCRC * hdrcrc;
//////  if( BufferChached != 1 )  hdrcrc = __ROM_GetTermHeader(recievebuffer, buffersize, ROM_TERM_COMP_ADDR);
//////  else                      hdrcrc = (TECALTCOMPHEADERCRC *)recievebuffer; // !!! пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅ пїЅ пїЅпїЅпїЅпїЅпїЅпїЅ пїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ !!!
//////  //---------------------------------
//////  /*- RET -*/if(hdrcrc == NULL) return NULL;
//////  //---------------------------------
//////  TCRC crc = ICRC32; // пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ CRC32
//////  //---------------------------------
//////  crc = CRC32( crc, (unsigned char const *)hdrcrc, sizeof(TECALTCOMPHEADER)); 
//////  //---------------------------------
//////  if( crc == hdrcrc->CRCValue ) return (TECALTCOMPHEADER *)hdrcrc;
//////  else 
//////  {  if(BufferChached == 1) // пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅ RAM пїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ
//////     { LastReadAddress = 0xffffffff;
//////       return ROM_GetTermHeader( /*!!!*/buffer/*!!!*/, buffersize); // пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅ пїЅпїЅпїЅ, пїЅпїЅ пїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ
//////     } else return NULL;
//////  }                    
//////  //---------------------------------
//////}
//////
//////// ------------------------------------------------------------------------------
//////char * ROM_GetConnectorString( unsigned int ID )
//////{
//////   if(ID<=12)
//////    return (char*)Connector[ID];
//////   else
//////    return NULL;
//////}
//////
//////
//////TECALDATAHEADERCRC  * __ROM_GetHeader( char * buffer, unsigned int buffersize, unsigned int address )
//////{
//////  if( buffer == NULL || buffersize < sizeof(TECALDATAHEADERCRC) ) return NULL;
//////
//////  flash_read( address, buffer, sizeof(TECALDATAHEADERCRC) );  
//////  
//////  return (TECALDATAHEADERCRC*)buffer;
//////}
//////
//////// -------                                                                 ------
//////
//////TECALDATAHEADER * ROM_GetHeader( char * buffer, unsigned int buffersize, EROMHEADER HeaderID )
//////{
//////  char * recievebuffer = buffer;
//////
//////  if( ! ( HeaderID <= 5 ) ) return NULL;
//////
//////  //---------------------------------
//////  if( LastReadAddress != ROM_MAP[HeaderID] )  // пїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅ пїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ
//////          BufferChached = 0;  // пїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ
//////  else
//////          BufferChached = 1; // пїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅ пїЅпїЅпїЅ ROM SPI 
//////  //---------------------------------
//////  if( recievebuffer == NULL ) {   // пїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ ROMHeaderBuffer
//////          recievebuffer = (char*)&ROMHeaderBuffer; 
//////          buffersize = SPIROMHeaderBufferSize; // !!! пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ TECALDATAHEADERCRC !!!
//////          LastReadAddress = ROM_MAP[HeaderID]; 
//////  }  
//////  else 
//////  {  BufferChached = 0;  // пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ, пїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ, пїЅпїЅ пїЅпїЅпїЅпїЅпїЅ ROMHeaderBuffer
//////     if( INT(recievebuffer)%sizeof(unsigned int) ) return NULL; // not aligment . 
//////  }
//////  //---------------------------------
//////  /*- RET -*/if( recievebuffer == NULL || buffersize < sizeof(/*CRC*/TECALDATAHEADERCRC/*CRC*/) ) return NULL;
//////  //---------------------------------
//////  TECALDATAHEADERCRC * hdrcrc;
//////  if( BufferChached != 1 )  hdrcrc = __ROM_GetHeader(recievebuffer, buffersize, ROM_MAP[HeaderID]);
//////  else                      hdrcrc = (TECALDATAHEADERCRC *)recievebuffer; // !!! пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅ пїЅ пїЅпїЅпїЅпїЅпїЅпїЅ пїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ !!!
//////  //---------------------------------
//////  /*- RET -*/if(hdrcrc == NULL) return NULL;
//////  //---------------------------------
//////  TCRC crc = ICRC32; // пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ CRC32
//////  //---------------------------------
//////  crc = CRC32( crc, (unsigned char const *)hdrcrc, sizeof(TECALDATAHEADER)); 
//////  //---------------------------------
//////  if( crc == hdrcrc->CRCValue ) return (TECALDATAHEADER *)hdrcrc;
//////  else 
//////  {  if(BufferChached == 1) // пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅ RAM пїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ
//////     { LastReadAddress = 0xffffffff;
//////       return ROM_GetHeader( /*!!!*/buffer/*!!!*/, buffersize, HeaderID); // пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅ пїЅпїЅпїЅ, пїЅпїЅ пїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ
//////     } else return NULL;
//////  }                    
//////  //---------------------------------
//////}
////////
//////
//////
//////// ######################################################################################################################################
//////// ######################################################################################################################################
//////unsigned int ROM_GetStartAddress( EROMHEADER HeaderID )
//////{
//////  return ROM_MAP[HeaderID] + sizeof(TECALDATAHEADERCRC);
//////}
//////
//////BOOL ROM_GetArray( TGETARRAYIN  * stGetArrayParameters, TGETARRAYOUT * stoutArrayParams  )
//////{
////////      
////////(dwStartAddress)            
////////*----------->|              (CHARACTERIZATION_)
////////             |             /
////////         --->|--------|<--+
////////             |        |   
//////// +-----------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
//////// |   BLOCK   | BLOCK  |        |        |        |        |        |        |        |        |        |        |
//////// |   HEADER  |  CRC   |  SH_A  |  SH_B  |  OP_A  |  OP_B  |  LD_A  |  LD_B  |  T_11  |  T_21  |  T_12  |  T_22  |
//////// | F/U1/../U5| F/./U5 |        |        |        |        |        |        |        |        |        |        |
//////// +-----------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
////////                     /          \
////////                    /            \
////////                   /              \
////////                  /                \
////////                 /                  \
////////                /                    \
////////               /                      \
////////              /      -ARRAY-           \
////////             /                          \
////////            +-------+------------+-------+
////////            | mindB |      N     |       |
////////            |       |...POINTS...|  CRC  |
////////            | maxdB |            |ARRAY  |
////////            +-------+------------+-------+
////////         
//////
//////// IN: TGETARRAYIN                         OUT: TGETARRAYOUT
///////*char * buffer;                           
//////  unsigned int buffersize;                 FIRSTPOINT FirstPoint;
//////  // --------------------                  --------------------
//////  unsigned int nMaxPoints;                 unsigned int   dwPointsAddress;       
//////  // ---------------------                 unsigned int   dwArrayCRC;
//////  unsigned int Version;                    void  *        pPoints;
//////  // ---------------------
//////  EPORT port;
//////  ESTATE state;
//////  // ---------------------
//////  unsigned int startaddress;*/
//////  //---------------------------------------------------------------------------------------------------------------------------------------
//////  if( stGetArrayParameters == NULL || stoutArrayParams == NULL) return NULL;
//////  //---------------------------------------------------------------------------------------------------------------------------------------
//////  unsigned int ps;
//////  unsigned int as;
//////  unsigned int of/*, rd*/;
//////  unsigned int adr_crc;
//////  unsigned int adr_points;
//////  unsigned int adr_minmax;
//////  char * data = stGetArrayParameters->buffer;
//////
//////  if( (stGetArrayParameters->cFlags & (1<<0)) == 0 ) // get characterization array
//////  {
//////    ps = POINTSIZE;   
///////*
//////    as = CHARACTERIZATION_ARRAY_SIZE(stGetArrayParameters->nMaxPoints,ps);
//////*/ 
//////    as = CHARACTERIZATION_TABLE_SIZE( stGetArrayParameters->nMaxPoints );
//////
//////  } else {                       
//////
//////    as = TERMCOMPENSATION_ARRAY_SIZE(stGetArrayParameters->nMaxPoints ); 
//////
//////    ps = sizeof(struct TEtermPoint); 
//////
//////  }
//////  //---------------------------------------------------------------------------------------------------------------------------------------
//////  if( stGetArrayParameters->buffer == NULL || stGetArrayParameters->buffersize < ps ) return NULL;
//////  //---------------------------------------------------------------------------------------------------------------------------------------
//////  // пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ пїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ
//////  if( !(     ( stGetArrayParameters->state == eSTATE_SHORT ||  
//////               stGetArrayParameters->state == eSTATE_LOAD  ||  
//////               stGetArrayParameters->state == eSTATE_OPEN  ||
//////               stGetArrayParameters->state == eSTATE_T11   ||
//////               stGetArrayParameters->state == eSTATE_T12   ||
//////               stGetArrayParameters->state == eSTATE_T21   ||
//////               stGetArrayParameters->state == eSTATE_T22   ||
//////               stGetArrayParameters->state == eSTATE_LOAD2 ||  
//////               stGetArrayParameters->state == eSTATE_OPEN2 ||
//////               stGetArrayParameters->state == eSTATE_A11   ||
//////               stGetArrayParameters->state == eSTATE_A12   ||
//////               stGetArrayParameters->state == eSTATE_A21   ||
//////               stGetArrayParameters->state == eSTATE_A22   
//////  
//////             ) 
//////             &&
//////             ( stGetArrayParameters->port  == ePORT_A      ||
//////               stGetArrayParameters->port  == ePORT_B      ||
//////               stGetArrayParameters->port  == ePORT_AB     
//////             )
//////       ) 
//////    ) return FALSE;
//////  //---------------------------------------------------------------------------------------------------------------------------------------
//////  // пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅ (A/B) пїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ SH/LD/OP/LD2/OP2
//////    if(  (   ( stGetArrayParameters->state == eSTATE_SHORT ||  
//////               stGetArrayParameters->state == eSTATE_LOAD  ||  
//////               stGetArrayParameters->state == eSTATE_OPEN  ||
//////               stGetArrayParameters->state == eSTATE_LOAD2 ||  
//////               stGetArrayParameters->state == eSTATE_OPEN2 
//////             ) 
//////             &&
//////             ( stGetArrayParameters->port  != ePORT_A      &&
//////               stGetArrayParameters->port  != ePORT_B      
//////             )
//////         ) 
//////    ) return FALSE;  
//////  //---------------------------------------------------------------------------------------------------------------------------------------
//////  // пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅ (AB) пїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ T11/T12/T21/T22
//////    if(  (   ( stGetArrayParameters->state == eSTATE_T11   ||
//////               stGetArrayParameters->state == eSTATE_T12   ||
//////               stGetArrayParameters->state == eSTATE_T21   ||
//////               stGetArrayParameters->state == eSTATE_T22     
//////             ) 
//////             &&
//////             ( stGetArrayParameters->port  != ePORT_AB
//////             )
//////       ) 
//////    ) return FALSE;      
//////  //---------------------------------------------------------------------------------------------------------------------------------------
//////  // пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅ (AB) пїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ A11/A12/A21/A22
//////    if(  (   ( stGetArrayParameters->state == eSTATE_A11   ||
//////               stGetArrayParameters->state == eSTATE_A12   ||
//////               stGetArrayParameters->state == eSTATE_A21   ||
//////               stGetArrayParameters->state == eSTATE_A22     
//////             ) 
//////             &&
//////             ( stGetArrayParameters->port  != ePORT_AB
//////             )
//////       ) 
//////    ) return FALSE;     
//////  //---------------------------------------------------------------------------------------------------------------------------------------
//////  // пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅ
//////
//////if(  (stGetArrayParameters->cFlags & (1<<0)) == 0 ) // get characterization array
//////{                 
//////
//////      // *============================ пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ ==================================   
//////
//////              // пїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅ SH,OP,LD. пїЅпїЅ пїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅ пїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅ SH * 2, OP * 2, LD * 2.
//////              // пїЅпїЅпїЅпїЅпїЅпїЅ A пїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ B       SHA,SHB,OPA,OPB,LDA,LDB
//////              if( stGetArrayParameters->state == eSTATE_SHORT ||  stGetArrayParameters->state == eSTATE_LOAD ||  stGetArrayParameters->state == eSTATE_OPEN )
//////              {
//////                if( stGetArrayParameters->state == eSTATE_SHORT ) of  = 0;
//////                if( stGetArrayParameters->state == eSTATE_OPEN  ) of  = 2;
//////                if( stGetArrayParameters->state == eSTATE_LOAD  ) of  = 4;  
//////            
//////                if( stGetArrayParameters->port ==  ePORT_A      ) of += 0;
//////                if( stGetArrayParameters->port ==  ePORT_B      ) of += 1;
//////            
//////              } else 
//////              if( stGetArrayParameters->state == eSTATE_T11 ||  stGetArrayParameters->state == eSTATE_T12 ||  stGetArrayParameters->state == eSTATE_T21 ||  stGetArrayParameters->state == eSTATE_T22)
//////              {                                                  
//////                                                                 of  = 6;
//////                if( stGetArrayParameters->state == eSTATE_T11  ) of += 0;
//////                if( stGetArrayParameters->state == eSTATE_T21  ) of += 1;
//////                if( stGetArrayParameters->state == eSTATE_T12  ) of += 2;
//////                if( stGetArrayParameters->state == eSTATE_T22  ) of += 3;
//////              }    
//////              else 
//////              if( stGetArrayParameters->state == eSTATE_A11 ||  stGetArrayParameters->state == eSTATE_A12 ||  stGetArrayParameters->state == eSTATE_A21 ||  stGetArrayParameters->state == eSTATE_A22)
//////              {                                                  
//////                                                                 of  = 10;
//////                if( stGetArrayParameters->state == eSTATE_A11  ) of += 0;
//////                if( stGetArrayParameters->state == eSTATE_A21  ) of += 1;
//////                if( stGetArrayParameters->state == eSTATE_A12  ) of += 2;
//////                if( stGetArrayParameters->state == eSTATE_A22  ) of += 3;    
//////            
//////              }  
//////              else 
//////              if( stGetArrayParameters->state == eSTATE_LOAD2 ||  stGetArrayParameters->state == eSTATE_OPEN2 )
//////              {                                                  
//////                                                                   of  =14; /*28*/
//////                if( stGetArrayParameters->state == eSTATE_LOAD2  ) of += 0;
//////                if( stGetArrayParameters->state == eSTATE_OPEN2  ) of += 2; /*4*/
//////            
//////                if( stGetArrayParameters->port ==  ePORT_A      )  of += 0;
//////                if( stGetArrayParameters->port ==  ePORT_B      )  of += 1; /*2*/ 
//////                /*                                                             пїЅпїЅпїЅ пїЅпїЅ пїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ, пїЅпїЅпїЅ пїЅпїЅпїЅ PHASE
//////                if( stGetArrayParameters->tca_type ==  eTCA_MAGN  ) of += 0;
//////                if( stGetArrayParameters->tca_type ==  eTCA_PHASE ) of += 1;*/
//////              }  
////// 
//////      // *====================================================================================
//////
//////} else /// get termo compensation array
//////{
////////                     +---------+------------+-------+
////////                     |  minRAD |      N     |       |
////////                     | ------- |...POINTS...|  CRC  |
////////                     |  maxRAD |            | ARRAY |
////////                     +---------+------------+-------+
////////                     \                             /
////////                      \                           /
////////                       \                         /                                                                                                                                                                                                                                  
////////                        \                       /                                                                                                                                                                                                                                   
////////                         \   - PHASE ARRAY -   /                                                                                                                                                                                                                                    
////////                          \                   /                                                                                                                                                                                                                                     
////////                           \                 /                                                                                                                                                                                                                                      
////////                            \               /
////////                             \             /
////////                              \           /
////////                               \         /
//////// +-----------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
//////// |   BLOCK   | TERMO  |    0   |    1   |    2   |    3   |    4   |    5   |    6   |    7   |    8   |    9   |   10   |   11   |   12   |   13   |   14   |   15   |   16   |   17   |   18   |   19   |   20   |   21   |   22   |   23   |   24   |   25   |   26   |   27   |   28   |   29   |   30   |   31   |   32   |   33   |   34   |   35   |
//////// |   HEADER  | COMPEN |  SH_A  |  SH_A  |  SH_B  |  SH_B  |  OP_A  |  OP_A  |  OP_B  |  OP_B  |  LD_A  |  LD_A  |  LD_B  |  LD_B  |  T_11  |  T_11  |  T_21  |  T_21  |  T_12  |  T_12  |  T_22  |  T_22  |  A_11  |  A_11  |  A_21  |  A_21  |  A_12  |  A_12  |  A_22  |  A_22  |  LD2A  |  LD2A  |  LD2B  |  LD2B  |  OP_A  |  OP_A  |  OP_B  |  OP_B  |
//////// | TERMOCOMP |  CRC   | MAGN   | PHASE  | MAGN   | PHASE  | MAGN   | PHASE  | MAGN   | PHASE  | MAGN   | PHASE  | MAGN   | PHASE  | MAGN   | PHASE  | MAGN   | PHASE  | MAGN   | PHASE  | MAGN   | PHASE  | MAGN   | PHASE  | MAGN   | PHASE  | MAGN   | PHASE  | MAGN   | PHASE  | MAGN   | PHASE  | MAGN   | PHASE  | MAGN   | PHASE  | MAGN   | PHASE  |
//////// +-----------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
////////                     /          \
////////                    /            \
////////                   /              \
////////                  /                \
////////                 /                  \
////////                /                    \
////////               /                      \
////////              /  - MAGNITUDE ARRAY -   \
////////             /                          \
////////            +-------+------------+-------+
////////            | mindB |      N     |       |
////////            | ----- |...POINTS...|  CRC  |
////////            | maxdB |            |ARRAY  |
////////            +-------+------------+-------+                                                     
//////
//////
//////  // * ============================ пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ =====================================         
//////
//////  if( stGetArrayParameters->state == eSTATE_SHORT ||  stGetArrayParameters->state == eSTATE_LOAD ||  stGetArrayParameters->state == eSTATE_OPEN ||  stGetArrayParameters->state == eSTATE_LOAD2 ||  stGetArrayParameters->state == eSTATE_OPEN2 )
//////  {
//////    if( stGetArrayParameters->state == eSTATE_SHORT ) of  = 0;
//////    if( stGetArrayParameters->state == eSTATE_OPEN  ) of  = 4;
//////    if( stGetArrayParameters->state == eSTATE_LOAD  ) of  = 8;  
//////
//////    if( stGetArrayParameters->state == eSTATE_OPEN2 ) of  = 32;
//////    if( stGetArrayParameters->state == eSTATE_LOAD2 ) of  = 28; 
//////
//////    if( stGetArrayParameters->port ==  ePORT_A      ) of += 0;
//////    if( stGetArrayParameters->port ==  ePORT_B      ) of += 2; 
//////
//////    if( stGetArrayParameters->tca_type ==  eTCA_MAGN  ) of += 0;
//////    if( stGetArrayParameters->tca_type ==  eTCA_PHASE ) of += 1;
//////
//////  } else 
//////  if( stGetArrayParameters->state == eSTATE_T11 ||  stGetArrayParameters->state == eSTATE_T12 ||  stGetArrayParameters->state == eSTATE_T21 ||  stGetArrayParameters->state == eSTATE_T22 
//////      ||
//////      stGetArrayParameters->state == eSTATE_A11 ||  stGetArrayParameters->state == eSTATE_A12 ||  stGetArrayParameters->state == eSTATE_A21 ||  stGetArrayParameters->state == eSTATE_A22 )
//////  {                                                  
//////                                                     of  = 12;  
//////
//////    if( stGetArrayParameters->state == eSTATE_T11  ) of += 0;
//////    if( stGetArrayParameters->state == eSTATE_T21  ) of += 2;
//////    if( stGetArrayParameters->state == eSTATE_T12  ) of += 4;
//////    if( stGetArrayParameters->state == eSTATE_T22  ) of += 6;  
//////
//////    if( stGetArrayParameters->state == eSTATE_A11  ) of += 8;
//////    if( stGetArrayParameters->state == eSTATE_A21  ) of += 10;
//////    if( stGetArrayParameters->state == eSTATE_A12  ) of += 12;
//////    if( stGetArrayParameters->state == eSTATE_A22  ) of += 14;
//////
//////    if( stGetArrayParameters->tca_type ==  eTCA_MAGN  ) of += 0;
//////    if( stGetArrayParameters->tca_type ==  eTCA_PHASE ) of += 1;
////// 
//////  }   
//////
//////  // * ====================================================================================
//////
//////}
//////  // ------------------------------
//////  // of пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅ
//////  of *= as;
//////  // of пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅ пїЅпїЅпїЅпїЅпїЅпїЅ
//////  // ------------------------------
//////
//////  // -----------------------------------------------------
//////  // пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅ of пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ 
//////  // (пїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ FACT / US1 / ... / US5)
//////  of += stGetArrayParameters->dwStartAddress;
//////  // -----------------------------------------------------
//////  //
//////    adr_minmax = of;
//////    adr_points = adr_minmax + sizeof(FIRSTPOINT);
//////    adr_crc    = adr_points + stGetArrayParameters->nMaxPoints * ps;  
//////    stoutArrayParams->dwPointsAddress = adr_points;
//////  //  
//////  // -----------------------------------------------
//////  // of пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅ (пїЅпїЅпїЅпїЅпїЅ min/max )
//////  // -----------------------------------------------
//////  //read_flash( adr_minmax, (char*)&stoutArrayParams->FirstPoint, sizeof(FIRSTPOINT)  ); // пїЅпїЅпїЅпїЅпїЅпїЅ FirstPoint (MindB / MaxdB)
//////  //read_flash( adr_crc   , (char*)&stoutArrayParams->dwArrayCRC, sizeof(unsigned int)); // пїЅпїЅпїЅпїЅпїЅпїЅ CRC
//////  BREAKPOINT;
//////  // -----------------------------------------------
//////  (void)(adr_crc);
//////
//////  // -----------------------------------------------
//////  TCRC crc = ICRC32; // пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ CRC32
//////  unsigned int maxread = stGetArrayParameters->buffersize - stGetArrayParameters->buffersize%ps;
//////  unsigned int pointsbytes = as - sizeof(unsigned int); //-crc
//////  unsigned int bytes = maxread;       
//////  // -----------------------------------------------
//////  unsigned int address = adr_minmax;
//////  unsigned int readcnt = 0;
//////
//////  while(readcnt < pointsbytes)
//////  {
//////     bytes = pointsbytes - readcnt;
//////     if(bytes > maxread) bytes = maxread;
//////     
//////     //read_flash( address, (char*)data, bytes ); 
//////     BREAKPOINT;
//////
//////     crc =  CRC32( crc, (unsigned char const *)data, bytes);
//////
//////     address    += bytes;
//////     readcnt    += bytes;
//////  }//0xA9D5BE5A
//////  // -----------------------------------------------
//////  if((stoutArrayParams->dwArrayCRC != crc)) stoutArrayParams->dwPointsAddress = 0;
//////  // -----------------------------------------------
//////  return (stoutArrayParams->dwArrayCRC==crc)?(TRUE):(FALSE);
//////}
//////// ######################################################################################################################################
//////// ######################################################################################################################################
//////// -------------------------------------------------------------------------------------------------------------
//////
//////
//////
//////
//////
//////
//////
//////
//////
//////
//////
//////
//////
//////
//////
//////
//////
//////
//////
//////
//////
//////
//////
//////TECALPOINT2 * ROM_ReadPoints( char * buffer, unsigned int buffersize, unsigned int address, unsigned int length )
//////{
//////  if( length > buffersize || buffer == NULL ) return NULL;
//////
//////  //read_flash( address, buffer, length );
//////  BREAKPOINT;
//////
//////  return (TECALPOINT2 *)buffer;
//////}
//////// ------------------------------------------------------------------------------
///////*
//////TECALPOINT * ROM_GetPoints( char * buffer, unsigned int buffersize, EROMHEADER HeaderID, unsigned int dwPointsStart, unsigned int dwPointsCount )
//////{
//////
//////  TECALPOINT * pPoints;
//////  char * recievebuffer = buffer;
//////  if( ! ( HeaderID >= 0 && HeaderID <= 5 ) ) return NULL;
//////  //---------------------------------
//////  unsigned int address;
//////            if(address > MAX_POINTS_MEMORY_SECTOR) return NULL;
//////               address+= ROM_MAP[HeaderID];
//////  //---------------------------------
//////  if( LastReadAddress != address )  // пїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅ пїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ
//////          BufferChached = 0;  // пїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ
//////  else
//////          BufferChached = 1; // пїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅ пїЅпїЅпїЅ ROM SPI 
//////  //---------------------------------
//////  if( recievebuffer == NULL ) {   // пїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ ROMHeaderBuffer
//////          recievebuffer = (char*)&ROMHeaderBuffer; 
//////          buffersize = SPIROMHeaderBufferSize; // !!! пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ TECALDATAHEADERCRC !!!
//////          LastReadAddress = address; 
//////  }  
//////  else 
//////  {  
//////         BufferChached = 0;  // пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ, пїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ, пїЅпїЅ пїЅпїЅпїЅпїЅпїЅ ROMHeaderBuffer 
//////         if( INT(recievebuffer)%sizeof(unsigned int) ) return NULL; // not aligment . 
//////  }
//////  //---------------------------------
//////  if( dwPointsCount > buffersize / sizeof(TECALPOINT) ) return NULL;
//////  //---------------------------------
//////  if( BufferChached != 1 )  pPoints = ROM_ReadPoints( recievebuffer, buffersize, address, dwPointsCount*sizeof(TECALPOINT)); 
//////  else                      pPoints = (TECALPOINT *)recievebuffer; // !!! пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅ пїЅ пїЅпїЅпїЅпїЅпїЅпїЅ пїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ !!!
////// 
////// return pPoints;
//////}  
//////// ------------------------------------------------------------------------------
//////*/
