/***************************************************************************//**
 *   @file   MemFlash.c
 *   @brief  Functions de gestion de la mémoire Flash
 *   @author Kévin MARCHAND(Kevin.marchand@intelligence-electronique.com)
********************************************************************************
 * Copyright 2014(c) PLCD, Inc.
 *
 * Functions de gestion de la mémoire Flash
 * Exemple d'utilisation :
 * - Lecture_Memoire_Flash_Ligne_Str(NumeroPage, NumeroLigne, * reponse)
 *  Lit la ligne <i>NumeroLigne</i> à la page <i>NumeroPage</i> et retourne la ligne lu dans
 *  le pointeur <i>reponse</i>
 * - Ecriture_Memoire_Flash_Ligne_Str(NumeroPage, NumeroLigne, * buffer)
 *  Ecrit <i>buffer</i> à la ligne <i>NumeroLigne</i> dans la page <i>NumeroPage</i>
 *
********************************************************************************
 *   SVN Revision: 1
*******************************************************************************/

/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include "MemFlash.h"
#include "Include/TCPIPStack/Delay.h"
#include "HardwareProfile.h"
/******************************************************************************/
/************************ Variables Declarations ******************************/
/******************************************************************************/
unsigned int Nb_Octets_Log;
unsigned char Address_Log_L, Address_Log_B;


/***************************************************************************//**
 * @brief Effectue un nombre d'impulsions sur la pin FLASH_SCK_IO.
 *
 * @param Nombre - Nombre d'impulsions sur la pin FLASH_SCK_IO.
 *
 * @return none.
*******************************************************************************/
void Flash_N_Clock(unsigned char Nombre)
{
    while(Nombre > 0)
    {
        Nombre--;						// Décrémente le nombre d'impulsions restants à envoyer
        FLASH_SCK_IO = 1;
        Nop();
        Nop();
        FLASH_SCK_IO = 0;
        Nop();
        Nop();
    }
}

/***************************************************************************//**
 * @brief Active la flash avec le chip select CS
 *
 * @param none.
 *
 * @return none.
*******************************************************************************/
void Active_Flash(void)
{
    FLASH_CS_IO = 0;
}

/***************************************************************************//**
 * @brief Désactive la flash avec le chip select CS
 *
 * @param none.
 *
 * @return none.
*******************************************************************************/
void Desactive_Flash(void)
{
    FLASH_CS_IO = 1;
    Nop();
    Nop();
    Nop();
}

/***************************************************************************//**
 * @brief Indique si la mémoire Flash est prête
 *
 * @param none.
 *
 * @return 1 si la flash est prête, 0 sinon.
*******************************************************************************/
int Flash_Ready(void)
{
    unsigned char byteRead;

    Active_Flash();
    Write_Flash(0xD7);
    byteRead = Read_Flash();
    Desactive_Flash();
    if ((byteRead & 0b10000000) == 0b10000000){
        return 1;
    }else
        return 0;
}

/***************************************************************************//**
 * @brief Attent que la flash soit prête
 *
 * @param none.
 *
 * @return none.
*******************************************************************************/
void Wait_Flash_Ready(void)
{
    while (Flash_Ready() == 0);
}

/***************************************************************************//**
 * @brief Ecrit un octet dans la flash
 *
 * @param Byte_To_Write - Octet à écrire dans la flash.
 *
 * @return none.
*******************************************************************************/
void Write_Flash(unsigned char Byte_To_Write)
{
    char Bits_Counter;
    Bits_Counter = 8;                                                           // Nombre de bits à envoyer

    FLASH_SCK_IO = 0;                                                           // Place la clock à 0
    while(Bits_Counter > 0)
    {
        Bits_Counter--;                                                         // Décrémente le nomre de bits restants à envoyer
        Byte_To_Write = Byte_To_Write<<1;                                       // Sort le premier bits à envoyer
        if(SRbits.C)                                                            // Si Carry = 1, alors bit envoi SPI à 1
        {
            FLASH_SDO_IO = 1;                                                   // Place la valeur du bit sur le port
        }
        else                                                                    // Sinon, alors bit envoi SPI à 0
        {
            FLASH_SDO_IO = 0;                                                   // Place la valeur du bit sur le port
        }
        FLASH_SCK_IO = 1;                                                       // Attente avec clock à 0
        Nop();
        FLASH_SCK_IO = 0;                                                       // Place le clock à 1 et valide la donnée
    }
}
/***************************************************************************//**
 * @brief Charge le pointeur de l'adresse mémoire de la flash
 *
 * @param Add_H - Octet de poids fort.
 * @param Add_L - Octet de poids faible.
 * @param Add_B - Octet Buffer Address.
 *
 * @return none.
*******************************************************************************/
void Charge_Pointeurs(unsigned char Add_H, unsigned char Add_L, unsigned char Add_B)
{
    Write_Flash(Add_H);
    Write_Flash(Add_L);
    Write_Flash(Add_B);
}
/***************************************************************************//**
 * @brief Lit un octet à l'adresse mémoire spécifié.
 *
 * @param Add_H - Octet de poids fort.
 * @param Add_L - Octet de poids faible.
 * @param Add_B - Octet Buffer Address.
 *
 * @return none.
*******************************************************************************/
void Lecture_Byte_In_Flash(unsigned char Add_H, unsigned char Add_L, unsigned char Add_B)
{
    Write_Flash(Main_Page_Read);
    Charge_Pointeurs(Add_H, Add_L, Add_B);
    Flash_N_Clock(32);
}

/*----- Direct_Byte_Write_In_Page ----------------------------------------------*/
void Direct_Byte_Write_In_Page(unsigned char Add_H, unsigned char Add_L, unsigned char Add_B)
{
    Write_Flash(Main_Page_Write);
    Charge_Pointeurs(Add_H, Add_L, Add_B);
}

/*----- Transfert_Page_To_Buffer -----------------------------------------------*/
void Transfert_Page_To_Buffer(unsigned char Add_H, unsigned char Add_L, unsigned char Add_B)
{
    Write_Flash(Main_Page_To_Buffer);
    Charge_Pointeurs(Add_H, Add_L, Add_B);

}

/***************************************************************************//**
 * @brief Lit un octet sur le port.
 *
 * @param none - Octet de poids fort.
 *
 * @return SPI_Byte_Read - Octet lu sur le port.
*******************************************************************************/
unsigned char Read_Flash(void)
{
    unsigned char Bits_Counter;
    unsigned char SPI_Byte_Read;

    Bits_Counter = 8;						// Nombre de bits à envoyer
    SPI_Byte_Read = 0;
    FLASH_SCK_IO = 0;
    while(Bits_Counter > 0)
    {
        Bits_Counter--;						// Décrémente le nomre de bits restants à envoyer
        SPI_Byte_Read = SPI_Byte_Read<<1;                       // Décale SPI_Byte_Read pour acceuillir la nouvele data
        SPI_Byte_Read = (SPI_Byte_Read |(PORTE&0x0016)>>4);	// Ajoute RE3 pour récupérer FLASH_SDI_IO (PORTE&0x0008)>>3);
        Nop();
        FLASH_SCK_IO = 1;
        Nop();
        FLASH_SCK_IO = 0;
        Nop();
    }
    return SPI_Byte_Read;
}

/***************************************************************************//**
 * @brief Increment de l'adresse mémoire.
 *    |     Add_H      |    Add_L      |    Add_B
 *	x P P P P P P P P P P P P P B B B B B B B B B B
 *		8192 pages de 528 Bytes (AD45DB321D)
 * P = Page Address Bit B = Byte/Buffer Address Bit
 *
 * @param Add_H - Octet de poids fort.
 * @param Add_L - Octet de poids faible.
 * @param Add_B - Octet Buffer Address.
 *
 * @return none.
*******************************************************************************/
void Incremente_Adresse_FlashDB32(unsigned char *Add_H, unsigned char *Add_L, unsigned char *Add_B)
{
    unsigned int page=0, addrB=0;
    unsigned char bReloadBuff = 0;

    page = ((*Add_H<<6)&0x1FE0);
    page = page | ((*Add_L>>2)&0x3F);
    addrB = (*Add_L&0x03);
    addrB = addrB <<2;
    addrB = addrB | (*Add_B&0xFF);

    addrB++;
    if(addrB>=528){
        addrB = 0;
        page++;
        bReloadBuff = 1;
    }
    *Add_H = page>>6;
    *Add_L = (page<<2)|((addrB>>8)&0x03);
    *Add_B = addrB&0x00FF;

    if(bReloadBuff == 1){
        Desactive_Flash();
        Wait_Flash_Ready();
        Active_Flash();
        Transfert_Page_To_Buffer(*Add_H, *Add_L, *Add_B);
        Desactive_Flash();
        Wait_Flash_Ready();
        Active_Flash();
        Direct_Byte_Write_In_Page(*Add_H, *Add_L, *Add_B);
    }
}

/***************************************************************************//**
 * @brief Increment de l'adresse mémoire.
 *         |      Add_H	   |	Add_L	   |	Add_B
 *	    P P P P P P P P P P P P P B B B B B B B B B B B
 *		8192 pages de 1056 Bytes (AD45DB642)
 * P = Page Address Bit B = Byte/Buffer Address Bit
 *
 * @param Add_H - Octet de poids fort.
 * @param Add_L - Octet de poids faible.
 * @param Add_B - Octet Buffer Address.
 *
 * @return none.
*******************************************************************************/
void Incremente_Adresse_FlashDB64(unsigned char *Add_H, unsigned char *Add_L, unsigned char *Add_B)
{
    unsigned int page=0, addrB=0;
    unsigned char bReloadBuff = 0;

    page = ((*Add_H<<5)&0x1FE0);
    page = page | ((*Add_L>>3)&0x1F);
    addrB = (*Add_L&0x07);
    addrB = addrB <<3;
    addrB = addrB | (*Add_B&0xFF);

    addrB++;
    if(addrB>=1056){
        addrB = 0;
        page++;
        bReloadBuff = 1;
    }
    *Add_H = page>>5;
    *Add_L = (page<<3)|((addrB>>8)&0x07);
    *Add_B = addrB&0x00FF;

    if(bReloadBuff == 1){
        Desactive_Flash();
        Wait_Flash_Ready();
        Active_Flash();
        Transfert_Page_To_Buffer(*Add_H, *Add_L, *Add_B);
        Desactive_Flash();
        Wait_Flash_Ready();
        Active_Flash();
        Direct_Byte_Write_In_Page(*Add_H, *Add_L, *Add_B);
    }
}	

/***************************************************************************//**
 * @brief Calcul de l'adresse mémoire à partir de File_Number et de position.
 *    |     Add_H      |    Add_L      |    Add_B
 *	x P P P P P P P P P P P P P B B B B B B B B B B
 *		8192 pages de 528 Bytes (AD45DB321D)
 * P = Page Address Bit B = Byte/Buffer Address Bit
 *
 * @param File_Number - Numéro du fichier.
 * @param position - Position dans le fichier.
 * @param Add_H - Octet de poids fort.
 * @param Add_L - Octet de poids faible.
 * @param Add_B - Octet Buffer Address.
 *
 * @return none.
*******************************************************************************/
char MakeAddrDB32(unsigned char File_Number, unsigned int position, unsigned char *Add_H, unsigned char *Add_L,unsigned  char *Add_B)
{
    unsigned int page, addrB;

    page = (File_Number) + ((position*32)/528);
    addrB = (position*32)%528;

    *Add_H = page>>6;
    *Add_L = (page<<2)|((addrB>>8)&0x03);
    *Add_B = addrB&0x00FF;
    return 0;
}

/***************************************************************************//**
 * @brief Calcul de l'adresse mémoire à partir de File_Number et de position.
 *         |      Add_H	   |	Add_L	   |	Add_B
 *	    P P P P P P P P P P P P P B B B B B B B B B B B
 *		8192 pages de 1056 Bytes (AD45DB642)
 * P = Page Address Bit B = Byte/Buffer Address Bit
 *
 * @param File_Number - Numéro du fichier.
 * @param position - Position dans le fichier.
 * @param Add_H - Octet de poids fort.
 * @param Add_L - Octet de poids faible.
 * @param Add_B - Octet Buffer Address.
 *
 * @return none.
*******************************************************************************/
char MakeAddrDB64(unsigned char File_Number, unsigned int position, unsigned char *Add_H, unsigned char *Add_L,unsigned  char *Add_B)
{
    unsigned int page, addrB;

    page = (File_Number) + ((position*32)/1056);
    addrB = (position*32)%1056;

    *Add_H = page>>5;
    *Add_L = (page<<3)|((addrB>>8)&0x07);
    *Add_B = addrB&0x00FF;
    return 0;
}

/***************************************************************************//**
 * @brief Ecriture Memoire Flash d'une Chaine Limitée à 32 Catacteres
 *
 * @param File_Number - Numéro du fichier.
 * @param Numero_Ligne - Numéro de la ligne.
 * @param Buff - Chaine de caratères à écrire.
 *
 * @return none.
*******************************************************************************/
void Ecriture_Memoire_Flash_Ligne_Str(unsigned char File_Number, unsigned int Numero_Ligne, unsigned char *Buff)
{
    unsigned char i;
    unsigned char Adr_H;
    unsigned char Adr_L;
    unsigned char Adr_B;

    #ifdef FLASH_SIZE_64M
        MakeAddrDB64(File_Number, Numero_Ligne, &Adr_H, &Adr_L,&Adr_B);
    #else
        MakeAddrDB32(File_Number, Numero_Ligne, &Adr_H, &Adr_L,&Adr_B);
    #endif

    Wait_Flash_Ready();
    Active_Flash();
    DelayMs(1);
    Transfert_Page_To_Buffer(Adr_H, Adr_L, Adr_B);
    Desactive_Flash();
    Wait_Flash_Ready();
    Active_Flash();
    DelayMs(1);
    Direct_Byte_Write_In_Page(Adr_H, Adr_L, Adr_B);
    i = 0;
    do{
        Write_Flash(Buff[i]);
        i++;
        #ifdef FLASH_SIZE_64M
                Incremente_Adresse_FlashDB64(&Adr_H, &Adr_L, &Adr_B);
        #else
                Incremente_Adresse_FlashDB32(&Adr_H, &Adr_L, &Adr_B);
        #endif

    }while((Buff[i-1] != 0) && (i<32));
    Desactive_Flash();
    DelayMs(1);
}

/***************************************************************************//**
 * @brief Lecture memoire flash d'une chaine terminé par NULL, limitée à 32 catacteres
 *
 * @param File_Number - Numéro du fichier.
 * @param Numero_Ligne - Numéro de la ligne.
 * @param Buff - Buffer de lecture.
 *
 * @return Nombre de caractères lu.
*******************************************************************************/
unsigned char Lecture_Memoire_Flash_Ligne_Str(unsigned char File_Number, unsigned int Numero_Ligne, unsigned char *Buff)
{
    unsigned char i;
    unsigned char Adr_H;
    unsigned char Adr_L;
    unsigned char Adr_B;

    #ifdef FLASH_SIZE_64M
        MakeAddrDB64(File_Number, Numero_Ligne, &Adr_H, &Adr_L,&Adr_B);
    #else
        MakeAddrDB32(File_Number, Numero_Ligne, &Adr_H, &Adr_L,&Adr_B);
    #endif

    Desactive_Flash();
    Wait_Flash_Ready();
    Active_Flash();
    DelayMs(1);
    Lecture_Byte_In_Flash(Adr_H, Adr_L, Adr_B);

    i = 0;
    do{
        Buff[i] = Read_Flash();
        i++;
    }while ((i<32) && (Buff[i-1]!=0));

    if(Buff[i-1]!=0)
        Buff[i]=0;

    Desactive_Flash();
    return i - 1;

}