/*******************************************************************************
 *	Comedi_test8.c		Simple COMEDI tests
 *				T.Barnaby,	Beam Ltd,	2006-02-07
 *******************************************************************************
 *
 *	RTSI trigger test.
 *	This test program reads continuous samples from 16 channels.
 *	The DAQ hardware is set so the first board is a master and another
 *	board is slaved to it.
 *	The DAQ hardware sets the sample rate and the sample sequence starts
 *	under program control.
 */ 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <comedilib.h>
#include <sys/time.h>

#define	BUFSZ	256

#ifdef ZAP
#define	NI_PFI_AI_START1	0
#define	NI_PFI_AI_START2	1
#define	NI_PFI_CONV		2
#define	NI_PFI_G_SRC1		3
#define	NI_PFI_G_GATE1		4
#define	NI_PFI_UPDATE		5
#define	NI_PFI_AO_START1	6	
#define	NI_PFI_AI_START		7	
#define	NI_PFI_G_SRC0		8
#define	NI_PFI_G_GATE0		9

#define	NI_PFI_AI_START_TRIG	0
#define	NI_PFI_AI_REF_TRIG	1
#define	NI_PFI_2		2
#define	NI_PFI_CT1_SRC		3
#define	NI_PFI_CT1_GATE		4
#define	NI_PFI_AO_SAMP_CLOCK	5
#define	NI_PFI_AO_START_TRIG	6	
#define	NI_PFI_AI_SAMP_CLOCK	7	
#define	NI_PFI_CTR0_SRC		8
#define	NI_PFI_CTR0_GATE	9
#endif

// Get current time in seconds
double getTime()
{
	struct timeval	tp;
	
	gettimeofday(&tp, NULL);
	return ((double) tp.tv_sec + (double) tp.tv_usec * 1e-6);
}

char *cmd_src(int src,char *buf)
{
	buf[0]=0;

	if(src&TRIG_NONE)strcat(buf,"none|");
	if(src&TRIG_NOW)strcat(buf,"now|");
	if(src&TRIG_FOLLOW)strcat(buf, "follow|");
	if(src&TRIG_TIME)strcat(buf, "time|");
	if(src&TRIG_TIMER)strcat(buf, "timer|");
	if(src&TRIG_COUNT)strcat(buf, "count|");
	if(src&TRIG_EXT)strcat(buf, "ext|");
	if(src&TRIG_INT)strcat(buf, "int|");
#ifdef TRIG_OTHER
	if(src&TRIG_OTHER)strcat(buf, "other|");
#endif

	if(strlen(buf)==0){
		sprintf(buf,"unknown(0x%08x)",src);
	}else{
		buf[strlen(buf)-1]=0;
	}

	return buf;
}

void dump_cmd(FILE *out,comedi_cmd *cmd)
{
	char buf[100];

	fprintf(out,"subdev:      %d\n", cmd->subdev);
	fprintf(out,"flags:       %x\n", cmd->flags);

	fprintf(out,"start:      %-8s %d\n",
		cmd_src(cmd->start_src,buf),
		cmd->start_arg);

	fprintf(out,"scan_begin: %-8s %d\n",
		cmd_src(cmd->scan_begin_src,buf),
		cmd->scan_begin_arg);

	fprintf(out,"convert:    %-8s %d\n",
		cmd_src(cmd->convert_src,buf),
		cmd->convert_arg);

	fprintf(out,"scan_end:   %-8s %d\n",
		cmd_src(cmd->scan_end_src,buf),
		cmd->scan_end_arg);

	fprintf(out,"stop:       %-8s %d\n",
		cmd_src(cmd->stop_src,buf),
		cmd->stop_arg);
	
	fprintf(out,"chanlist_len: %d\n", cmd->chanlist_len);
	fprintf(out,"data_len: %d\n", cmd->data_len);
	
}

void comediEnableMaster(comedi_t* dev){
	comedi_insn	configCmd;
	lsampl_t	configData[2];
	int		ret;
	unsigned int	d = 0;;
	
	// Configure the RTSI bus device
	memset(&configCmd, 0, sizeof(configCmd));
	memset(&configData, 0, sizeof(configData));
	configCmd.insn = INSN_CONFIG;
	configCmd.subdev = 10;
	configCmd.chanspec = 0;
	configCmd.n = 2;
	configCmd.data = configData;
	configCmd.data[0] = INSN_CONFIG_SET_RTSI_CLOCK_MODE;
	configCmd.data[1] = COMEDI_RTSI_CLOCK_MODE_MASTER;

	ret = comedi_do_insn(dev, &configCmd);
	if(ret < 0){
		comedi_perror("comedi_command: INSN_CONFIG");
		exit(1);
	}

	// Set direction of the 3 main AI RTSI signals
#ifndef ZAP
	ret = comedi_dio_config(dev, 10, NI_RTSI_0, 1);
#endif
	ret = comedi_dio_config(dev, 10, NI_RTSI_1, 1);
#ifndef ZAP
	ret = comedi_dio_config(dev, 10, NI_RTSI_2, 1);
#endif
	if(ret < 0){
		comedi_perror("comedi_command: INSN_CONFIG: 1");
		exit(1);
	}
	return;

	
	// Configure the PFI bus device
	memset(&configCmd, 0, sizeof(configCmd));
	memset(&configData, 0, sizeof(configData));
	configCmd.insn = INSN_CONFIG;
	configCmd.subdev = 7;
	configCmd.n = 1;
	configCmd.data = configData;
	configCmd.data[0] = COMEDI_OUTPUT;
	configCmd.data[0] = INSN_CONFIG_DIO_QUERY;
	configCmd.chanspec = 0;

	ret = comedi_do_insn(dev, &configCmd);
	if(ret < 0){
		comedi_perror("comedi_command: INSN_CONFIG");
		exit(1);
	}
	printf("Setting: %d\n", configData[1]);
}

void comediEnableSlave(comedi_t* dev){
	comedi_insn	configCmd;
	lsampl_t	configData[2];
	int		ret;
	unsigned int	d = 0;;
	
	// Configure the PFI bus device
	memset(&configCmd, 0, sizeof(configCmd));
	memset(&configData, 0, sizeof(configData));
	configCmd.insn = INSN_CONFIG;
	configCmd.subdev = 10;
	configCmd.chanspec = 0;
	configCmd.n = 2;
	configCmd.data = configData;
	configCmd.data[0] = INSN_CONFIG_SET_RTSI_CLOCK_MODE;
	configCmd.data[1] = COMEDI_RTSI_CLOCK_MODE_SLAVE;

	ret = comedi_do_insn(dev, &configCmd);
	if(ret < 0){
		comedi_perror("comedi_command: INSN_CONFIG");
		exit(1);
	}
}

int main(int argc,char *argv[])
{
	int		subdevice = 0;
	int		aref = AREF_GROUND;
	int		range = 0;
	int		nChannels = 8;
	int		sampleRate = 50000;

	comedi_t*	dev0;
	comedi_t*	dev1;
	int		ret;
	unsigned int	chanList[24];
	comedi_cmd	cmd0;
	comedi_cmd	cmd1;
	int		i;
	sampl_t		buf[BUFSZ];
	int		subdev_flags;
	int		bytes_per_sample;
	double		timeStart;
	double		timeNow;
	double		r;
	double		nSamples = 0.0;
	int		n = 0;
	
	dev0 = comedi_open("/dev/comedi0");
	if(!dev0){
		fprintf(stderr,"cannot open %s\n", "/dev/comedi0");
		exit(0);
	}

	printf("Info:\n");
	printf("Version code: 0x%06x\n", comedi_get_version_code(dev0));
	printf("Driver name: %s\n", comedi_get_driver_name(dev0));
	printf("Board name: %s\n", comedi_get_board_name(dev0));
	printf("Number of subdevices: %d\n", comedi_get_n_subdevices(dev0));

	dev1 = comedi_open("/dev/comedi1");
	if(!dev1){
		fprintf(stderr,"cannot open %s\n", "/dev/comedi1");
		exit(0);
	}
	printf("Info:\n");
	printf("Version code: 0x%06x\n", comedi_get_version_code(dev1));
	printf("Driver name: %s\n", comedi_get_driver_name(dev1));
	printf("Board name: %s\n", comedi_get_board_name(dev1));
	printf("Number of subdevices: %d\n", comedi_get_n_subdevices(dev1));

	subdev_flags = comedi_get_subdevice_flags(dev0, subdevice);
	if(subdev_flags & SDF_LSAMPL)
		bytes_per_sample = sizeof(lsampl_t);
	else
		bytes_per_sample = sizeof(sampl_t);
	printf("SampleSize: %d\n", bytes_per_sample);


	// Enable signals from Master device
	comediEnableMaster(dev0);
	comediEnableSlave(dev1);

	// Setup chan list
	for(i = 0; i < nChannels; i++){
		chanList[i] = CR_PACK(i, range, aref);
	}
	
	// Set up command
	memset(&cmd0, 0, sizeof(cmd0));
	ret = comedi_get_cmd_generic_timed(dev0, subdevice, &cmd0, int(1e9/sampleRate));
	if(ret<0){
		printf("comedi_get_cmd_generic_timed failed\n");
		return ret;
	}
	cmd0.chanlist		= chanList;
	cmd0.chanlist_len	= nChannels;
	cmd0.scan_begin_arg	= int(1e9/sampleRate);
	cmd0.scan_end_arg	= nChannels;
	cmd0.stop_src		= TRIG_NONE;
	
	dump_cmd(stderr, &cmd0);

	// Test command
	ret = comedi_command_test(dev0, &cmd0);
printf("Ret: %d\n", ret);
	if(ret < 0){
		comedi_perror("CmdTest1");
		exit(0);
	}
	dump_cmd(stderr, &cmd0);
	ret = comedi_command_test(dev0, &cmd0);
printf("Ret: %d\n", ret);
	if(ret < 0){
		comedi_perror("CmdTest1");
		exit(0);
	}
	dump_cmd(stderr, &cmd0);

printf("Exit0\n");
exit(0);	
	// Set up command
	memset(&cmd1, 0, sizeof(cmd1));
	ret = comedi_get_cmd_generic_timed(dev1, subdevice, &cmd1, int(1e9/sampleRate));
	if(ret<0){
		printf("comedi_get_cmd_generic_timed failed\n");
		return ret;
	}
	cmd1.chanlist		= chanList;
	cmd1.chanlist_len	= nChannels;
	cmd1.scan_end_arg	= nChannels;
#ifndef ZAP
	cmd1.start_src		= TRIG_EXT;
	cmd1.start_arg		= CR_EDGE | NI_EXT_RTSI_0;
#endif
#ifndef ZAP
	cmd1.convert_src	= TRIG_EXT;
	cmd1.convert_arg	= CR_INVERT | CR_EDGE | NI_EXT_RTSI_2;
#endif
	cmd1.stop_src		= TRIG_NONE;
	
	dump_cmd(stderr, &cmd1);
exit(1);
	// Test command
	ret = comedi_command_test(dev1, &cmd1);
	if(ret < 0){
		comedi_perror("CmdTest1");
		exit(0);
	}
	ret = comedi_command_test(dev1, &cmd1);
	if(ret < 0){
		comedi_perror("CmdTest1");
		exit(0);
	}
	

	timeStart = getTime();
	/* Start the commands */
	ret = comedi_command(dev1, &cmd1);
	if(ret < 0){
		comedi_perror("comedi_command");
		exit(1);
	}
	ret = comedi_command(dev0, &cmd0);
	if(ret < 0){
		comedi_perror("comedi_command");
		exit(1);
	}

	while(1){
		ret = read(comedi_fileno(dev0), buf, BUFSZ);
		printf("Read Dev0 returns: %d\n", ret);
		if(ret < 0){
			perror("read");
			exit(1);
		}
		if(ret == 0)
			break;

		ret = read(comedi_fileno(dev1), buf, BUFSZ);
		printf("Read Dev1 returns: %d\n", ret);
		if(ret < 0){
			perror("read");
			exit(1);
		}
		if(ret == 0)
			break;

		nSamples += (ret / bytes_per_sample);


		n++;
#ifdef ZAP
		if((n % 1) == 0){
//			if((n % 256) == 0){		
			timeNow = getTime();
			r = nSamples / (timeNow - timeStart);
			printf("NSamples: %6.0f Rate: %6.2f\n", nSamples, r);
		}
#endif
	}

	return 0;
}
