/*
 * main_imx519.cpp
 *
 *  Created on: Jun 26, 2024
 *      Author: Richard
 */
 //niosv-app --bsp-dir=software/camera_bsp --app-dir=software/camera_app --srcs=software/camera_app/main.cpp --elf-name=camera.elf




#include <stdio.h>
#include <stdlib.h> // malloc, free
#include <unistd.h>  // usleep (unix standard?)
#include <stdint.h>
#include <stdbool.h>
#include "system.h"
#include "io.h"
#include "altera_avalon_i2c.h"
#include "i2c.h"
#include "IMX519.h"
#include "AK7375.h"
#include "VVP_TPG.h"
#include "VVP_SW.h"
#include "VVP_PIP.h"
#include "VVP_FB.h"
#include "VVP_Demosaic.h"


static IMX519 *gpCameraI2C=NULL;
static AK7375 *gpVcmI2C=NULL;

VVP_SW  gVVP_SW(VVP_SYSTEM_INTEL_VVP_SWITCH_BASE);



typedef bool (*LP_VERIFY_FUNC)(void);
typedef struct{
    LP_VERIFY_FUNC func;
    char szName[128];
}FUNC_INFO;


static bool CAMERA_Init();

static bool CAMERA_Start_Streaming(){
	bool bSuccess;

	bSuccess = gpCameraI2C->imx519_start_streaming();

	return bSuccess;
}

static bool CAMERA_Stop_Streaming(){
	bool bSuccess;

	bSuccess = gpCameraI2C->imx519_stop_streaming();

	return bSuccess;
}





static bool CAMERA_Exposure_control(){
	bool bSuccess;
	unsigned int Value, CurValue;

	bSuccess = gpCameraI2C->imx519_get_exposure(&CurValue);
	if (bSuccess){
		printf("input exposure value (current %d, default %d, %d~%d):", CurValue, IMX519_EXPOSURE_DEFAULT, IMX519_EXPOSURE_MIN,IMX519_EXPOSURE_MAX);
		scanf("%d", &Value);
		printf("%d(%04xh)", Value, Value);
		bSuccess = gpCameraI2C->imx519_set_exposure(Value);
	}

	return bSuccess;

}

static bool CAMERA_Colour_balance(){

	bool bSuccess;
	int Value;
	unsigned int blue, red, CurBlue, CurRed;
	blue = 0x0213; // default 0x100
	red = 0x01BC;

	bSuccess = gpCameraI2C->imx519_get_color_balance_BR(&CurBlue, &CurRed);
	if (bSuccess){
		printf("input blue value (current %d, default %d, %d~%d):", CurBlue, IMX519_DGTL_GAIN_DEFAULT, IMX519_DGTL_GAIN_MIN,IMX519_DGTL_GAIN_MAX);
		scanf("%d", &Value);
		printf("%d(%04xh)\r\n", Value, Value);
		blue = Value;

		printf("input red value (current %d, default %d, %d~%d):", CurRed, IMX519_DGTL_GAIN_DEFAULT, IMX519_DGTL_GAIN_MIN,IMX519_DGTL_GAIN_MAX);
		scanf("%d", &Value);
		printf("%d(%04xh)\r\n", Value, Value);
		red = Value;
		bSuccess = gpCameraI2C->imx519_set_color_balance_BR(blue, red);

		printf("IMX708_REG_COLOUR_BALANCE_BLUE = %d, IMX708_REG_COLOUR_BALANCE_RED = %d\r\n", blue, red);
	}
//	if (bSuccess)
//		bSuccess = gpCameraI2C->imx708_set_color_balance_BR(0x0213, 0x01BC);

	return bSuccess;


}

static bool CAMERA_Analog_gain(){
/* Analog gain control */
/* 57.9528608000,511,0x34,W,0x02 0x04 0x01 0x55
*/
	bool bSuccess;

	unsigned int Value, CurValue;

	bSuccess = gpCameraI2C->imx519_get_analogue_gain(&CurValue);
	if (bSuccess){
		printf("input analog gain value (current %d, default %d, %d~%d):", CurValue, IMX519_ANA_GAIN_DEFAULT, IMX519_ANA_GAIN_MIN, IMX519_ANA_GAIN_MAX);
		scanf("%d", &Value);
		printf("%d(%04xh)", Value, Value);

		bSuccess = gpCameraI2C->imx519_set_analogue_gain(Value);
	}
	return bSuccess;
}

static bool CAMERA_Digital_gain(){

	bool bSuccess;
	unsigned int Value, CurValue;

	bSuccess = gpCameraI2C->imx519_get_digital_gain(&CurValue);
	if (bSuccess){
		printf("input digital gain value (current %d, default %d, %d~%d):", CurValue, IMX519_DGTL_GAIN_DEFAULT, IMX519_DGTL_GAIN_MIN, IMX519_DGTL_GAIN_MAX);
		scanf("%d", &Value);
		printf("%d(%04xh)", Value, Value);

		bSuccess = gpCameraI2C->imx519_set_digital_gain(Value);
	}
	return bSuccess;
}


static bool CAMERA_Test_pattern_colour(){
/* Test pattern colour components */
/*
#define IMX708_REG_TEST_PATTERN_R	0x0602
#define IMX708_REG_TEST_PATTERN_GR	0x0604
#define IMX708_REG_TEST_PATTERN_B	0x0606
#define IMX708_REG_TEST_PATTERN_GB	0x0608
#define IMX708_TEST_PATTERN_COLOUR_MIN	0
#define IMX708_TEST_PATTERN_COLOUR_MAX	0x0fff
#define IMX708_TEST_PATTERN_COLOUR_STEP	1
45.7274284500,290,0x34,W,0x06 0x02 0x0F 0xFF
45.7279200000,291,0x34,W,0x06 0x04 0x0F 0xFF
45.7284166000,292,0x34,W,0x06 0x06 0x0F 0xFF
45.7289132500,293,0x34,W,0x06 0x08 0x0F 0xFF
*/
	bool bSuccess;
	int R, GR, B, GB;

	printf("R(0~1023):");
	scanf("%d", &R);
	printf("%d\r\n", R);

	printf("GR(0~1023):");
	scanf("%d", &GR);
	printf("%d\r\n", GR);

	printf("B(0~1023):");
	scanf("%d", &B);
	printf("%d\r\n", B);

	printf("GB(0~1023):");
	scanf("%d", &GB);
	printf("%d\r\n", GB);

	bSuccess = gpCameraI2C->imx519_set_test_patttern_colour(R, GR, B, GB);

	return bSuccess;
}

static bool CAMERA_Test_pattern_sel(){
	bool bSuccess;
	unsigned int nPatternID;

	printf("Select Test Pattern\r\n");
	printf("0: Disable\r\n");
	printf("1: Solid Color\r\n");
	printf("2: Color Bar\r\n");
	printf("3: Grey Color\r\n");
	printf("4: PN9\r\n");

    scanf("%d", &nPatternID);

    if (nPatternID >=0 && nPatternID <=4){
    	bSuccess = gpCameraI2C->imx519_set_test_patttern(nPatternID);
    }else{
    	printf("%d is invalid selection", nPatternID);
    }

	return bSuccess;
}









static bool CAMERA_Dump_Setting(){
	bool bSuccess;

	bSuccess = gpCameraI2C->imx519_dump_setting();

	return bSuccess;
}



static bool VCM_active(){
	bool bSuccess;

	bSuccess = gpVcmI2C->active();

	return bSuccess;
}




static bool VCM_standby(){
	bool bSuccess;

	bSuccess = gpVcmI2C->standby();

	return bSuccess;
}


static bool VCM_set_pos(){
	bool bSuccess;
	int pos;

	printf("Input position (%d~%d):", 0, AK7375_MAX_FOCUS_POS);
	scanf("%d", &pos);
	printf("%d\r\n", pos);
	bSuccess = gpVcmI2C->set_pos(pos);

	return bSuccess;
}

static bool VCM_scan(){
	bool bSuccess;

	bSuccess = gpVcmI2C->scan();

	return bSuccess;
}

static bool VVP_Switch(){
	bool bSuccess = false;
	int nInputChannel;
	int nOutputChannel = 0;

	//int Value;
	printf("input switch source channel number (0~N-1):");
	scanf("%d", &nInputChannel);
	printf("%d", nInputChannel);

	bSuccess = gVVP_SW.Config(nInputChannel, nOutputChannel);
	if (bSuccess)
		gVVP_SW.ShowStatus();

	return bSuccess;
}



static FUNC_INFO szFuncList[] = {
		{CAMERA_Init,  				 		"Camera: ReInit"	   },
	//	{CAMERA_Start_Streaming,  			"CAMERA_Start_Streaming"	   },
	//	{CAMERA_Stop_Streaming,  			"CAMERA_Stop_Streaming"	   },
		{CAMERA_Exposure_control,			"Camera: Exposure"	   },
		{CAMERA_Colour_balance,  			"Camera: Color Balance"	   },
		{CAMERA_Analog_gain,				"Camera: Analog Gain"	   },
		{CAMERA_Digital_gain,				"Camera: Global Digital Gain"	   },
		{CAMERA_Test_pattern_sel,			"Camera: Test Pattern"	   },
		{CAMERA_Test_pattern_colour,		"Camera: Solid Test Pattern Color"	   },
		{CAMERA_Dump_Setting,				"Camera: Dump Setting"	   },
		//
	//	{VCM_active,						"VCM_active"	   },
	//	{VCM_standby,						"VCM_standby"	   },
		{VCM_set_pos,						"Focus: Set Position"	   },
		{VCM_scan,							"Focus: Scan"	   },

		// VVP control
		{VVP_Switch,						"VVP: Switch (0:color bar, 1: Camera, 2: SDI Pattern)"	   },




};





// imx519_probe
static bool CAMERA_Init(){
	bool bSuccess;

	bSuccess = gpCameraI2C->imx519_identify_module();
	if (!bSuccess){
		printf("failed to find camera\r\n");
	}else{
		/* Initialize default format */
		bSuccess = gpCameraI2C->imx519_init();
		printf("CAMERA_Init %s\r\n", bSuccess?"success":"failed");
	}


	return bSuccess;

}

static void ShowMenu(void){
    int nNum,i;

    nNum = sizeof(szFuncList)/sizeof(szFuncList[0]);
    printf("======= Camera Demo Config Menu =======\r\n");
    for(i=0;i<nNum;i++){
        printf("[%d]%s\r\n", i, szFuncList[i].szName);
    }
    printf("99: Quit\r\n");
    printf("Please input your selection:");
}


static int QuerySelection(void){
    int nChoice = 0;
    scanf("%d", &nChoice);
    //printf("%d\r\n", nChoice);
    return nChoice;
}

static void Camera_ConfigMenu(){
	int nSel,nNum;
	bool bQuit = false;


	//IOWR_ALTERA_AVALON_PIO_DATA(PIO_XCVR_RESET_BASE, 0x00);

	nNum = sizeof(szFuncList)/sizeof(szFuncList[0]);

	while(!bQuit){
		ShowMenu();
		nSel = QuerySelection();

		if (nSel >= 0 && nSel < nNum){
			szFuncList[nSel].func();
		}else if (nSel == 99){
			bQuit = true;
		}
	}
}




int main(void){
	//bool bSuccess;

	printf("Camera Demo\r\n");
	IOWR(PIO_LED_BASE, 0x00, 0x00); // turn on led




	alt_u32 status32;
	status32 = IORD(PIO_HDMI_CONFIG_DONE_BASE,0x00);
	if ((status32 & 0x01) != 0x01)
			printf("Warning: HDMI configure not done!\r\n");

	//



	// init camera
	gpCameraI2C = new IMX519(I2C_NAME, IMX519_I2C_ADDRESS); // must new before calling any Camera_xxx funtion

	if (CAMERA_Init()){

		///////////////////////
		// 1. VVP config

		VVP_Demosaic Demoasic(VVP_SYSTEM_INTEL_VVP_DEMOSAIC_BASE);
		VVP_TPG TPG1(VVP_SYSTEM_INTEL_VVP_TPG_1_BASE);
		VVP_PIP PIP(VVP_SYSTEM_INTEL_VVP_PIP_CONV_4TO1_BASE);
		VVP_FB FB(VVP_SYSTEM_INTEL_VVP_VFB_BASE);

		gpVcmI2C = new AK7375(I2C_NAME, AK7375_I2C_ADDRESS);


		// config VVP frame buffer
		if (FB.IsLiteMode()){
			//printf("Config VVP FB\r\n");
			FB.Run(false);
			FB.Config();
		}
		FB.Run();
		//FB.ShowStatus();

		// config VVP pixel in parallel
		if (PIP.IsLiteMode()){
			//printf("Config VVP PIP\r\n");
			PIP.Config();
		}
		//PIP.ShowStatus();

		// config VVP switch
		if (gVVP_SW.IsLiteMode()){
			//printf("Config VVP Switch\r\n");
			gVVP_SW.Config(1,0);
			//gVVP_SW.ShowStatus();
		}


		//
		TPG1.Config();
		TPG1.Run();
		//TPG1.ShowStatus();

		//
		//printf("Config VVP Demoasic Config\r\n");
		//Demoasic.ShowStatus();
		Demoasic.Config();
		Demoasic.Run();
		//Demoasic.ShowStatus();
		//usleep(1000*1000);
		//Demoasic.ShowStatus();

		///////////////////////
		// 2. enter main menu
		Camera_ConfigMenu();
	}else{
		printf("failed to init camera\r\n");
	}

	delete gpVcmI2C;
	delete gpCameraI2C;


	return 0;
}
