/*
 * Created on: Jul 27, 2024
 *
 * code taken from example WCH code, which was likely stolen from somewhere else.
 * directly uses i2c peripheral in shitty way. no time to make this better.
 * modified to support multiple "pages" (addresses) for 02/04/08/16 EEPROMs.
 *
 * ensure i2c bus has been configured before using these functions.
 */

#define EEPROM_BASE_ADDR        0xa0


#include <ch32v00x.h>
#include <stdint.h>

#include "eeprom.h"
#include "i2c.h"



static inline uint8_t page_to_i2caddr(uint8_t page)
{
    page &= 0x7;                // limit page to 3 bits (8 pages)
    page <<= 1;                 // shift page to required position
    page |= EEPROM_BASE_ADDR;   // merge top address bits to form address

    return page;
}


/*********************************************************************
 * @fn      eeprom_read_byte
 *
 * @brief   Read one data from EEPROM.
 * @param   page - Which 256-byte EEPROM page.
 * @param   addr - First read address.
 * @param   data - Pointer to byte(s) to write.
 * @param   len - Count of data to write.
 */
void eeprom_read_bytes(uint8_t page, uint8_t addr, uint8_t *data, uint8_t len)
{
    page = page_to_i2caddr(page);

    i2c_read_addr1b(page, addr, data, len);
}

/*********************************************************************
 * @fn      eeprom_write_bytes
 *
 * @brief   Write data to EEPROM.
 *          Note that some EEPROMs have buffers smaller than the page size.
 *
 * @param   page - Which 256-byte EEPROM page.
 * @param   addr - Starting write address.
 * @param   data - Pointer to byte(s) to write.
 * @param   len  - Count of data to write.
 */
void eeprom_write_bytes(uint8_t page, uint8_t addr, uint8_t *data, uint8_t len)
{
    page = page_to_i2caddr(page);

    // disable systick interrupt
    NVIC_DisableIRQ(SysTicK_IRQn);

    // write the data
#ifdef EEPROM_WP_PORT
    EEPROM_WP_PORT->BCR = EEPROM_WP_PIN;
#endif

    while (!i2c_addr_scan(page));
    i2c_write_addr1b(page, addr, data, len);
    while (!i2c_addr_scan(page));

#ifdef EEPROM_WP_PORT
    EEPROM_WP_PORT->BSHR = EEPROM_WP_PIN;
#endif

    // clear systick timer
    SysTick->CNT = 0;
    SysTick->SR = 0;

    // re-enable systick interrupt
    NVIC_EnableIRQ(SysTicK_IRQn);
}
