/*
 * Copyright (c) 2018-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 _CNVMCAMERAMODULE_HPP_
#define _CNVMCAMERAMODULE_HPP_

#include "NvSIPLPlatformCfg.hpp"
#include "DeserializerIF/CNvMDeserializer.hpp"
#include "utils/utils.hpp"

namespace nvsipl
{

class CNvMCameraModule

{
public:
    struct CameraModuleConfig {
        //! Settings specific to this camera module
        const CameraModuleInfo *cameraModuleInfo;

        //! Device parameters (simulator, slave, etc)
        CNvMDevice::DeviceParams *params;

        //! Pointer to the deserializer
        CNvMDeserializer *deserializer;

        //! A bitmask of which links this camera module object is responsible for initializing
        //! Only applicable if group Init is enabled
        uint8_t initLinkMask;

        //! Whether group Init is enabled
        bool groupInitProg;
    };

    typedef struct {
        typedef struct {
            typedef struct {
                bool isNeeded;          //Need release reset
                uint8_t pinNum;         //Serializer pin number
                bool releaseResetLevel; //Logic level to release reset
            } SensorReset;

            typedef struct {
                uint8_t pinNum;         //Serializer pin number
            } FrameSync;

            typedef struct {
                bool isNeeded;          //Need release reset
                uint8_t pinNum;         //Serializer pin number
            } RefClock;

            typedef struct {
                bool isLaneSwapNeeded;
                bool isTwoLane;
            } PhyLanes;

            SensorReset sensorReset;

            FrameSync frameSync;

            RefClock refClock;

            PhyLanes phyLanes;

            //! Holding native address for sensor
            std::uint8_t uBrdcstSensorAddrs;

            //! Holding translation address for sensors
            std::uint8_t uSensorAddrs;

            //! Holding VCID
            std::uint8_t uVCID;

            //! Holding ICP input format type
            NvMediaICPInputFormat inputFormat;

            //! Holding embedded data type.
            //! false means EMB coming with pixel data and true means EMB coming in CSI packet with different data type
            bool bEmbeddedDataType;

            //! Flag indicating whether trigger mode sync has been enabled or not
            bool bEnableTriggerModeSync;

            //! Holding frame rate
            float fFrameRate;

            //! Holding sensor image width
            uint32_t width;

            //! Holding sensor image height
            uint32_t height;

            //! Holding sensor number of top embedded lines
            uint32_t embeddedTop;

            //! Holding sensor number of bottom embedded lines
            uint32_t embeddedBot;

            //! Holding whether sensor TPG is enabled
            bool bEnableTPG;

            //! Holding whether FSYNC should be enabled before or after sensor init
            bool bPostSensorInitFsync;

            //! Holding sensor pclk
            uint32_t pclk;

            //! Holding the serializer regen Vsync high
            uint32_t vsyncHigh;

            //! Holding the serializer regen Vsync low
            uint32_t vsyncLow;

            //! Holding the serializer regen Vsync delay
            uint32_t vsyncDelay;

            //! Holding the serializer regen Vsync trigger edge
            uint32_t vsyncTrig;

            //! Holding the sensor description
            std::string sensorDescription = "";

        } SensorConnectionProperty;

        SensorConnectionProperty sensorConnectionProperty;

        //! Holding native address for EEPROM
        std::uint8_t brdcstEepromAddr;

        //! Holding translation address for EEPROM. Same size as brdcstEepromAddr
        std::uint8_t eepromAddr;

        std::uint16_t powerOnDelay;
    } ConnectionProperty;

    typedef struct {
        typedef struct {
            uint32_t id;
            uint32_t virtualChannelID;
            NvMediaICPInputFormat inputFormat;
            NvMediaSurfaceType surfaceType;
            uint32_t width;
            uint32_t height;
            uint32_t startX;
            uint32_t startY;
            uint32_t embeddedTop;
            uint32_t embeddedBot;
            float frameRate;
            bool embeddedDataType;
            DevBlkCDIDevice *pCDIHandle;
        } SensorProperty;

        typedef struct {
            bool isEEPROMSupported = false;
            DevBlkCDIDevice *pCDIHandle;
        } EEPROMProperty;

        SensorProperty sensorProperty;

        EEPROMProperty eepromProperty;
    } Property;

    static constexpr uint32_t MAJOR_VER  = 1U; /* Major Revison */
    static constexpr uint32_t MINOR_VER  = 0U; /* Minor Revision */
    static constexpr uint32_t PATCH_VER  = 0U; /* Patch Revision */

    //! Camera Module API version
    struct Version
    {
        uint32_t uMajor = MAJOR_VER;
        uint32_t uMinor = MINOR_VER;
        uint32_t uPatch = PATCH_VER;
    };

    //! Virtual destructor
    virtual ~CNvMCameraModule() = default;

    //! Get Camera module properties
    virtual Property* GetCameraModuleProperty() = 0;

    //! Store configuration information and allocate VCID
    virtual SIPLStatus SetConfig(const CameraModuleConfig *cameraModuleConfig, const uint8_t linkIndex) = 0;

    //! Do any initialization that needs to be done before the capture pipeline is started
    virtual SIPLStatus Init() = 0;

    //! Do any post initialization that needs to be done before the capture pipeline is started
    virtual SIPLStatus PostInit() = 0;

    //! Reconfigure the given camera module
    virtual SIPLStatus Reconfigure() = 0;

    //! Read from an EEPROM in the camera module
    virtual SIPLStatus ReadEEPROMData(const std::uint16_t address,
                                      const std::uint32_t length,
                                      std::uint8_t * const buffer) = 0;

#if !NV_IS_SAFETY
    //! Write to an EEPROM in the camera module
    virtual SIPLStatus WriteEEPROMData(const std::uint16_t address,
                                       const std::uint32_t length,
                                       std::uint8_t * const buffer) = 0;
#endif // !NV_IS_SAFETY

    //! Enable/disable LED on the given camera module
    virtual SIPLStatus ToggleLED(bool enable) = 0;

    //! Steps to be done after the capture pipeline has started
    virtual SIPLStatus Start() = 0;

    //! Steps to be done when quitting, before shuttind down the capture pipeline
    virtual SIPLStatus Stop() = 0;

    //! Deinitialized the camera module
    virtual SIPLStatus Deinit() = 0;

    //! Return a string to identify the supported deserializer (eg "MAX96712")
    virtual std::string GetSupportedDeserailizer() = 0;

    //! Create the CDI devices needed by the camera module
    virtual SIPLStatus CreateCDIDevice(DevBlkCDIRootDevice* cdiRoot) = 0;

    //! After the device is powered on, wait this many milliseconds before programming
    virtual uint16_t GetPowerOnDelayMs() = 0;

    //! Get the type of link between the serializer and deserializer
    virtual CNvMDeserializer::LinkMode GetLinkMode() = 0;
};

} // end of namespace
#endif //_CNVMCAMERAMODULE_HPP_

