/*
 * 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.
 */

#include "CNvMDevice.hpp"

namespace nvsipl
{

CNvMDevice::CNvMDevice()
{
    m_eState = CREATED;
    m_pCDIDriver = NULL;
    m_oAdvConfig = {};
    m_oDeviceParams = {};
    m_i2CAddr = 0;
    m_nativeI2CAddr = 0;
}

CNvMDevice::~CNvMDevice()
{
    Deinit();
}

SIPLStatus CNvMDevice::CreateCDIDevice(DevBlkCDIRootDevice* cdiRoot)
{

    DevBlkCDIDevice* cdiDevice = NULL;
    std::uint32_t addressList[1] = {};
    DevBlkCDIAdvancedConfig *pCDIAdvConfig = NULL;

    if (m_eState != CDI_DEVICE_CONFIG_SET) {
        LOG_ERR("CDI device config is not set\n");
        return NVSIPL_STATUS_INVALID_STATE;
    }

    if (cdiRoot == NULL) {
        LOG_ERR("CDI root device is NULL\n");
        return NVSIPL_STATUS_BAD_ARGUMENT;
    }

    // Generate I2c address
    if (m_oDeviceParams.bUseNativeI2C) {
        m_i2CAddr = m_nativeI2CAddr;
    } else {
        m_i2CAddr = m_oDeviceParams.pI2CAddrMgr->GenerateI2CAddr(m_nativeI2CAddr);
    }

    if (m_oDeviceParams.bEnableSimulator or m_oDeviceParams.bSlave) {
        addressList[0] = DEVBLK_CDI_SIMULATOR_ADDRESS;
    } else {
        addressList[0] = m_i2CAddr;
    }

    CHK_PTR_AND_RETURN(addressList[0], "Failed to get I2C address");

    if (m_upDrvContext != NULL) {
        m_oAdvConfig.clientContext = m_upDrvContext->GetPtr();
        pCDIAdvConfig = &m_oAdvConfig;
    }

    // Create the CDI device
    cdiDevice = DevBlkCDIDeviceCreate(cdiRoot,
                                       addressList,
                                       1,
                                       m_pCDIDriver,
                                       pCDIAdvConfig);
    CHK_PTR_AND_RETURN(cdiDevice, "DevBlkCDIDeviceCreate in CNvMSensor::Init");
    m_upCDIDevice = std::unique_ptr<DevBlkCDIDevice, CloseDevBlkCDI>(
            cdiDevice);

    m_eState = CDI_DEVICE_CREATED;
    return NVSIPL_STATUS_OK;
}

SIPLStatus CNvMDevice::Init()
{
    if (m_eState != CDI_DEVICE_CREATED) {
        LOG_ERR("CDI device invalid state\n");
        return NVSIPL_STATUS_INVALID_STATE;
    }

    m_eState = INIT_4_DONE;
    return NVSIPL_STATUS_OK;
}


SIPLStatus CNvMDevice::Start()
{
    if (m_eState != INIT_4_DONE) {
        LOG_ERR("CDI device invalid state\n");
        return NVSIPL_STATUS_INVALID_STATE;
    }

    m_eState = STARTED;
    return NVSIPL_STATUS_OK;
}

SIPLStatus CNvMDevice::Stop()
{
    if (m_eState != STARTED) {
        LOG_ERR("CDI device invalid state\n");
        return NVSIPL_STATUS_INVALID_STATE;
    }

    m_eState = STOPPED;
    return NVSIPL_STATUS_OK;
}

SIPLStatus CNvMDevice::Reset()
{
    m_eState = CDI_DEVICE_CREATED;
    return NVSIPL_STATUS_OK;
}

SIPLStatus CNvMDevice::Deinit()
{
    m_upCDIDevice.reset();

    m_eState = DEINIT;
    return NVSIPL_STATUS_OK;
}

//! Get CDI handle
DevBlkCDIDevice* CNvMDevice::GetCDIDeviceHandle()
{
    if (m_eState == CREATED or m_eState == CDI_DEVICE_CONFIG_SET) {
        LOG_ERR("CDI device not created\n");
        return NULL;
    }

    return m_upCDIDevice.get();
}

//! Get I2C address
uint8_t CNvMDevice::GetI2CAddr()
{
    if (m_eState == CREATED or m_eState == CDI_DEVICE_CONFIG_SET) {
        LOG_ERR("CDI device not created\n");
        return 0;
    }

    return m_i2CAddr;
}

//! Get I2C address
uint8_t CNvMDevice::GetNativeI2CAddr()
{
    if (m_eState == CREATED) {
        LOG_ERR("CDI device config is not set\n");
        return 0;
    }

    return m_nativeI2CAddr;
}

} // end of nvsipl
