 /******************************************************************************
 * @file    m_loramngt_flash.c
 * @author  Insight SiP
 * @version V2.2.0
 * @date    20-dec-2019
 * @brief   loramngt flash module implementation file.
 *
 * @attention
 *	THIS SOFTWARE IS PROVIDED BY INSIGHT SIP "AS IS" AND ANY EXPRESS
 *	OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 *	OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
 *	DISCLAIMED. IN NO EVENT SHALL INSIGHT SIP OR CONTRIBUTORS BE
 *	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 *	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 *	GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 *	HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *	LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 *	OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *****************************************************************************/
 
#include <stdint.h>
#include <string.h>
#include "nrf_fstorage.h"
#include "fds.h"
#include "app_error.h"
#include "app_scheduler.h"

#include "nrf_log.h"

#include "macros_common.h" 
#include "ble_loramngt.h"
#include "m_loramngt_flash.h"

#define WS_FLASH_CONFIG_VALID           0x42UL
#define LORAMNGT_CONFIG_FILE_ID         0x1001
#define LORAMNGT_CONFIG_REC_KEY     	0x1002


/**@brief Data structure of lora configuration data stored to flash.
 */
typedef struct
{
    uint32_t                    valid;
    ble_loramngt_config_t       config;
} m_loramngt_flash_config_data_t;

/**@brief Lora configuration data with size.
 */
typedef union
{
    m_loramngt_flash_config_data_t      data;
    uint32_t                            padding[CEIL_DIV(sizeof(m_loramngt_flash_config_data_t), 4)];
} m_loramngt_flash_config_t;

static bool                         m_fds_initialized = false;
static fds_record_desc_t            m_lora_record_config_desc;
static m_loramngt_flash_config_t    m_lora_config;
static bool                         m_lora_fds_config_write_success = false;

/**@brief Function for handling flash data storage events.
 */
static void loramngt_fds_evt_handler (fds_evt_t const * const p_fds_evt)
{
    switch (p_fds_evt->id)
    {
        case FDS_EVT_INIT:
            if (p_fds_evt->result == FDS_SUCCESS)
            {
                m_fds_initialized = true;
            }
            else
            {
                // Initialization failed.
                NRF_LOG_ERROR("FDS init failed!");
                APP_ERROR_CHECK_BOOL(false);
            }
            break;
			
        case FDS_EVT_WRITE:
            if (p_fds_evt->result == FDS_SUCCESS)
            {
                if (p_fds_evt->write.file_id == LORAMNGT_CONFIG_FILE_ID)
                {
                    NRF_LOG_INFO("FDS config write success! %d FileId: 0x%x RecKey:0x%x",   p_fds_evt->write.is_record_updated,
                                                                                            p_fds_evt->write.file_id,
                                                                                            p_fds_evt->write.record_key);
                    m_lora_fds_config_write_success = true;
                }
            }
            else
            {
                // Initialization failed.
                NRF_LOG_ERROR("FDS write failed!");
                APP_ERROR_CHECK_BOOL(false);
            }
            break;
			
        case FDS_EVT_UPDATE:
            if (p_fds_evt->result == FDS_SUCCESS)
            {
                if (p_fds_evt->write.file_id == LORAMNGT_CONFIG_FILE_ID)
                {
                    NRF_LOG_INFO("FDS config update success! %d FileId: 0x%x RecKey:0x%x",  p_fds_evt->write.is_record_updated,
                                                                                            p_fds_evt->write.file_id,
                                                                                            p_fds_evt->write.record_key);
                    m_lora_fds_config_write_success = true;
                }
            }
            else
            {
                // Initialization failed.
                NRF_LOG_ERROR("FDS write failed!");
                APP_ERROR_CHECK_BOOL(false);
            }		
            break;
			
			
        default:
            NRF_LOG_INFO("FDS handler - %d - %d", p_fds_evt->id, p_fds_evt->result);
            APP_ERROR_CHECK(p_fds_evt->result);
            break;
          
    }
}

uint32_t m_loramngt_flash_config_store (ble_loramngt_config_t *p_config)
{
    uint32_t        err_code;
    fds_record_t    record;

    NRF_LOG_INFO("Storing lora configuration");

    NULL_PARAM_CHECK(p_config);

    memcpy(&m_lora_config.data.config, p_config, sizeof(ble_loramngt_config_t));
    m_lora_config.data.valid = WS_FLASH_CONFIG_VALID;

    // Set up record.
    record.file_id              = LORAMNGT_CONFIG_FILE_ID;
    record.key                  = LORAMNGT_CONFIG_REC_KEY;
    record.data.length_words 	= sizeof(m_loramngt_flash_config_t)/4;
    record.data.p_data          = &m_lora_config;

    err_code = fds_record_update(&m_lora_record_config_desc, &record);
    RETURN_IF_ERROR(err_code);

    return NRF_SUCCESS;
}

uint32_t m_loramngt_flash_config_load (ble_loramngt_config_t **p_config)
{
    uint32_t            err_code;
    fds_flash_record_t  flash_record;
    fds_find_token_t    ftok;

    memset(&ftok, 0x00, sizeof(fds_find_token_t));

    NRF_LOG_INFO("Loading lora configuration");

    err_code = fds_record_find(LORAMNGT_CONFIG_FILE_ID, LORAMNGT_CONFIG_REC_KEY, &m_lora_record_config_desc, &ftok);
    RETURN_IF_ERROR(err_code);

    err_code = fds_record_open(&m_lora_record_config_desc, &flash_record);
    RETURN_IF_ERROR(err_code);

    memcpy(&m_lora_config, flash_record.p_data, sizeof(m_loramngt_flash_config_t));

    err_code = fds_record_close(&m_lora_record_config_desc);
    RETURN_IF_ERROR(err_code);

    *p_config = &m_lora_config.data.config;

    return NRF_SUCCESS;
}

uint32_t m_loramngt_flash_init (const ble_loramngt_config_t *p_lora_default_config, ble_loramngt_config_t **p_lora_config)
{
    uint32_t err_code;

    NULL_PARAM_CHECK(p_lora_default_config);

    err_code = fds_register(loramngt_fds_evt_handler);
    RETURN_IF_ERROR(err_code);

    err_code = fds_init();
    RETURN_IF_ERROR(err_code);

   while (m_fds_initialized == false)
    {
        app_sched_execute();
    }
	
    err_code = m_loramngt_flash_config_load(p_lora_config);
    if (err_code == FDS_ERR_NOT_FOUND)
    {
        NRF_LOG_INFO("Writing lora default config\r\n");

        fds_record_t record;

        memcpy(&m_lora_config.data.config, p_lora_default_config, sizeof(ble_loramngt_config_t));
        m_lora_config.data.valid = WS_FLASH_CONFIG_VALID;

        // Set up record.
        record.file_id              = LORAMNGT_CONFIG_FILE_ID;
        record.key                  = LORAMNGT_CONFIG_REC_KEY;
        record.data.length_words    = sizeof(m_loramngt_flash_config_t)/4;
        record.data.p_data          = &m_lora_config;
		
        m_lora_fds_config_write_success = false;
		
        err_code = fds_record_write(&m_lora_record_config_desc, &record);
        RETURN_IF_ERROR(err_code);

        *p_lora_config = &m_lora_config.data.config;

        while(m_lora_fds_config_write_success != true)
        {
            app_sched_execute();
        }
    }
    else
    {
        RETURN_IF_ERROR(err_code);
    }

    return NRF_SUCCESS;
}
