/*******************************************************************************
 *	Comedi_test7.c		Simple COMEDI tests
 *				T.Barnaby,	Beam Ltd,	2006-02-02
 *******************************************************************************
 *
 *	RTSI trigger test.
 *	This test program reads continuous samples from 8 channels.
 *	The DAQ hardware is set so the board is a master.
 *	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,"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);
}

void comediEnableMaster(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_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
	ret = comedi_dio_config(dev, 10, NI_RTSI_0, 1);
	ret = comedi_dio_config(dev, 10, NI_RTSI_1, 1);
	ret = comedi_dio_config(dev, 10, NI_RTSI_2, 1);
	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]);
}

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

	comedi_t*	dev;
	int		ret;
	unsigned int	chanList[24];
	comedi_cmd	cmd;
	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;
	
	dev = comedi_open("/dev/comedi0");
	if(!dev){
		fprintf(stderr,"cannot open %s\n", "/dev/comedi0");
		exit(0);
	}

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

	// Enable signals from Master device
	comediEnableMaster(dev);
	
	// Setup chan list
	for(i = 0; i < nChannels; i++){
		chanList[i] = CR_PACK(i, range, aref);
	}
	
	// Set up command
	memset(&cmd, 0, sizeof(cmd));
	ret = comedi_get_cmd_generic_timed(dev, subdevice, &cmd, int(1e9/sampleRate));
	if(ret<0){
		printf("comedi_get_cmd_generic_timed failed\n");
		return ret;
	}
	cmd.chanlist		= chanList;
	cmd.chanlist_len	= nChannels;
	cmd.scan_end_arg	= nChannels;
//	cmd.stop_src		= TRIG_NONE;
	cmd.stop_src		= TRIG_COUNT;
	cmd.stop_arg		= 32;
	
	dump_cmd(stderr, &cmd);

	// Test command
	ret = comedi_command_test(dev, &cmd);
	if(ret < 0){
		comedi_perror("CmdTest1");
		exit(0);
	}
	ret = comedi_command_test(dev, &cmd);
	if(ret < 0){
		comedi_perror("CmdTest1");
		exit(0);
	}
	
	subdev_flags = comedi_get_subdevice_flags(dev, 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);

	timeStart = getTime();
	while(1){
		/* Start the command */
		ret = comedi_command(dev, &cmd);
		if(ret < 0){
			comedi_perror("comedi_command");
			exit(1);
		}

		while(1){
			ret = read(comedi_fileno(dev), buf, BUFSZ);
//			printf("Read 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;
}
