/*
 * Copyright (c) 2018-2020, NVIDIA CORPORATION.  All rights reserved. All
 * information contained herein is proprietary and confidential to NVIDIA
 * Corporation.  Any use, reproduction, or disclosure without the written
 * permission of NVIDIA Corporation is prohibited.
 */

#ifndef _CNVMDEVICE_HPP_
#define _CNVMDEVICE_HPP_

#include <string>
#include <memory>

#include "utils/CNvMI2CAddrMgr.hpp"
#include "NvSIPLPlatformCfg.hpp"
#include "devblk_cdi.h"
#include "utils/utils.hpp"

namespace nvsipl
{

//! Base class representing a generic device
class CNvMDevice
{
public:
    //! Device Parameter structure
    typedef struct {
        bool bEnableSimulator;
        bool bSlave;
        bool bUseNativeI2C;
        CNvMI2CAddrMgr *pI2CAddrMgr;
    } DeviceParams;

    //! CDI configure and its description
    typedef struct {
        std::uint32_t cmd;
        std::string description;
    } ConfigCmd;

    struct DriverContext {
        virtual void *GetPtr() = 0;
        virtual ~DriverContext() = default;
    };

    template <typename ContextType>
    struct DriverContextImpl : public DriverContext {
        ContextType m_Context;
        void *GetPtr() override {return &m_Context;}
        ~DriverContextImpl() = default;
    };

    virtual SIPLStatus CreateCDIDevice(DevBlkCDIRootDevice* cdiRoot);

    //! Destructor
    virtual ~CNvMDevice();

    //! Get CDI handle
    virtual DevBlkCDIDevice* GetCDIDeviceHandle() final;

    //! Get I2C address
    virtual uint8_t GetI2CAddr() final;

    //! Get Native I2C address
    virtual uint8_t GetNativeI2CAddr() final;

    virtual SIPLStatus Init();

    virtual SIPLStatus Start();

    virtual SIPLStatus Stop();

    virtual SIPLStatus Reset();

    virtual SIPLStatus Deinit();

protected:
    //! Constructor
    CNvMDevice();

    enum DeviceState {
        CREATED = 0,
        CDI_DEVICE_CONFIG_SET,
        CDI_DEVICE_CREATED,
        INIT_1_DONE,
        INIT_2_DONE,
        INIT_3_DONE,
        INIT_4_DONE,
        STARTED,
        STOPPED,
        DEINIT
    };

    //! Holding internal transition state
    DeviceState m_eState;

    //! Pointer pointing to CDI device driver
    DevBlkCDIDeviceDriver *m_pCDIDriver;

    //! Pointer pointing to advanced driver context for init
    std::unique_ptr<DriverContext> m_upDrvContext;

    //! CDI advanced configure
    DevBlkCDIAdvancedConfig m_oAdvConfig{};

    //! Unique pointer pointing to CDI device handle
    std::unique_ptr<DevBlkCDIDevice, CloseDevBlkCDI> m_upCDIDevice;

    //! Holding device parameters
    DeviceParams m_oDeviceParams;

    //! Holding i2c address
    uint8_t m_i2CAddr;

    //! Holding native I2C address
    uint8_t m_nativeI2CAddr;
};

} // end of namespace nvsipl
#endif //_CNVMDEVICE_HPP_
