/*******************************************************************************
 * @file    mem_hal.c
 * @brief   Memory HAL - Common functions and driver selection
 * @author  Charles KWON <charleskwon@medithings.co.kr>
 * @date    2025-02-03
 *
 * @details This file provides common functionality that applies to all
 *          memory backends. Specific implementations are in:
 *          - mem_flash.c  (W25Q32RV SPI Flash)
 *          - mem_eeprom.c (I2C EEPROM) - not yet implemented
 ******************************************************************************/

#include "mem_hal.h"
#include "mem_config.h"
#include <stdio.h>

/*==============================================================================
 * DEBUG MACROS
 *============================================================================*/

#define MEM_DEBUG   1

#if MEM_DEBUG
    #define MEM_LOG(...)    printf(__VA_ARGS__)
#else
    #define MEM_LOG(...)
#endif

/*==============================================================================
 * MEMORY TEST FUNCTION
 *============================================================================*/

/**
 * @brief Test memory read/write functionality
 * @return NRF_SUCCESS if all tests pass
 */
ret_code_t mem_test(void)
{
    ret_code_t err;
    uint8_t manufacturer_id;
    uint16_t device_id;

    MEM_LOG("[MEM] Testing memory...\r\n");

#if MEM_USE_W25Q_FLASH
    /* Read device ID */
    err = mem_get_device_id(&manufacturer_id, &device_id);
    if (err != NRF_SUCCESS)
    {
        MEM_LOG("[MEM] Failed to read device ID\r\n");
        return err;
    }

    MEM_LOG("[MEM] Manufacturer: 0x%02X, Device: 0x%04X\r\n",
            manufacturer_id, device_id);

    /* Verify it's W25Q32RV */
    if (manufacturer_id != 0xEF || device_id != 0x4016)
    {
        MEM_LOG("[MEM] WARNING: Unexpected device ID!\r\n");
    }
#endif

    /* Test read/write at address 0x0000 */
    uint8_t test_data[4] = { 0x12, 0x34, 0x56, 0x78 };
    uint8_t read_data[4] = { 0 };

    MEM_LOG("[MEM] Writing test data...\r\n");
    err = mem_write_bytes(0x0000, test_data, 4);
    if (err != NRF_SUCCESS)
    {
        MEM_LOG("[MEM] Write failed: %d\r\n", err);
        return err;
    }

    MEM_LOG("[MEM] Reading back...\r\n");
    err = mem_read_bytes(0x0000, read_data, 4);
    if (err != NRF_SUCCESS)
    {
        MEM_LOG("[MEM] Read failed: %d\r\n", err);
        return err;
    }

    /* Verify */
    bool match = true;
    for (int i = 0; i < 4; i++)
    {
        if (test_data[i] != read_data[i])
        {
            match = false;
            break;
        }
    }

    if (match)
    {
        MEM_LOG("[MEM] Test PASSED\r\n");
        return NRF_SUCCESS;
    }
    else
    {
        MEM_LOG("[MEM] Test FAILED: data mismatch\r\n");
        MEM_LOG("[MEM] Wrote: %02X %02X %02X %02X\r\n",
                test_data[0], test_data[1], test_data[2], test_data[3]);
        MEM_LOG("[MEM] Read:  %02X %02X %02X %02X\r\n",
                read_data[0], read_data[1], read_data[2], read_data[3]);
        return NRF_ERROR_INTERNAL;
    }
}

/*==============================================================================
 * STUB IMPLEMENTATIONS (when memory type not selected)
 *============================================================================*/

#if !MEM_USE_W25Q_FLASH && !MEM_USE_EEPROM && !MEM_USE_INTERNAL_FDS

/* No memory backend selected - provide stub implementations */

ret_code_t mem_init(void) { return NRF_ERROR_NOT_SUPPORTED; }
void mem_uninit(void) { }
bool mem_is_ready(void) { return false; }
ret_code_t mem_read_byte(uint32_t addr, uint8_t *out) { return NRF_ERROR_NOT_SUPPORTED; }
ret_code_t mem_write_byte(uint32_t addr, uint8_t data) { return NRF_ERROR_NOT_SUPPORTED; }
ret_code_t mem_read_bytes(uint32_t addr, uint8_t *buf, uint16_t len) { return NRF_ERROR_NOT_SUPPORTED; }
ret_code_t mem_write_bytes(uint32_t addr, const uint8_t *buf, uint16_t len) { return NRF_ERROR_NOT_SUPPORTED; }
ret_code_t mem_read_word(uint32_t addr, uint16_t *out) { return NRF_ERROR_NOT_SUPPORTED; }
ret_code_t mem_write_word(uint32_t addr, uint16_t data) { return NRF_ERROR_NOT_SUPPORTED; }
ret_code_t mem_read_uint32(uint32_t addr, uint32_t *out) { return NRF_ERROR_NOT_SUPPORTED; }
ret_code_t mem_write_uint32(uint32_t addr, uint32_t data) { return NRF_ERROR_NOT_SUPPORTED; }
ret_code_t mem_read_uint16_array(uint32_t addr, uint16_t *arr, uint16_t count) { return NRF_ERROR_NOT_SUPPORTED; }
ret_code_t mem_write_uint16_array(uint32_t addr, const uint16_t *arr, uint16_t count) { return NRF_ERROR_NOT_SUPPORTED; }
ret_code_t mem_read_decrypted(uint32_t addr, uint8_t *buf, uint16_t len) { return NRF_ERROR_NOT_SUPPORTED; }
ret_code_t mem_write_encrypted(uint32_t addr, const uint8_t *buf, uint16_t len) { return NRF_ERROR_NOT_SUPPORTED; }
ret_code_t mem_erase_sector(uint32_t addr) { return NRF_ERROR_NOT_SUPPORTED; }
ret_code_t mem_get_device_id(uint8_t *manufacturer_id, uint16_t *device_id) { return NRF_ERROR_NOT_SUPPORTED; }

#endif
