/****************************************************************************//**
  \file extMemReader.h

  \brief Declaration of external memory loader interface.

  \author
    Atmel Corporation: http://www.atmel.com \n
    Support email: avr@atmel.com

  Copyright (c) 2008-2015, Atmel Corporation. All rights reserved.
  Licensed under Atmel's Limited License Agreement (BitCloudTM).

  \internal
  History:
    17/08/09 A. Khromykh - Created
*******************************************************************************/
#ifndef _EXTMEMREADER_H
#define _EXTMEMREADER_H

/******************************************************************************
                   Define(s) section
******************************************************************************/
#define CRC_INITIALIZATION_VALUE     0xFF
#define EMPTY_EEPROM_VALUE           0xFF
#define ACTION_POSITION              0

#if EXTERNAL_MEMORY == AT25F2048

  #if !defined(ATMEGA1281) && !defined(ATMEGA128RFA1)
    #error 'at25f2048 is supported only for atmega1281/128rfa1.'
  #endif

  // flash instruction format (see at25f2048 manual)
  #define READ                                          0x03
  #define RDID                                          0x15

  // Atmel ID
  #define MANUFACTURER_ID                               0x1F
  // at25f2048
  #define DEVICE_ID                                     0x63

  #define PAGE_SIZE                                      256
  // 2 Mbits
  #define FLASH_SIZE                                  262144
  // image consists mcu flash - bootloader size + eeprom size. 128k - 4k + 4k
  #define IMAGE_SIZE                                  131072
  #define EXT_FLASH_START_ADDRESS                          0
  #define IMAGE1_START_ADDRESS                     EXT_FLASH_START_ADDRESS
  #define IMAGE2_START_ADDRESS                    (EXT_FLASH_START_ADDRESS + IMAGE_SIZE)

  #define MCU_EEPROM_SIZE                                4096
  #define MCU_FLASH_SIZE                          (IMAGE_SIZE - MCU_EEPROM_SIZE)

#elif EXTERNAL_MEMORY == AT45DB041

  #if !defined(ATMEGA1281) && !defined(ATMEGA128RFA1) && !defined(ATXMEGA256A3) && !defined(ATXMEGA256D3)
    #error 'at45db041 is supported only for atmega1281/128rfa1, atxmega256a/d3.'
  #endif

  // flash instruction format (see at45db041 manual)
  #define RDSR                                            0xD7
  #define READ                                            0xE8

  // status register bits
  #define RDY                                             0x80
  // unchanged bit mask within status register xx0111xx
  #define STATUS_UNCHANGED_BIT_MASK                       0x1C

  #define PAGE_SIZE                                        264
  // block addresses
  #define FIRST_HALF_BLOCK_NUMBER                            0
  #define SECOND_HALF_BLOCK_NUMBER                         128

  // 4 Mbits
  #define FLASH_SIZE                                    540672
  #define EXT_FLASH_START_ADDRESS                            0
  #define MCU_EEPROM_SIZE                                 4096

  #if defined(ATMEGA1281) || defined(ATMEGA128RFA1)
    #define IMAGE_SIZE                                  131072
    #define MCU_FLASH_SIZE                          (IMAGE_SIZE - MCU_EEPROM_SIZE)
  #elif  defined(ATXMEGA256A3) || defined(ATXMEGA256D3)
    #define IMAGE_SIZE                                  266240
    #define MCU_FLASH_SIZE                              262144
  #endif
  #define IMAGE1_START_ADDRESS                     EXT_FLASH_START_ADDRESS
  #define IMAGE2_START_ADDRESS                    (EXT_FLASH_START_ADDRESS + IMAGE_SIZE)

#elif EXTERNAL_MEMORY == AT25DF041A

  #if !defined(ATXMEGA256A3) && !defined(ATMEGA256RFR2) && !defined(ATMEGA2564RFR2)
    #error 'at25df041a is supported only for atxmega256a3, atmega256rfr2, atmega2564rfr2.'
  #endif

  // flash instruction format (see at25df041a manual)
  #define READ          0x03
  #define RDID          0x9F

  // Atmel ID
  #define MANUFACTURER_ID     0x1F
  // at25df041a
  #define DEVICE_ID_1         0x44
  #define DEVICE_ID_2         0x01
  #define EXT_STRING_LENGTH   0x00

  #define PAGE_SIZE            256

  // 4 Mbits
  #define FLASH_SIZE                                  524288
  #define EXT_FLASH_START_ADDRESS                          0
  
  #if defined(ATMEGA256RFR2) || defined(ATMEGA2564RFR2)
    // image consists mcu flash size - boot section size. 256k - 8k
    #define MCU_FLASH_SIZE                            253952
    #define MCU_EEPROM_SIZE                             8192
  #elif defined(ATXMEGA256A3)
    #define MCU_FLASH_SIZE                            262144
    #define MCU_EEPROM_SIZE                             4096
  #endif
  #define IMAGE_SIZE                 (MCU_FLASH_SIZE + MCU_EEPROM_SIZE)

  #define IMAGE1_START_ADDRESS        EXT_FLASH_START_ADDRESS
  // this is fake start address used for code compatibility
  #define IMAGE2_START_ADDRESS       (EXT_FLASH_START_ADDRESS + IMAGE_SIZE)

#elif EXTERNAL_MEMORY == W25X20CV
  
  #if !defined(ATMEGA2564RFR2) && !defined(ATSAMR21E18A) && !defined(ATSAMR21G18A)
    #error 'w25x20cv is supported for atmega2564rfr2 & atsamr21e18a.'
  #endif

  // flash instruction format (see w25x20cv manual)
  #define READ          0x03
  #define RDID          0x90

  // Winbond ID
  #define MANUFACTURER_ID   0xEF
  // w25x20cv
  #define DEVICE_ID_1       0x11
  
  #define PAGE_SIZE         256

  // 2 Mbits
  #define FLASH_SIZE                                  262144

  
  #if defined(ATMEGA256RFR2)
    // image consists mcu flash size - boot section size. 256k - 4k
    #define MCU_FLASH_SIZE                            249856
    #define MCU_EEPROM_SIZE                             8192
    #define EXT_FLASH_START_ADDRESS                        0
  #elif defined(ATSAMR21E18A)
    // image consists mcu flash size - bootloader - eeprom emulation size -. 256k - 4k -4k
    #define MCU_FLASH_SIZE                            253952
    #define MCU_EEPROM_SIZE                             4096
    #define MCU_BOOTLOADER_SIZE                         4096
    #define MCU_EEPROM_START_ADDR                    0x3F000
    #define EXT_FLASH_START_ADDRESS                   0x1000  // bootloader 0- 0x1000
  #elif defined(ATSAMR21G18A)
    // image consists mcu flash size - bootloader - eeprom emulation size -. 256k - 4k -4k
    #define MCU_FLASH_SIZE                            253952
    #define MCU_EEPROM_SIZE                             4096
    #define MCU_BOOTLOADER_SIZE                         4096
    #define MCU_EEPROM_START_ADDR                    0x3F000
    #define EXT_FLASH_START_ADDRESS                   0x1000  // bootloader 0- 0x1000
  #endif

  #define IMAGE_SIZE                     (MCU_FLASH_SIZE + MCU_EEPROM_SIZE)

  #define IMAGE1_START_ADDRESS        EXT_FLASH_START_ADDRESS
  // this is fake start address used for code compatibility
  #define IMAGE2_START_ADDRESS       (EXT_FLASH_START_ADDRESS + IMAGE_SIZE)
#elif EXTERNAL_MEMORY == M25P40VMN6PB
  
  #if !defined(ATMEGA2564RFR2) && !defined(ATSAMR21E18A) && !defined(ATSAMR21G18A)
    #error 'M25P40VMN6PB is supported for atmega2564rfr2 & atsamr21e18a.'
  #endif

  // flash instruction format (see M25P40VMN6PB manual)
  #define READ          0x03
  #define RDID          0x9F

  // Micron ID
  #define MANUFACTURER_ID   0x20
  // M25P40VMN6PB
  #define DEVICE_ID_1       0x20

  #define PAGE_SIZE         256

  // 4 Mbits
  #define FLASH_SIZE                                  524288

  // image consists mcu flash size - bootloader - eeprom emulation size -. 256k - 8k -4k
  #define MCU_FLASH_SIZE                           249856
  #define MCU_EEPROM_SIZE                          4096
  #define MCU_BOOTLOADER_SIZE                      8192
  #define MCU_EEPROM_START_ADDR                    0x3F000
  #define EXT_FLASH_START_ADDRESS                  0x2000

  #define IMAGE_SIZE                     (MCU_FLASH_SIZE + MCU_EEPROM_SIZE)

  #define IMAGE1_START_ADDRESS        EXT_FLASH_START_ADDRESS
  // this is fake start address used for code compatibility
  #define IMAGE2_START_ADDRESS       (EXT_FLASH_START_ADDRESS + IMAGE_SIZE)
#else
  #error 'Unknown memory type.'
#endif

// 1 byte (action for bootloader), 2 bytes (images crc), 1 byte table of image types.
#define SERVICE_INFO_SIZE                                 4

#define LITTLE_TO_BIG_ENDIAN(A)  ((((uint32_t)A & 0xFFul) << 24)   \
                                | (((uint32_t)A & 0xFF00ul) << 8)   \
                                | (((uint32_t)A >> 8) & 0xFF00ul)   \
                                | (((uint32_t)A >> 24) & 0xFFul))

// image type space in eeprom
#define EEPROM_IMGTYPE_OFFSET           (37U)
#define EEPROM_IMGTYPE_LENGTH           (2U)
#define DEFAULT_IMGTYPE_VALUE           (0)
#define INVALID_IMGTYPE_VALUE           (0xFFFF)
#define SKIP_ADDRESS_LENGTH             (4U)
#define SKIP_START_ADDRESS_EEPROM_OFFSET (EEPROM_IMGTYPE_OFFSET+EEPROM_IMGTYPE_LENGTH)
#define SKIP_END_ADDRESS_EEPROM_OFFSET   (SKIP_START_ADDRESS_EEPROM_OFFSET+SKIP_ADDRESS_LENGTH)
#define EEPROM_ACTION_POSITION   (SKIP_END_ADDRESS_EEPROM_OFFSET + SKIP_ADDRESS_LENGTH)
#define EEPROM_ACTION_LENGTH     (1U)
#define EEPROM_USER_REGION_START_ADDRESS  (EEPROM_ACTION_POSITION + EEPROM_ACTION_LENGTH)
#define REMAINDER_FOR_256_MASK           (0xFFu)
#define ADD_256_FOR_ROUND_MASK           (0x100u)
#define ROUND_TO_256_INT_MASK            (0xFFFFFF00u)
#define IS_SKIP_ADDRESS_WITHIN_BUFFER(address, len, skipAddress)       \
  ((skipAddress >= address) && (skipAddress < (address+len)))

/******************************************************************************
                   Types section
******************************************************************************/
/** \brief Number of position for image in the external flash */
typedef enum
{
  POSITION_1,
  POSITION_2,
  POSITION_MAX
} ImagePosition_t;

/** \brief states for skipping NVM in internal flash */
typedef enum {
  SKIP_NOT_STARTED = 0,
  SKIP_IN_PROCESS,
  SKIP_DONE
} skipStatus_t;

/******************************************************************************
                   Prototypes section
******************************************************************************/
/**************************************************************************//**
\brief Check availability of the external flash. Reads vendor and chip ID
from the external flash.

\return
  true - correct memory, \n
  false - other
******************************************************************************/
bool memCheckMem(void);

/**************************************************************************//**
\brief Reads data from memory.

\param[in]
  offset -  internal flash address;
\param[in]
  buffer -  pointer to the data buffer;
\param[in]
  length -  number bytes for reading;
******************************************************************************/
void memReadData(uint32_t offset, uint8_t *data, uint16_t size);

/**************************************************************************//**
\brief Starts external flash loader. Makes all tests and loads image.
******************************************************************************/
void extLoadDataFromExtMem(void);

#endif /* _EXTMEMREADER_H */
