#include "eeprom.h"

// Includes
#include "term.h"

// ============================================================================
//                                   GLOBALS
// ============================================================================

eeprom_t eeprom;

// ============================================================================
//                                PROTOTYPES
// ============================================================================


// ============================================================================
//                                 FUNCTION
// ============================================================================

void eeprom_init()
{
    GPIO_InitTypeDef gpio = {0};

    // SCL, SDA
    gpio.Mode        = GPIO_MODE_AF_OD;
    gpio.Pull        = GPIO_NOPULL;
    gpio.Speed       = GPIO_SPEED_FREQ_LOW;
    gpio.Alternate   = EEPROM_I2C_AF;
    SYSTEM_GPIO_INIT(gpio, EEPROM_SCL_PORT, EEPROM_SCL_PIN);
    SYSTEM_GPIO_INIT(gpio, EEPROM_SDA_PORT, EEPROM_SDA_PIN);

    // I2C
    EEPROM_I2C_CLK_INIT();
    EEPROM_I2C_CLK_ENABLE();
    eeprom.i2c.Instance              = EEPROM_I2C;
    eeprom.i2c.Init.Timing           = EEPROM_SPEED_400KHZ;
    eeprom.i2c.Init.OwnAddress1      = 0;
    eeprom.i2c.Init.AddressingMode   = I2C_ADDRESSINGMODE_7BIT;
    eeprom.i2c.Init.DualAddressMode  = I2C_DUALADDRESS_DISABLE;
    eeprom.i2c.Init.OwnAddress2      = 0;
    eeprom.i2c.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
    eeprom.i2c.Init.GeneralCallMode  = I2C_GENERALCALL_DISABLE;
    eeprom.i2c.Init.NoStretchMode    = I2C_NOSTRETCH_DISABLE;
    HAL_I2C_Init(&eeprom.i2c);
    HAL_I2CEx_ConfigAnalogFilter(&eeprom.i2c, I2C_ANALOGFILTER_ENABLE);
    HAL_I2CEx_ConfigDigitalFilter(&eeprom.i2c, 0);

    // Check device
    if (HAL_I2C_IsDeviceReady(&eeprom.i2c, EEPROM_I2C_ADDR, 3, EEPROM_I2C_TIMEOUT) != HAL_OK){
        term_out_msg("EEPROM not found !\r\n");
    }

}

uint32_t eeprom_read(uint16_t addr, uint8_t *buff, uint16_t buffsz)
{
    uint16_t nread = 0;
    uint16_t blocksz;
    uint16_t remaining;
    while(nread < buffsz){
        // Compute remaining data to read
        remaining = buffsz - nread;
        // Get current block size
        blocksz = EEPROM_BLOCK_SIZE - (addr % EEPROM_PAGE_SIZE);
        // Shrink the block if need
        if (blocksz > remaining) blocksz = remaining;
        // Read bloc
        //printf("W 0x%04X\r\n", addr);
        if (HAL_I2C_Mem_Read(&eeprom.i2c, EEPROM_I2C_ADDR | ((addr & 0x0300) >> 7), addr & 0xFF, I2C_MEMADD_SIZE_8BIT, buff, blocksz, EEPROM_I2C_TIMEOUT) != HAL_OK){
            return false;
        }
        // Next block
        nread += blocksz;
        buff += blocksz;
        addr += blocksz;

    }
    return true;
}

uint32_t eeprom_write(uint16_t addr, uint8_t *buff, uint16_t buffsz)
{
    uint16_t nwrite = 0;
    uint16_t blocksz;
    uint16_t remaining;
    while(nwrite < buffsz){
        // Compute remaining data to write
        remaining = buffsz - nwrite;
        // Get current block size
        blocksz = EEPROM_PAGE_SIZE - (addr % EEPROM_PAGE_SIZE);
        // Shrink the block if need
        if (blocksz > remaining) blocksz = remaining;
        // Write bloc
        //printf("W 0x%04X\r\n", addr);
        if (HAL_I2C_Mem_Write(&eeprom.i2c, EEPROM_I2C_ADDR | ((addr & 0x0300) >> 7), addr & 0xFF, I2C_MEMADD_SIZE_8BIT, buff, blocksz, EEPROM_I2C_TIMEOUT) != HAL_OK){
            return false;
        }
        HAL_Delay(10);
        // Next block
        nwrite += blocksz;
        buff += blocksz;
        addr += blocksz;
    }
    return true;
}

/*
//char buffer[] = "L'objectif est de produire un bloc de donnees de taille precise. Dans le monde de l'informatique, la standardisation est la cle. Nous utilisons ici uniquement des caracteres compris entre le code trente et le code cent-vingt-six de la table ASCII. Cela signifie qu'aucun accent, comme le e accent aigu ou le a accent grave, ne peut apparaitre dans ce message. Le respect des contraintes techniques est un exercice de style interessant qui force a reformuler ses pensees avec simplicite et clarte. La communication doit rester fluide malgre les limites imposees par le formatage binaire sous-jacent. Imaginez un systeme ancien, depourvu de support pour l'UTF-8, ou chaque octet compte et ou la compatibilite est reine. Nous arrivons doucement vers la moitie de ce texte. La structure est maintenue par une serie de phrases courtes et directes. Il est crucial de verifier que chaque espace et chaque signe de ponctuation est valide. Continuons ainsi jusqu'a atteindre le compte exact. Un kilo-octet de texte pur. Fin. Merci !!";
//eeprom_write(0x0000, (uint8_t*)buffer, 1024);

uint8_t c;
uint8_t buffer[1024];
eeprom_read(0x0000, buffer, 1024);
for(int i = 0; i< 1024; i++){
    c = buffer[i];
    if (c >= 30 && c <= 126){
        printf("%c", (char)c);
    }else{
        printf(" %02X", c);
    }
}
printf("\r\n");
for(;;){}
*/
