/*
 * Copyright (c) 2019-2020, NVIDIA CORPORATION.  All rights reserved.
 *
 * NVIDIA CORPORATION and its licensors retain all intellectual property
 * and proprietary rights in and to this software, related documentation
 * and any modifications thereto.  Any use, reproduction, disclosure or
 * distribution of this software and related documentation without an express
 * license agreement from NVIDIA CORPORATION is strictly prohibited.
 */
#ifndef _UTILS_HPP_
#define _UTILS_HPP_

#include "NvSIPLCommon.hpp"
#include "trace/CNvMTrace.hpp"
#include "devblk_cdi.h"
#include <thread>
#include <chrono>
#include <cstdio>


// Utility functions and macros
#define SLEEP_MS(x) std::this_thread::sleep_for (std::chrono::milliseconds(x))
#define SLEEP_US(x) std::this_thread::sleep_for (std::chrono::microseconds(x))

// Free standing function to convert/map NvMediaStatus to nvsipl::SIPLStatus
inline nvsipl::SIPLStatus ConvertNvMediaStatus(NvMediaStatus nvmStatus)
{
    switch (nvmStatus) {
     case NVMEDIA_STATUS_OK:
         return nvsipl::NVSIPL_STATUS_OK;
         break;
     case NVMEDIA_STATUS_BAD_PARAMETER:
         return nvsipl::NVSIPL_STATUS_BAD_ARGUMENT;
         break;
     default:
         return nvsipl::NVSIPL_STATUS_ERROR;
         break;
     }
}

#define CHK_NVMERROR_AND_FAIL(nvmStatus, nvmFunction) \
    if (nvmStatus != NVMEDIA_STATUS_OK) { \
        LOG_ERR("%s failed! with NvMedia error: %d\n", nvmFunction, nvmStatus); \
        goto failed; \
    }

#define CHK_NVMERROR_CONVERT_AND_RETURN(nvmStatus, nvmFunction) \
    if (nvmStatus != NVMEDIA_STATUS_OK) { \
        LOG_ERR("%s failed! with NvMedia error: %d\n", nvmFunction, nvmStatus); \
        return ConvertNvMediaStatus(nvmStatus); \
    }

#define CHK_NVMERROR(nvmStatus, nvmFunction) \
    if (nvmStatus != NVMEDIA_STATUS_OK) { \
        LOG_ERR("%s failed! with NvMedia error: %d\n", nvmFunction, nvmStatus); \
    }

#define CHK_PTR_AND_RETURN(ptr, function) \
    if (!ptr) { \
        LOG_ERR("%s failed!\n", function); \
        return NVSIPL_STATUS_ERROR; \
    }

#define CHK_PTR(ptr, function) \
    if (!ptr) { \
        LOG_ERR("%s failed!\n", function); \
    }

#define CHK_NVSIPLEERROR_AND_FAIL(nvsiplStatus, function) \
    if (nvsiplStatus != NVSIPL_STATUS_OK) { \
        LOG_ERR("%s failed! with error: %x\n", function, nvsiplStatus); \
        goto failed; \
    }

#define CHK_NVSIPLEERROR_AND_RETURN(nvsiplStatus, function) \
    if (nvsiplStatus != NVSIPL_STATUS_OK) { \
        LOG_ERR("%s failed! with error: %x\n", function, nvsiplStatus); \
        return nvsiplStatus; \
    }

#define NVSIPL_IsSucceeded(cond)   ((cond) == NVSIPL_STATUS_OK)

#define NVSIPL_IsFailed(cond)      ((cond) != NVSIPL_STATUS_OK)

namespace nvsipl
{

struct CloseDevBlkCDIRoot {
    void operator ()(DevBlkCDIRootDevice *device) const {
        DevBlkCDIRootDeviceDestroy(device);
    }
};

struct CloseDevBlkCDI {
    void operator ()(DevBlkCDIDevice *device) const {
        DevBlkCDIDeviceDestroy(device);
    }
};

struct CloseNvMediaDevice {
    void operator ()(NvMediaDevice *device) const {
        NvMediaDeviceDestroy(device);
    }
};

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