/*************************************************************************************************
// INTEL CONFIDENTIAL Copyright 2011-2017 Intel Corporation All Rights Reserved.
//
// The source code contained or described herein and all documents related to the source code
// ("Material") are owned by Intel Corporation or its suppliers or licensors. Title to the Material
// remains with Intel Corporation or its suppliers and licensors. The Material contains trade secrets
// and proprietary and confidential information of Intel or its suppliers and licensors. The Material is
// protected by worldwide copyright and trade secret laws and treaty provisions. No part of the
// Material may be used, copied, reproduced, modified, published, uploaded, posted, transmitted,
// distributed, or disclosed in any way without Intel's prior express written permission.
//
// No license under any patent, copyright, trade secret or other intellectual property right is
// granted to or conferred upon you by disclosure or delivery of the Materials, either expressly, by
// implication, inducement, estoppel or otherwise. Any license under such intellectual property
// rights must be express and approved by Intel in writing.
//*************************************************************************************************/

#ifdef SKY_CAM

#include "device.h"
#include "trace.h"
#include <math.h>
#include "Ssreader.h"
#include "Sample_setting.c"
#include "Sample_skc.tmh"


extern NTSTATUS EnableEmbeddedLine(PDEVICE_CONTEXT SensorCtx);




NTSTATUS SampleCmd_SetExtFeature(
    PDEVICE_CONTEXT SensorCtx,
    SNSR_EXT_FEATURE_ID Feature,
    ULONG_PTR Value
)
{
    NTSTATUS status = STATUS_SUCCESS;

    CHECK_POINTER(SensorCtx)
    CHECK_POINTER(Value)

    DoTraceMessage(FLAG_LOG, "%s SampleCmd_SetExtFeature+ Feature: %d\n", DEVICE_NAME, Feature);

    switch (Feature)
    {
    case SNSR_EXT_FEATURE_PRIVACY_LED:
    {
        switch (*((SNSR_EXT_FEATURE_PRIVACY_LED_STATE *)Value))
        {
        case SNSR_EXT_FEATURE_PRIVACY_LED_OFF:
        {

            status = SensorCtx->ControlLogicInterface->PrivacyLedOff(
                SensorCtx->ControlLogicInterface->InterfaceHeader.Context, &SensorCtx->SensorConf);

            break;
        }
        case SNSR_EXT_FEATURE_PRIVACY_LED_ON:
        {

            status = SensorCtx->ControlLogicInterface->PrivacyLedOn(
                SensorCtx->ControlLogicInterface->InterfaceHeader.Context, &SensorCtx->SensorConf);

            break;
        }
        default:
            status = STATUS_INVALID_PARAMETER_3;
        }

        break;
    }
    default:
        status = STATUS_NOT_SUPPORTED;
    }

done:
    DoTraceMessage(
        FLAG_LOG,
        "%s SampleCmd_SetExtFeature- , returns with code: 0x%x\n", DEVICE_NAME, status);
    return status;
}

NTSTATUS SampleCmd_GetSensorLink(
    PDEVICE_CONTEXT SensorCtx,
    PSENSOR_LINK LinkConfig)
{
    NTSTATUS status = STATUS_SUCCESS; 
    int i = 1;
    SENSOR_MODE_DATA ModeData = { .BinningFactorX = 1 };
    BOOLEAN SensorPowerOn = FALSE;
    VC_SETTINGS *vcSettings = &(LinkConfig->VcSettings[0]);
    CHECK_POINTER_INVALID(SensorCtx)
    DoTraceMessage(FLAG_ERROR, "--- before IRQL:%d--", KeGetCurrentIrql());
    status = KeWaitForSingleObject(&SensorCtx->SettingEvent, Executive, KernelMode, FALSE, NULL);
    if (!CHECK_STATUS_SUCCESS(status))
    {
        DoTraceMessage(FLAG_ERROR, "--- error --");
        DoTraceMessage(FLAG_ERROR, "%s SampleCmd_GetSensorLink KeWaitForSingleObject fail, (status 0x%x)\n",
            DEVICE_NAME, status);
        goto invalid;
    }
    DoTraceMessage(FLAG_ERROR, "--- after IRQL:%d--", KeGetCurrentIrql());
    LinkConfig->LinkUsed = SensorCtx->SensorDriverView.LinkUsed;
    LinkConfig->LanesUsed = SensorCtx->SensorDriverView.LanesUsed;
    LinkConfig->HostControllerGlobal.G_LanesClockDivision = SensorCtx->SensorDriverView.HostControllerGlobal.G_LanesClockDivision;
    LinkConfig->HostControllerID.Csi2.InstanceID.BdfValue = SensorCtx->SensorDriverView.HostController.InstanceID.BdfValue;

    memcpy_s(&(LinkConfig->LinkDelayParameters), sizeof(LINK_DELAY_PARAMETERS), &(SensorCtx->SensorDriverView.LinkDelayParameters), sizeof(LINK_DELAY_PARAMETERS));
    if (LinkConfig->LinkSharingKey != 0xFF)
        SensorPowerOn = TRUE;
    
    if (SensorPowerOn)//only when sensor is power on, you can read this information
    {
        ULONG data = 0;
        ULONG pre_pll1_perdiv0;
        ULONG pll1_m_divider;
        ULONG pll1_multiplier;
        ULONG data1 = 0;

        float    pre_pll1_perdiv;
        float pre_pll1_perdiv_val[8]= {1, 1.5, 2, 2.5, 3, 4, 6, 8};
        GetTimingFactor(SensorCtx, &ModeData); 

        status = RegRead(SensorCtx, REG_PLL1_PREDIV0, &data, DATA_8BITS);
        if (!NT_SUCCESS(status))
            goto done;
        pre_pll1_perdiv0 = ((data & 0x1) + 1);

        status = RegRead(SensorCtx, REG_PLL1_PREDIV, &data, DATA_8BITS);
        if (!NT_SUCCESS(status))
            goto done;
        pre_pll1_perdiv = pre_pll1_perdiv_val[data & 0x7];

        status = RegRead(SensorCtx, REG_PLL1_MULTIPLIER_H, &data, DATA_8BITS);
        if (!NT_SUCCESS(status))
            goto done;

        status = RegRead(SensorCtx, REG_PLL1_MULTIPLIER_L, &data1, DATA_8BITS);
        if (!NT_SUCCESS(status))
            goto done;

        pll1_multiplier = (((data & 0x3) << 8 ) | data1);

        status = RegRead(SensorCtx, REG_PLL1_M_DIVIDER, &data, DATA_8BITS);
        if (!NT_SUCCESS(status))
            goto done;
        pll1_m_divider = ((data & 0xf) +1);
        
        LinkConfig->ActualLaneSpeed = (ULONG)(19200000 / pre_pll1_perdiv0 / pre_pll1_perdiv * pll1_multiplier / pll1_m_divider);
    }
    else
    {
        LinkConfig->ActualLaneSpeed = 0;
    }
    LinkConfig->SensorProvidesFrameNumbers = FALSE;
    LinkConfig->VcSettings[0].VC_Value = 0;

    //rest of VC not are not used
    for (i = 1; i < CIO2_VC_NUMBER; i++)
        LinkConfig->VcSettings[i].VC_Value = CIO2_VC_NOT_USED;

    // for image data
    vcSettings->DataType[0].MipiDataType = RAW10;
    vcSettings->DataType[0].CRCErrorsThreshold = 0;
    vcSettings->DataType[0].ImageWidth = ModeData.OutputWidth;
    vcSettings->DataType[0].ImageHeight = ModeData.OutputHeight;
    vcSettings->DataType[0].VerticalBlankTime = 0; //just testing
    vcSettings->DataType[0].HorizonatlBlankTime = 0;

    if (SensorPowerOn)
    {
        float framerate = 30.0;//default 30fps
        if ( ModeData.FrameLengthLines != 0 && ModeData.LineLengthPck != 0)
            framerate = (float)ModeData.VtPixClkFreqHz / ModeData.FrameLengthLines / ModeData.LineLengthPck;
        vcSettings->DataType[0].FrameTime = (ULONG)(1E9 / framerate); //Nano seconds duration of frame
    }
    else
        vcSettings->DataType[0].FrameTime = 0;

    LinkConfig->LinkSharingKey = 0;
    
    //for sensor metadata
    vcSettings->DataType[1].MipiDataType = EMBEDDED_8b;
    vcSettings->DataType[1].CRCErrorsThreshold = 0;
    vcSettings->DataType[1].ImageWidth = ModeData.OutputWidth;
    vcSettings->DataType[1].ImageHeight = 1;       //for Sample, there are 1 embedded lines
    vcSettings->DataType[1].VerticalBlankTime = 0; //just testing
    vcSettings->DataType[1].HorizonatlBlankTime = 0;
    vcSettings->DataType[1].FrameTime = vcSettings->DataType[0].FrameTime;

    vcSettings->ExpectedLastDataTypeBeforeEOF = RAW10;

    //the rest of array for MIPI buffers is not used
    for (i = 2; i < CIO2_DATA_TYPES_MAX; i++)
        vcSettings->DataType[i].MipiDataType = UNUSED_DATA_TYPE;
done:    
    KeSetEvent(&SensorCtx->SettingEvent, IO_NO_INCREMENT, FALSE);
invalid:
    DoTraceMessage(FLAG_LOG, "[SensorDrv] SensorDriverView data is valid. LinkID = %d, Num lanes = %d, ClockDiv = %d, InstanceID = 0x%x, " \
        "width = %d, height = %d, frametime:%d, LinkSpeed:%d ",
        LinkConfig->LinkUsed, LinkConfig->LanesUsed, LinkConfig->HostControllerGlobal.G_LanesClockDivision,
        LinkConfig->HostControllerID.Csi2.InstanceID.BdfValue, ModeData.OutputWidth, ModeData.OutputHeight,
        vcSettings->DataType[1].FrameTime, LinkConfig->ActualLaneSpeed);

    DoTraceMessage(FLAG_LOG, "[SensorDrv] Clane:0x%04x, Dlane0:0x%04x Dlane1:0x%04x", 
        LinkConfig->LinkDelayParameters.CSI_RX_DLY_CNT_SETTLE_CLANE,
        LinkConfig->LinkDelayParameters.CSI_RX_DLY_CNT_SETTLE_DLANE0,
        LinkConfig->LinkDelayParameters.CSI_RX_DLY_CNT_SETTLE_DLANE1);
    return status;
}

NTSTATUS
SampleCmd_SetResolutionWidthHeigth(
    PDEVICE_CONTEXT SensorCtx,
    SNSR_MODE Mode,
    SNSR_RESOLUTION_DEBUG Resolution
)
{
    NTSTATUS status = STATUS_SUCCESS;
    UNREFERENCED_PARAMETER(Mode);
    DoTraceMessage(FLAG_ERROR, "GetRegSettingFromFile333\n");
    CHECK_POINTER_INVALID(SensorCtx)
        
    status = KeWaitForSingleObject(&SensorCtx->SettingEvent, Executive, KernelMode, FALSE, NULL);
    if (!CHECK_STATUS_SUCCESS(status))
    {
        DoTraceMessage(FLAG_ERROR, "%s SampleCmd_SetResolutionDebug KeWaitForSingleObject fail, (status 0x%x)\n",
            DEVICE_NAME, status);
        goto invalid;
    }

       
    if (Resolution.Width == 3280 && Resolution.Height == 2464) 
    {
       status |= RegWriteQueue(SensorCtx, sensor_global_setting);
       SensorCtx->Binning = 1;
    }
    if(SensorCtx->Orientation == DEGREE_180)
    {
            ULONG flipReg, mirrorReg;
            status = RegRead(SensorCtx, REG_FLIP_CONTROL, &flipReg, DATA_8BITS);
            if (!NT_SUCCESS(status))
            {
                DoTraceMessage(FLAG_ERROR, "REG_FLIP_CONTROL Fail = 0x%x\n", flipReg);
                goto done;
            }            
            status = RegRead(SensorCtx, REG_MIRROR_CONTROL, &mirrorReg, DATA_8BITS);
            if (!NT_SUCCESS(status))
            {
                DoTraceMessage(FLAG_ERROR, "REG_MIRROR_CONTROL Fail = 0x%x\n", mirrorReg);
                goto done;
            } 
            flipReg ^= CONFIG_FLIP;
            mirrorReg ^= CONFIG_MIRROR;
            status = RegWrite(SensorCtx, REG_FLIP_CONTROL, flipReg, DATA_8BITS);
            if (!NT_SUCCESS(status))
            {
                DoTraceMessage(FLAG_ERROR, "REG_FLIP_CONTROL Fail = 0x%x\n", flipReg);
                goto done;
            }            
            status = RegWrite(SensorCtx, REG_MIRROR_CONTROL, mirrorReg, DATA_8BITS);
            if (!NT_SUCCESS(status))
            {
                DoTraceMessage(FLAG_ERROR, "REG_MIRROR_CONTROL Fail = 0x%x\n", mirrorReg);
                goto done;
            }
    }
    //overide BLC level target to 0x40
    status |= RegWrite(SensorCtx, 0x4005, 0x40, DATA_8BITS);
    //Manula enable of master AWB statistics
    status |= RegWrite(SensorCtx, 0x501E, 0x98, DATA_8BITS);
        
    if (SensorCtx->IsEmbeddedDataEnabled && SensorCaps.EmbeddedLineNum != 0)
    {
        status = EnableEmbeddedLine(SensorCtx);
        if (!NT_SUCCESS(status))
        {
           DoTraceMessage(FLAG_ERROR, "%s Failed to enable embedded line (0x%x)\n", DEVICE_NAME, status);
           goto done;
        }
    }   
    
    // get default VTS
    status = RegRead(SensorCtx, REG_TIMING_VTS, &SensorCtx->FrameLines, DATA_16BITS);
    if (!NT_SUCCESS(status))
    {
        DoTraceMessage(FLAG_ERROR, "REG_TIMING_VTS Fail = 0x%x\n", SensorCtx->FrameLines);
        goto done;
    }
    
done:    
    KeSetEvent(&SensorCtx->SettingEvent, IO_NO_INCREMENT, FALSE);
invalid:
    DoTraceMessage(FLAG_LOG,"%s SetResolution: w=%d, h=%d, lanes=%d, fps=%d\n",
                                 DEVICE_NAME, Resolution.Width, Resolution.Height, Resolution.NumberOfLanes, Resolution.FPS);
    return status;    
}

NTSTATUS
SampleCmd_ResetSensor(
    PDEVICE_CONTEXT SensorCtx
)
{
    NTSTATUS status = STATUS_SUCCESS;
    CHECK_POINTER(SensorCtx);
    status = KeWaitForSingleObject(&SensorCtx->SettingEvent, Executive, KernelMode, FALSE, NULL);

    status = RegWrite(SensorCtx, SOFTWARE_RST, 1, DATA_8BITS);
    SleepMSecond(1);

done:
    if (SensorCtx)
        KeSetEvent(&SensorCtx->SettingEvent, IO_NO_INCREMENT, FALSE);

    DoTraceMessage(FLAG_LOG, "%s ResetSensor returns with code: 0x%x\n", DEVICE_NAME, status);
    return status;
}
#endif //SKY_CAM
