#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
 #include <sys/ioctl.h>
 
#include <apci3600.h>
#include "apci3600-def.h"
#include "consoleio.h"
#include "debug.h"
#include "apci3600msg.h"
#include "displayboardinitialisation.h"
#include "configuration.h"


//--------------------------------------------------------------------------------
static void GetClockDivisorGenerator(int index, uint8_t * val)
{
	printf("Select the divisor clock generator %i :", index);
	printf(" 0: Divisor = 4 ->25,60MHz\n");
	printf(" 1: Divisor = 5 ->20,48MHz\n");
	printf(" 2: Divisor = 6 ->17,06MHz\n");
	printf(" 3: Divisor = 8 ->12,80MHz\n");
	printf(" 4: Divisor = 10 ->10,24MHz\n");
	printf(" 5: Divisor = 12 -> 8,53MHz\n");
	printf(" 6: Divisor = 16 -> 6,40MHz\n");
	printf(" 7: Divisor = 20 -> 5,12MHz\n");
	printf(" 8: Divisor = 25 -> 4,096 MHz\n");
	printf(" 9: Divisor = 40 -> 2,56MHz\n");
	printf(" 10: Divisor = 50 -> 2,048 MHz\n");
	printf(" 11: Divisor = 60 -> 1,706 MHz\n");
	printf(" 12: Divisor = 80 -> 1,28MHz\n");
	printf(" 13: Divisor = 100 -> 1,024 MHz\n");
	printf("Your choice :\n");
 
	/* map menu item to parameter */
	{
		int userinput =get_integer(0,13);
		switch(userinput)
		{
			case 0:
				*val = 4;
				break;
			case 1:
				*val = 5;
				break;
			case 2:
				*val = 6;
				break;
			case 3:
				*val = 8;
				break;			
			case 4:
				*val = 10;
				break;
			case 5:
				*val = 12;
				break;
			case 6:
				*val = 16;
				break;
			case 7:
				*val = 20;
				break;
			case 8:
				*val = 25;
				break;
			case 9:
				*val = 40;
				break;
			case 10:
				*val = 50;
				break;
			case 11:
				*val = 60;
				break;
			case 12:
				*val = 80;
				break;
			case 13:
				*val = 100;
				break;
			default:
				FAILURE();
		}
	} 
}

//--------------------------------------------------------------------------------
/*Interactively initialise a board.
 * 
 * You may put your default init. here
*/

void get_Board_Initialisation(str_InitBoardArg_t * InitBoardArg)
{
	if (0)
	{
		InitBoardArg->b_MasterSlaveMode = 0;
		InitBoardArg->b_ClockGen1_Divisor = 4;
		InitBoardArg->b_ClockGen2_Divisor = 4;
		InitBoardArg->b_SamplingClock1_Selection = 0;
		InitBoardArg->b_SamplingClock2_Selection = 0;
		InitBoardArg->b_Chronometer_MasterClock_Divisor = 0;
		InitBoardArg->b_SlaveSamplingClock1_Selection = 0;
		InitBoardArg->b_SlaveSamplingClock2_Selection = 0;
		return;
	}

	printf("Select the mode of the board (0 : Master, 1 : Slave):\n");
	printf("IMPORTANT: In slave mode, the Clock1 and Clock2 selection and divisor MUST be the same that the master board.\n");
	InitBoardArg->b_MasterSlaveMode = get_integer(0,1);

	switch(InitBoardArg->b_MasterSlaveMode)
	{ 
		case 0:
			printf("**************************************************************************\n");
			printf("* Sampling clock selection in master mode*\n");
			printf("**************************************************************************\n");
			printf("+--------------------+\n");
			printf("| PLD Clock 102,4MHz |\n");
			printf("+--------------------+\n");
			printf("|\n");
			printf("| Sampling Clock selection\n");
			printf("| +---------------------------+ \n");
			printf("+-| Divisor Clock Generator 1 |-> Clock Generator 1+ \n");
			printf("| +---------------------------+| \n");
			printf("+-| Divisor Clock Generator 2 |-> Clock Generator 2+ \n");
			printf("+---------------------------+| \n");
			printf(" |-> Sampling Clock 1 / 2\n");
			printf("Chonometer 0 Latch input + \n");
			printf(" | \n");
			printf("Chonometer 1 Latch input + \n");
			printf("**************************************************************************\n");
			printf("* Sampling Clock 1 & 2 are then used as Source for the Ext Clock 1 & 2 *\n");
			printf("**************************************************************************\n");
			printf ("Enter the clock configuration form the board :\n");
			printf ("----------------------------------------------\n");
			break;
		default:
			printf("**************************************************************************\n");
			printf("* Sampling clock selection in slave mode *\n");
			printf("**************************************************************************\n");
			printf("+--------------+\n");
			printf("| Master board |\n");
			printf("+--------------+\n");
			printf("|\n");
			printf("| Slave Sampling Clock selection\n");
			printf("+-| Extern Clock 1 + \n");
			printf("||-> Sampling Clock 1 / 2\n");
			printf("+-| Extern Clock 2 + \n");
			printf("**************************************************************************\n");			
			printf ("Enter the clock configuration from the master board :\n");
			printf ("----------------------------------------------------- \n");
	} 
	
	GetClockDivisorGenerator(1, &(InitBoardArg->b_ClockGen1_Divisor) );
	GetClockDivisorGenerator(2, &(InitBoardArg->b_ClockGen2_Divisor) );

	printf("Select the Sampling Clock 1 :\n");
	printf(" 0: Clock Generator 1 : 102,4 MHz / %hu -> %lf MHz\n",InitBoardArg->b_ClockGen1_Divisor,(double)(102.4 / (double)InitBoardArg->b_ClockGen1_Divisor));
	printf(" 1: Clock Generator 2 : 102,4 MHz / %hu -> %lf MHz\n",InitBoardArg->b_ClockGen2_Divisor,(double)(102.4 / (double)InitBoardArg->b_ClockGen2_Divisor));
	printf(" 2: Chronometer 0 Latch input\n");
	printf(" 3: Chronometer 1 Latch input\n");
	printf("Your choice :\n");
	InitBoardArg->b_SamplingClock1_Selection = get_integer(0,3);

	printf("Select the Sampling Clock 2 :\n");
	printf(" 0: Clock Generator 1 : 102,4 MHz / %hu -> %lf MHz\n",InitBoardArg->b_ClockGen1_Divisor,(double)(102.4 / (double)InitBoardArg->b_ClockGen1_Divisor));
	printf(" 1: Clock Generator 2 : 102,4 MHz / %hu -> %lf MHz\n",InitBoardArg->b_ClockGen2_Divisor,(double)(102.4 / (double)InitBoardArg->b_ClockGen2_Divisor));
	printf(" 2: Chronometer 0 Latch input\n");
	printf(" 3: Chronometer 1 Latch input\n");
	printf("Your choice :\n");
	InitBoardArg->b_SamplingClock2_Selection = get_integer(0,3);

	switch(InitBoardArg->b_MasterSlaveMode)
	{
		case 1:
			printf("Select the Sampling Clock 1 to use for the slave board :\n");
			printf(" 0: Ext Clock 1 \n");
			printf(" 1: Ext Clock 2 \n");
			printf("Your choice :\n");
			InitBoardArg->b_SlaveSamplingClock1_Selection = get_integer(0,1);
			printf("Select the Sampling Clock 2 to use for the slave board :\n");
			printf(" 0: Ext Clock 1 \n");
			printf(" 1: Ext Clock 2 \n");
			printf("Your choice :\n");
			InitBoardArg->b_SlaveSamplingClock2_Selection = get_integer(0,1);
			break;
		default:
			break;
	}
	printf("Select the master clock divisor for the chronometer:\n");
	printf(" 0: Divisor = 1 -> 102,4 MHz\n");
	printf(" 1: Divisor = 10-> 10,24 MHz\n");
	printf(" 2: Divisor = 100 -> 1,024 MHz\n");
	printf("Your choice :\n");	
	InitBoardArg->b_Chronometer_MasterClock_Divisor = get_integer(0,2);
	
}

//--------------------------------------------------------------------------------
int i_Board_Initialisation(struct apci3600_card_t * pboard)
{
	str_InitBoardArg_t str_InitBoardArg;
	int ret;

	get_Board_Initialisation(&str_InitBoardArg);

	/* Initialise the board */
	{
		ret =ioctl(pboard->base,CMD_APCI3600_InitBoard, &str_InitBoardArg);
		STATUS_MSG_VERBOSE(ret, InitBoard);
	}
	i_Display_Board_Initialisation(pboard);
	return ret;
}


//--------------------------------------------------------------------------------
int i_Analog_Input_Initialisation(struct apci3600_card_t * pboard, uint8_t * pb_Module)
{
	str_InitAnalogInputModuleArg_t InitAnalogInputModuleArg;
	
	printf("Select the analog input module you want to use (0 to 3):\n");
	*pb_Module = get_integer(0, 3);
	 
	printf("Do you want to activate the current source for the left channel (0:No, 1:Yes)?\n");
	InitAnalogInputModuleArg.pb_EnableCurrentSource[0] = get_integer(0, 1);
	printf("do You want to activate the current source for the right channel (0:No, 1:Yes)?\n");
	InitAnalogInputModuleArg.pb_EnableCurrentSource[1] = get_integer(0, 1);

	switch(InitAnalogInputModuleArg.pb_EnableCurrentSource[0])
	{
		case 0:
			printf("Select the Single-Ended(0) / Differential mode(1) for the left channel :\n");
			InitAnalogInputModuleArg.pb_SingleDiffMode[0] = get_integer(0, 1);
			printf("Select the DC(0) or AC(1) coupling for the left channel :\n");
			InitAnalogInputModuleArg.pb_Coupling[0] = get_integer(0, 1);
			break;
		default:
 			InitAnalogInputModuleArg.pb_SingleDiffMode[0] = PCI3600_SINGLE_ENDED_MODE;
 			InitAnalogInputModuleArg.pb_Coupling[0] = PCI3600_AC_COUPLING;			
 			break;
	}
	
	switch(InitAnalogInputModuleArg.pb_EnableCurrentSource[1])
	{
		case 0:
			printf("Select the Single-Ended(0) / Differential mode(1) for the right channel :\n");
			InitAnalogInputModuleArg.pb_SingleDiffMode[1] = get_integer(0, 1);
			printf("Select the DC(0) or AC(1) coupling for the right channel :\n");
			InitAnalogInputModuleArg.pb_Coupling[1] = get_integer(0, 1);
			break;
		default:
 			InitAnalogInputModuleArg.pb_SingleDiffMode[1] = PCI3600_SINGLE_ENDED_MODE;
 			InitAnalogInputModuleArg.pb_Coupling[1] = PCI3600_AC_COUPLING;			
 			break;
	}

	printf("Select the gain for the left channel :\n");
	printf("0 : Gain 1\n");
	printf("1 : Gain 10\n");
	InitAnalogInputModuleArg.pb_GainSelection[0] = get_integer(0, 1);

	printf("Select the gain for the right channel :\n");
	printf("0 : Gain 1\n");
	printf("1 : Gain 10\n");
	InitAnalogInputModuleArg.pb_GainSelection[1] = get_integer(0, 1);


	printf("Select the sampling clock :\n");
	printf(" 0 : Sampling Clock 1\n");
	printf(" 1 : Sampling Clock 2\n");
	InitAnalogInputModuleArg.b_SamplingClockSelection = get_integer(0, 1);

	printf("Select the speed mode :\n");
	printf(" 0: Single Speed mode (2KHz-50KHz)\n");
	printf(" 1: Double Speed mode (50KHz-100KHz)\n");
	printf(" 2: Quad Speed mode (100KHz-200KHz)\n");
	InitAnalogInputModuleArg.b_SpeedMode = get_integer(0, 2);


	/* Initialise the analog input module */
	{
		int ret = ioctl(apci3600_get_analog_input_module(pboard,*pb_Module), CMD_APCI3600_InitAnalogInputModule, &InitAnalogInputModuleArg);
	
		STATUS_MSG_VERBOSE(ret, InitAnalogInputModule);
		if( ret )
			return -1;
	}
	/* wait for calibration to finishes */
	{
		uint8_t b_Status = 0; 
		char* pc_Wait = {"|/-\\"};
		int w_Wait = 0;
		do
		{
			/* Wait interrupt string */
			if ((w_Wait % 8650) == 0)
			{
				printf ("\rWait for end of calibration %c", pc_Wait[w_Wait / 8650]);
			}
			w_Wait = (w_Wait + 1) % 34600;
	
			/* Test the status of the ADC calibration */
			{
				uint8_t arg = 0;
				int ret = ioctl( apci3600_get_analog_input_module(pboard,*pb_Module), CMD_APCI3600_GetAnalogInputModuleCalibrationStatus, &arg);
				STATUS_MSG(ret, GetAnalogInputModuleCalibrationStatus);
				
				if ( ret )
					return -2;
					
				b_Status = arg;
			}
		} while (b_Status == 1);
	}
	printf("\n");
	
	return 0;
}
//--------------------------------------------------------------------------------
int i_External_Trigger_Initialisation(struct apci3600_card_t * pboard)
{
	InitDigitalInputExternalTrigger_t InitDigitalInputExternalTriggerArg;

	printf("Define the trigger edge :\n");
	printf("1. Rising edge\n");
	printf("2. Falling edge\n");
	printf("3. Both edge\n");
	InitDigitalInputExternalTriggerArg.b_TriggerLevel = get_integer(1, 3);

	printf("Define the number of trigger to wait for, before the board takes it into account (1 to 65535):\n");
	InitDigitalInputExternalTriggerArg.w_TriggerCountValue = get_integer(1, 65535);

	/* Initialise the digital input external trigger */
 	{
		int ret = ioctl(pboard->external_trigger, CMD_APCI3600_InitDigitalInputExternalTrigger, &InitDigitalInputExternalTriggerArg);
		STATUS_MSG_VERBOSE(ret, InitDigitalInputExternalTrigger);
		if(ret)
			return -1;
 	}
 	return 0;
}
//--------------------------------------------------------------------------------
int i_Init_And_Start_Cyclic_Acquisition(struct apci3600_card_t * pboard, uint8_t b_Module)
{
	uint32_t dw_OnBoardBufferSize = 0;
	uint32_t dw_CompareValue = 0;
	uint b_Mode = 0;
	printf("Enter the nbr of bytes (n) of the on board RAM You want to use (1kB*2^n):\n");
	printf("For example :\n");
	printf("n = 0->1 KB ->256 Values\n");
	printf("n = 1->2 KB ->512 Values\n");
	printf("n = 2->4 KB ->1 024 Values\n");
	printf("n = 3->8 KB ->2 048 Values\n");
	printf("n = 4-> 16 KB ->4 096 Values\n");
	printf("n = 5-> 32 KB ->8 192 Values\n");
	printf("n = 6-> 64 KB -> 16 384 Values\n");
	printf("n = 7->128 KB -> 32 768 Values\n");
	printf("n = 8->256 KB -> 65 536 Values\n");
	printf("n = 9->512 KB ->131 072 Values\n");
	printf("n = 10 ->1 MB ->262 144 Values\n");
	printf("n = 11 ->2 MB ->524 288 Values\n");
	printf("n = 12 ->4 MB ->1 048 576 Values\n");
	printf("n = 13 ->8 MB ->2 097 152 Values\n");
	printf("n = 14 -> 16 MB ->4 194 304 Values\n");
	printf("n = 15 -> 32 MB ->8 388 608 Values\n");
	printf("n = 16 -> 64 MB -> 16 777 216 Values\n");
	printf("n = 17 ->128 MB -> 33 554 432 Values\n");
	printf("n = 18 ->256 MB -> 67 108 864 Values\n");
	printf("Your choice :");
	
	dw_OnBoardBufferSize = get_integer(0,18);
	
 	printf("It defines the number of acquisition to have in the on-board Buffer to generate an interrupt for start a DMA transfer.");
	printf("It cannot be :\n");
	printf("\n- greater that the size of the on board buffer in Auto Stop mode\n");                    
	printf("- greater or equal that the size of the on board buffer in Ring Buffer mode\n");              
	printf("\t- 0\n");                	
	
	printf("Enter the compare value (in nbr of value): 1 .. %i\n",1024*(2^dw_OnBoardBufferSize) );
	dw_CompareValue = get_integer(1,1024*(2^dw_OnBoardBufferSize));
	
 	printf("Enter the cyclic acquisition mode (0 : Auto-Stop, 1 : Ring buffer):");
 	b_Mode = get_integer(0,1);
	
	/* init the acquisition */
	{
		int ret;
		str_InitAnalogInputModuleCyclicAcquisitionArg_t param;
		param.dw_CompareValue = dw_CompareValue;
		param.dw_Mode = b_Mode;
		param.dw_OnBoardBufferSize = dw_OnBoardBufferSize;
		ret = ioctl(apci3600_get_analog_input_module(pboard,b_Module),CMD_APCI3600_InitAnalogInputModuleCyclicAcquisition,&param);
		STATUS_MSG_VERBOSE(ret, InitAnalogInputModuleCyclicAcquisition);
		if(ret)
			return -1;
	}
	
	printf("Do you want to start the acquisition - 0: abort sample , 1: go on\n");
	{
		if ( 0 == get_integer(0,1) )
		{
			printf("aborted on user request\n");
			return -1;
		} 
	}
	
	
	/* start */
	{
		int ret = ioctl( apci3600_get_analog_input_module(pboard,b_Module), CMD_APCI3600_StartAnalogInputModuleCyclicAcquisition, NULL);
		STATUS_MSG_VERBOSE(ret, StartAnalogInputModuleCyclicAcquisition);
		if(ret)
			return -1;
	}
 	return 0;	
}
//--------------------------------------------------------------------------------
int apci3600_EnableDisableMasterTrigger(struct apci3600_card_t * pboard, uint8_t b_Module, unsigned long flag )
{
	int ret = ioctl( apci3600_get_analog_input_module(pboard,b_Module), CMD_APCI3600_AnalogInput_EnableDisableMasterTrigger, flag) ;
	STATUS_MSG_VERBOSE( ret, AnalogInput_EnableDisableMasterTrigger);			
	return ret;		
}
//--------------------------------------------------------------------------------
int apci3600_EnableDisableDigitalInputExternalTrigger(struct apci3600_card_t * pboard, uint8_t b_Module, unsigned long flag )
{
	int ret = ioctl( apci3600_get_analog_input_module(pboard,b_Module), CMD_APCI3600_AnalogInput_EnableDisableDigitalInputExternalTrigger, 0) ;
	STATUS_MSG_VERBOSE( ret, AnalogInput_EnableDisableDigitalInputExternalTrigger);
	return ret;	
}
//--------------------------------------------------------------------------------
int apci3600_ReleaseAnalogInputModule(struct apci3600_card_t * pboard, uint8_t b_Module)
{
	int ret = ioctl( apci3600_get_analog_input_module(pboard,b_Module) ,CMD_APCI3600_ReleaseAnalogInputModule, NULL) ;
	STATUS_MSG_VERBOSE( ret, ReleaseAnalogInputModule);	
	return ret;
}
//--------------------------------------------------------------------------------
int apci3600_StopAnalogInputModuleCyclicAcquisition(struct apci3600_card_t * pboard, uint8_t b_Module)
{
	int ret = ioctl( apci3600_get_analog_input_module(pboard,b_Module) ,CMD_APCI3600_StopAnalogInputModuleCyclicAcquisition, NULL) ;
	STATUS_MSG_VERBOSE( ret, StopAnalogInputModuleCyclicAcquisition);
	return ret;
}
//--------------------------------------------------------------------------------
int apci3600_ReleaseAnalogInputModuleCyclicAcquisition(struct apci3600_card_t * pboard, uint8_t b_Module)
{
	int ret = ioctl( apci3600_get_analog_input_module(pboard,b_Module) ,CMD_APCI3600_ReleaseAnalogInputModuleCyclicAcquisition, NULL) ;
	STATUS_MSG_VERBOSE( ret, ReleaseAnalogInputModuleCyclicAcquisition);
	return ret;
}
//--------------------------------------------------------------------------------
int apci3600_ResetAcquisitionBuffer(struct apci3600_card_t * pboard)
{
	int ret = ioctl( pboard->base ,CMD_APCI3600_ResetAcquisitionBuffer, NULL) ;
	STATUS_MSG_VERBOSE( ret, ResetAcquisitionBuffer);
	return ret;
}
//--------------------------------------------------------------------------------
int apci3600_QueryAnalogInputCyclicAcquisitionNumberOfData(struct apci3600_card_t * pboard, unsigned long * val)
{
	int ret = ioctl( pboard->base ,CMD_APCI3600_QueryAnalogInputCyclicAcquisitionNumberOfData, val) ;
	STATUS_MSG( ret, QueryAnalogInputCyclicAcquisitionNumberOfData);
	return ret;
}
