/* Reads 1 Analog Input in Auto-Stop/Ring Buffer Mode */
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
#include <limits.h>
#include <fcntl.h>
#include <errno.h>
#include <assert.h>
#include <ctype.h>
#include <sys/sysmacros.h> /* major() minor() */

#include "consoleio.h"
#include "debug.h"
#include "apci3600msg.h"
#include "findboards.h"
#include "configuration.h"
#include "displayboardinitialisation.h"
#include "retrieve.h"
#include "event.h"

#include <apci3600.h>

#include <apci3600-analoginput.h>

//--------------------------------------------------------------------------------
static int open_file(char * file_path)
{
	int fd = open(file_path, O_WRONLY | O_CREAT | O_TRUNC ); 
	if ( -1 == fd )
	{
		perror("open");
		exit(1);
	}
	
	printf("file %s opened (O_WRONLY | O_CREAT | O_TRUNC)\n",file_path);
	return fd;
}

//--------------------------------------------------------------------------------
void help(void)
{
	fprintf(stderr,"sample13 PATH/TO/DATA/FILE [MAX]\n");
	fprintf(stderr,"\tPATH/TO/DATA/FILE: file to store acquired data (in binary format)\n");
	fprintf(stderr,"\tMAX: number of bytes to acquire before stopping acquisition\n");
}

//--------------------------------------------------------------------------------


static int check_str_has_only_digit(const char * str)
{
	int index = 0;
	while(str[index] != '\0')
	{
		if(!isdigit(str[index]))
		{
			fprintf(stderr,"MAX can contain only digit\n");
			exit(1);
		}
		index++;
	}
	return 0;
}
//--------------------------------------------------------------------------------
static unsigned long long parse_max(const char * arg)
{
	unsigned long long tmpmax = 0;
	
	check_str_has_only_digit(arg);
	       
	/* try to parse number in base 10 */
	{
		char * tail = NULL;
		
		errno = 0;
		tmpmax = strtoull(arg,&tail,10);
		
		/* could not parse number ? */
		if ( tail == arg )
		{
			fprintf(stderr,"could not parse number %s\n",arg);
			exit(1);
		}
		if (ERANGE == errno)
		{
			fprintf(stderr,"overflow while parsing number %s\n",arg);
			exit(1);
		}
	}
	return tmpmax;	
}

//--------------------------------------------------------------------------------
int main(int argc, char** argv)
{
	struct apci3600_card_t ** apci3600_cards = NULL; /* array of struct apci3600_card_t - allocated by apci3600_find_boards() */
	int apci3600_card_number = 0;
	struct apci3600_card_t * pboard = NULL; /* index of the board the user wish to work with (if there is only one board, select it) */ 
	uint8_t b_Module = 0; /* module to use */
	int data_file = -1; /* file desc. of data file */
	unsigned long long max = 0;
	
	/* */
	int b_ExternalTriggerUsed = 0;
    int b_MasterTriggerUsed = 0;	
	
	int retval = 0;
		
	/* must have one arg: file to save data in  */
	switch(argc)
	{
		case 3:
			max = parse_max(argv[2]);
		case 2:
			data_file = open_file(argv[1]);		
			break;
		default:
			printf("bad number of arguments\n");
			help();
			exit(1);		
	} 

	assert( 0 != (apci3600_card_number = apci3600_find_boards(&apci3600_cards) ) );

	max ? printf("acquisition stops when at least %llu bytes are acquired\n",max) : printf("acquisition in endless loop\n");
	
	if (apci3600_card_number>1)
	{
		printf("which board do you want to access ? (%i-%i) \n", 0, apci3600_card_number-1 );
		pboard=apci3600_cards[get_integer(0, apci3600_card_number-1)];
	}
	else
		pboard=apci3600_cards[0];
	
	ASSERT_SUCCESS( apci3600_ResetAcquisitionBuffer(pboard) );
		
	ASSERT_SUCCESS( i_Board_Initialisation(pboard) );

	/* from now on must CMD_APCI3600_ReleaseAnalogInputModule be called */

	if ( i_Analog_Input_Initialisation(pboard,&b_Module) )
	{
		retval = 1;
		goto release_analog_input_module;
	}
	
	/* external trigger */
	{
		printf("Do you want to use the external trigger (0 : No or 1 : Yes) ?\n");
		b_ExternalTriggerUsed = get_integer(0,1);
		if(b_ExternalTriggerUsed)
		{
			/* configure external trigger */
			if( i_External_Trigger_Initialisation( pboard ) )
			{
				retval = 1;
				goto release_analog_input_module;
			}
			/* start external trigger */
			{
				if ( apci3600_EnableDisableDigitalInputExternalTrigger(pboard, b_Module, 1 ) )
				{
					retval = 1;
					goto release_analog_input_module;
				}
			}
		}
	}
	if (  i_Display_Board_Initialisation(pboard) ) 
	{
		retval = 1;
		goto release_analog_input_module;
	}	
	
	/* master trigger */
	{
		printf("Do you want to use the master trigger (0 : No or 1 : Yes) ?\n");
		b_MasterTriggerUsed = get_integer(0,1);
		
		if(b_MasterTriggerUsed)
		{
			/* start master trigger */
			if ( apci3600_EnableDisableMasterTrigger(pboard, b_Module, 1 ) )
			{
				retval = 1;
				goto disable_digital_input_extern_trigger;
			}
		}		
	}
	
	/* before strting, empty drivers event FIFO */
	if ( apci3600_empty_event_buffer(pboard) )
	{
		retval = -1;
		goto disable_analog_input_master_trigger;
	}
	
	/* init and start acquisition */
	if ( i_Init_And_Start_Cyclic_Acquisition(pboard, b_Module) )
		goto disable_analog_input_master_trigger;
	
	/* wait for event and get data*/
	apci3600_loop_and_read_data(pboard, b_Module, data_file, max);

	/* stop acquisition */
	apci3600_StopAnalogInputModuleCyclicAcquisition(pboard, b_Module);

	/* release acquisition */
	apci3600_ReleaseAnalogInputModuleCyclicAcquisition(pboard, b_Module);
	
	disable_analog_input_master_trigger:
		if(b_MasterTriggerUsed)
		{
			apci3600_EnableDisableMasterTrigger(pboard, b_Module, 0 );
		}

	disable_digital_input_extern_trigger:
		if(b_ExternalTriggerUsed)
		{
			apci3600_EnableDisableDigitalInputExternalTrigger(pboard, b_Module, 0 );
		}
	release_analog_input_module:			
		apci3600_ReleaseAnalogInputModule(pboard, b_Module);
		
	return retval;
}
