/*!
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* All rights reserved.
*
* \file NV_FsciCommands.c
* This file implemens the handler functions for he request received from FSCI
* and the NVM moitoring functions.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
*   of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
*   list of conditions and the following disclaimer in the documentation and/or
*   other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
*   contributors may be used to endorse or promote products derived from this
*   software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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
*************************************************************************************
************************************************************************************/

#include "EmbeddedTypes.h"
#include "Messaging.h"
#include "FunctionLib.h"
#include "NVM_Interface.h"

#if gFsciIncluded_c && gNvStorageIncluded_d
#include "FsciInterface.h"
#include "FsciCommands.h"
#include "NV_FsciCommands.h"

/******************************************************************************
*******************************************************************************
* Private functions prototype
******************************************************************************
******************************************************************************/

/*****************************************************************************
*****************************************************************************
* Private memory declarations
*****************************************************************************
*****************************************************************************/
#if gNvmEnableFSCIMonitoring_c
bool_t  nvmMonitorOn = TRUE;
#endif

/*****************************************************************************
*****************************************************************************
* Public functions
*****************************************************************************
*****************************************************************************/

/*****************************************************************************
*****************************************************************************
* Private functions
*****************************************************************************
*****************************************************************************/

#if gNvmEnableFSCIRequests_c
void NV_FsciMsgHandler( void* pData, void*param, uint32_t fsciInterface )
{
    bool_t reusePkt = FALSE;

    switch(((clientPacket_t*)pData)->structured.header.opCode)
    {
    case mFsciMsgNVSaveReq_c:
        reusePkt = FSCI_MsgNVSaveReqFunc( pData, fsciInterface );
        break;

    case mFsciMsgGetNVDataSetDescReq_c:
        reusePkt = FSCI_MsgGetNVDataSetDescReqFunc( pData, fsciInterface );
        break;

    case mFsciMsgGetNVCountersReq_c:
        reusePkt = FSCI_MsgGetNVCountersReqFunc( pData, fsciInterface );
        break;

    case mFsciMsgSetNVMonitoringReq_c:
        reusePkt = FSCI_MsgSetNVMonitoring( pData, fsciInterface );
        break;

    case mFsciMsgFormatNvmReq_c:
        reusePkt = FSCI_MsgNVFormatReq( pData, fsciInterface );
        break;

    case mFsciMsgRestoreNvmReq_c:
        reusePkt = FSCI_MsgNVRestoreReq( pData, fsciInterface );
        break;

    default:
        FSCI_Error( gFsciUnknownOpcode_c, fsciInterface );
        break;
    }
    
    if(reusePkt)
    {
        ((clientPacket_t*)pData)->structured.header.opGroup = gNV_FsciCnfOG_d;
        FSCI_transmitFormatedPacket( pData, fsciInterface );
    }
    else
    {
        MSG_Free(pData);
    }
}

/******************************************************************************
Name: FSCI_MsgNVSaveReqFunc
Description:
In:
None
Out:
None
******************************************************************************/
bool_t FSCI_MsgNVSaveReqFunc(void* pData, uint32_t fsciInterface)
{
    uint16_t countInd=0;
    uint16_t dataSetIndex=0;
    uint16_t dataSetElement=0;
    NVM_DataEntry_t* pNVM_DataTableEntry=NULL;
    
    ((clientPacket_t*)pData)->structured.header.len = sizeof(clientPacketStatus_t);
    
    dataSetIndex = ((clientPacket_t*)pData)->structured.payload[1];
    dataSetIndex <<= 8;
    dataSetIndex+= ((clientPacket_t*)pData)->structured.payload[0];
    
    /* Look in NVM table for the dataset entry */
    while (gNvEndOfTableId_c != (pNVM_DataTable+countInd)->DataEntryID)
    {
        if(dataSetIndex == (pNVM_DataTable+countInd)->DataEntryID)
        {
            pNVM_DataTableEntry = pNVM_DataTable+countInd;
            break;
        }
        countInd++;
    }
    
    if( NULL == pNVM_DataTableEntry)
    {
        /* data set not found */
        ((clientPacket_t*)pData)->structured.payload[0] = gNVM_InvalidTableEntry_c; 
        return TRUE;
    }
    
    if(!((clientPacket_t*)pData)->structured.payload[5])
    {
        dataSetElement = ((clientPacket_t*)pData)->structured.payload[2];
        dataSetElement <<= 8;
        dataSetElement += ((clientPacket_t*)pData)->structured.payload[3];
    }
    
    
    switch(((clientPacket_t*)pData)->structured.payload[4])
    {
    case 0:
        ((clientPacket_t*)pData)->structured.payload[0] = NvSaveOnIdle((uint8_t*)(pNVM_DataTableEntry->pData)+
                                                                       dataSetElement*pNVM_DataTableEntry->ElementSize,
                                                                       !!((clientPacket_t*)pData)->structured.payload[5]);
          break;
    case 1:
        ((clientPacket_t*)pData)->structured.payload[0] = NvSaveOnInterval(pNVM_DataTableEntry->pData);
        break;
    case 2:
        ((clientPacket_t*)pData)->structured.payload[0] = NvSaveOnCount(pNVM_DataTableEntry->pData);
        break;
    case 3:
        if(!!((clientPacket_t*)pData)->structured.payload[6])
        {
            ((clientPacket_t*)pData)->structured.payload[0] = NvAtomicSave(TRUE);
        }
        else
        {
            ((clientPacket_t*)pData)->structured.payload[0] = 
                NvSyncSave((uint8_t*)(pNVM_DataTableEntry->pData)+
                           dataSetElement*pNVM_DataTableEntry->ElementSize,
                           !!((clientPacket_t*)pData)->structured.payload[5],
                           FALSE);
        }
        break;
    default:
        ((clientPacket_t*)pData)->structured.payload[0] = gNVM_SaveRequestRejected_c; 
        break;
    }  
    return TRUE;
}

/******************************************************************************
Name: FSCI_MsgGetNVDataSetDescReqFunc
Description:
In:
None
Out:
None
******************************************************************************/
bool_t FSCI_MsgGetNVDataSetDescReqFunc(void* pData, uint32_t fsciInterface)
{
    uint16_t dataSetIndex;
    uint8_t payload[9];
    uint32_t address; 
    
    /* Left for nvm table count */  
    payload[0]=0;
    dataSetIndex = ((clientPacket_t*)pData)->structured.payload[1];
    dataSetIndex <<= 8;
    dataSetIndex+= ((clientPacket_t*)pData)->structured.payload[0];
    address = (uint32_t)(pNVM_DataTable+dataSetIndex)->pData;
    
    FLib_MemCpy(&payload[1],&address,4);
    FLib_MemCpy(&payload[5],&(pNVM_DataTable+dataSetIndex)->DataEntryID,2);
    payload[7] = ((pNVM_DataTable+dataSetIndex)->ElementSize & 0xFF);
    payload[8] = ((pNVM_DataTable+dataSetIndex)->ElementsCount & 0xFF);
    FSCI_transmitPayload(gNV_FsciCnfOG_d, mFsciMsgGetNVDataSetDescReq_c,payload,9,fsciInterface);  

    return FALSE;
    
}

/*********************************************  *********************************
Name: FSCI_MsgGetNVCountersReqFunc
Description:
In:
None
Out:
None
******************************************************************************/
bool_t FSCI_MsgGetNVCountersReqFunc(void* pData, uint32_t fsciInterface)
{
    NVM_Statistics_t ptrStat;
    uint8_t payload[sizeof(NVM_Statistics_t)+1];

    payload[0] = 0; 
    NvGetPagesStatistics(&ptrStat);
    FLib_MemCpy(&payload[1],&ptrStat.FirstPageEraseCyclesCount,4);
    FLib_MemCpy(&payload[5],&ptrStat.SecondPageEraseCyclesCount,4);
    FSCI_transmitPayload(gNV_FsciCnfOG_d,mFsciMsgGetNVCountersReq_c,payload,sizeof(NVM_Statistics_t)+1,fsciInterface);

    return FALSE;
}

/******************************************************************************
Name: FSCI_MsgSetNVMonitoring
Description:
In:
None
Out:
None
******************************************************************************/
bool_t FSCI_MsgSetNVMonitoring(void* pData, uint32_t fsciInterface)
{
#if !gNvmEnableFSCIMonitoring_c
    (void)pData;
    FSCI_Error( gFsciRequestIsDisabled_c, fsciInterface );    
    return FALSE;
#else
    nvmMonitorOn = !!((clientPacket_t*)pData)->structured.payload[0];
    ((clientPacket_t*)pData)->structured.payload[0] = 0;
    ((clientPacket_t*)pData)->structured.header.len = sizeof(clientPacketStatus_t);
    return TRUE;
#endif/* gNvStorageIncluded_d*/
}

/******************************************************************************
Name: FSCI_MsgNVFormatReq
Description:
In:
None
Out:
None
******************************************************************************/
bool_t FSCI_MsgNVFormatReq(void* pData, uint32_t fsciInterface)
{
    ((clientPacket_t*)pData)->structured.header.len = sizeof(clientPacketStatus_t);
    ((clientPacket_t*)pData)->structured.payload[0] = NvFormat();
    return TRUE;
}

/******************************************************************************
Name: FSCI_MsgNVRestoreReq
Description:
In:
None
Out:
None
******************************************************************************/
bool_t FSCI_MsgNVRestoreReq(void* pData, uint32_t fsciInterface)
{
    uint16_t countInd=0;
    uint16_t dataSetIndex;
    uint16_t dataSetElement=0;
    bool_t fSave;
    uint8_t status = gNVM_InvalidTableEntry_c;
    
    dataSetIndex = ((clientPacket_t*)pData)->structured.payload[3];
    dataSetIndex <<= 8;
    dataSetIndex+= ((clientPacket_t*)pData)->structured.payload[2];
    
    while (gNvEndOfTableId_c != (pNVM_DataTable+countInd)->DataEntryID)
    {
        fSave=FALSE;
        if(((clientPacket_t*)pData)->structured.payload[0])
        {
            fSave = TRUE;
            dataSetElement=0;
        }
        else
        {
            if(dataSetIndex ==  (pNVM_DataTable+countInd)->DataEntryID)
            {
                if(gNvInvalidDataEntry_c != (pNVM_DataTable+countInd)->DataEntryID)
                {
                    fSave = TRUE;
                }
                else
                {
                    break;
                }
            }  
        }
        if(fSave)
        {    
            uint8_t* pData= (pNVM_DataTable+countInd)->pData;
            pData += dataSetElement * (pNVM_DataTable+countInd)->ElementSize;
            status = NvRestoreDataSet(pData,!!((clientPacket_t*)pData)->structured.payload[1]);
            if((!((clientPacket_t*)pData)->structured.payload[0])||(status))
            {
                break;
            }
        }
        countInd++;
    }

    ((clientPacket_t*)pData)->structured.header.len = sizeof(clientPacketStatus_t);
    ((clientPacket_t*)pData)->structured.payload[0] = status;
    return TRUE;
}
#endif

#if gNvmEnableFSCIMonitoring_c
/******************************************************************************
Name: FSCI_MsgNVPageEraseMonitoring
Description:
In:
None
Out:
None
******************************************************************************/
void FSCI_MsgNVPageEraseMonitoring(uint32_t pageAddress, uint8_t status)
{
    uint8_t payload[5];

    if(!nvmMonitorOn)
        return;
    
    FLib_MemCpy(&payload[0],&pageAddress ,4);
    payload[4]=status;

    FSCI_transmitPayload(gNV_FsciCnfOG_d,
                         mFsciMsgNVPageEraseMonitoring_c,
                         payload,
                         sizeof(payload),
                         gNvmDefaultFsciInterface_c);
}

/******************************************************************************
Name: FSCI_MsgNVWriteMonitoring
Description:
In:
None
Out:
None
******************************************************************************/
void FSCI_MsgNVWriteMonitoring(uint16_t nvmTableEntryId, uint16_t elementIndex, uint8_t saveRestoreAll)
{
    uint8_t payload[5];

    if( !nvmMonitorOn )
        return;
    
    FLib_MemCpy(&payload[0],&nvmTableEntryId ,2);
    FLib_MemCpy(&payload[2],&elementIndex ,2);
    payload[4]=saveRestoreAll;

#if mGetFsciInterfaceFromNvTableEntryId_d
    FSCI_transmitPayload(gNV_FsciCnfOG_d,
                         mFsciMsgNVWriteMonitoring_c,
                         payload,
                         sizeof(payload),
                         nvmTableEntryId>>12);
#else
    FSCI_transmitPayload(gNV_FsciCnfOG_d,
                         mFsciMsgNVWriteMonitoring_c,
                         payload,
                         sizeof(payload),
                         gNvmDefaultFsciInterface_c);
#endif
}

/******************************************************************************
Name: FSCI_MsgNVRestoreMonitoring
Description:
In:
None
Out:
None
******************************************************************************/
void FSCI_MsgNVRestoreMonitoring(uint16_t nvmTableEntryId, bool_t bStart, uint8_t status)
{
    uint8_t payload[4];
    
    if(!nvmMonitorOn)
        return;
    
    FLib_MemCpy(&payload[0],&nvmTableEntryId ,2);
    payload[2]=bStart;
    payload[3]=status;

#if mGetFsciInterfaceFromNvTableEntryId_d
    FSCI_transmitPayload(gNV_FsciCnfOG_d,
                         mFsciMsgRestoreMonitoring_c,
                         payload,
                         sizeof(payload),
                         nvmTableEntryId>>12);
#else
    FSCI_transmitPayload(gNV_FsciCnfOG_d,
                         mFsciMsgRestoreMonitoring_c,
                         payload,
                         sizeof(payload),
                         gNvmDefaultFsciInterface_c);
#endif
}

/******************************************************************************
Name: FSCI_MsgNVVirtualPageMonitoring
Description:
In:
None
Out:
None
******************************************************************************/                        
void FSCI_MsgNVVirtualPageMonitoring(bool_t bStart, uint8_t status)
{
    uint8_t payload[2];
    
    if(!nvmMonitorOn)
        return;

    payload[0]=bStart;
    payload[1]=status;

    FSCI_transmitPayload(gNV_FsciCnfOG_d,
                         mFsciMsgVirtualPageMonitoring_c,
                         payload,
                         sizeof(payload),
                         gNvmDefaultFsciInterface_c); 
}

#endif //#if gNvmEnableFSCIMonitoring_c

#endif //gFsciIncluded_c