/*
The I-8014W contains two types of Magic Scan . One is type 1: standard (each sample clock only samples a single. ) 
and Type 2: virtual Sample and hold (each sample clock will to sample all scan channels that have been set. )
Both of two types can set as polling Mode,Internal Hardware trigger Mode and External Hardware trigger Mode
For Magic scan, we can set the FIFO level to trigger the slot Interrupt service and read the FIFO during Interrupt service.
This Demo will show you how to use Magic Scan with Interrupt service ,step by step

Step1:
    ret=i8014W_Init(slot); , this function will check hardware ID,
	if retrun code ret is -1 means this slot may empty or wrong I/O (not I-8014W)
	,return 0 this slot is I-8014W

Step2:
    i8014W_ConfigMagicScan( slot, chArr, gainArr, scanChCount, sampleRate, scanMode, triggerSource, triggerState , & realsampleRate);
    for Configure Magic Scan Parameters and return real sample rate that used by I-8014 module

Step3:
	i8014W_InstallMagicScanISR(slotIndex,ISRFUN,triggerLevel);
	to define the trigger level and Interrupt service

Step4:
	i8014W_StartMagicScan(int slot);
	to start Magic Scan function
	(If i8014W_ConfigMagicScan use external trigger signal mode , module will not start to save data .
	It will start to scan data when the signal is active)

Step5:
    Send a external trigger signal for I-8014 module to Start magic scan
    (external trigger signal Mode only)

Step6:
    i8014W_ReadFIFO(int slot, short hexData[], short readCount,short* dataCountFromFIFO);
    to read data from FIFO during Interrupt service
    Notice we have to use i8014W_ClearInt(slot); in Interrupt service
    If you don't clear the Interrupt, the Interrupt service will be blocked here.

Step7:
	i8014W_UnInstallMagicScanISR(slot);
	i8014W_StopMagicScan( slot);
	stop the Interrupt service and Magic Scan function

Step8:
	to show calibrated analog data.
	When we use Magic scan to read read data from FIFO ,the analog data is not calibrated
	We can use following function to get the calibrated data.
	void i8014W_CalibrateDataHex(int slot, short iGain,short dataFromFIFO, short* calibratedAI);
	void i8014W_CalibrateData(int slot, short iGain,short dataFromFIFO, float* calibratedAI);
*/

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include "msw.h"
#include "i8014W.h"
#define MAX_FIFO	4096

long TargetCnt=100;
unsigned long IntCnt=0;
unsigned long T1,T2; 

int slotIndex, chArr[16], gainArr[16], scanChCount=0, runFlag=1, showCnt=0;
int scanMode=0, triggerSource=-1, triggerState;
short triggerLevel=-1;
float realsampleRate, sampleRate=0;
int  rawData[8192];
int totalScanned=0;
char GainStr[5][32]={"+/-10V","+/-5V","+/-2.5V","+/-1.25V","+/-20mA"};
char ModeStr[2][32]={"Standard Mode", "Sample and Hold Mode"};
char SourceStr[3][32]={"Software Command", "Internal Interrupt Signal","External Trigger Signal"};
char StateStr[2][32]={"High","Low"};

void ISRFUN (int slot);
void ShowAI(void);

int main()
{
	int RetValue,slot,ch, maxCh;
	short ret_fifo=0,i,ret, jumper, readFromFIFO=0;
	char sTemp[20],c;
	unsigned short triggerCnt[8]={8,16,32,64,128,256,512,2048};

	printf("\n This Demo will show how to use magic scan function to read analog input\n");
	printf(" Search I-8014W ....\n");
	Open_Slot(9);
	for(slot=1;slot<9;slot++)
	{
		RetValue = Open_Slot(slot);
		if (RetValue == 0) {
			if(i8014W_Init(slot) == 0) //find I-8014W module out
			{
				slotIndex=slot;
				break;
			}
		}
	}

	if(slotIndex==-1)
	{
		printf("\t There is no I-8014W at LP-8x4x !\n");
		usleep(10);
		return FAILURE;  // end of program
	}
	else
		printf("\t There is an I-8014W at slot %d\n", slotIndex);

	jumper= i8014W_GetSingleEndJumper(slotIndex);
	if(jumper)
	{
	    	maxCh=16;
		printf("\t I-8014W Input Mode=Single-End and can have maximum 16 analog input\n");
	}
	else
	{ 
     		maxCh=8;
		printf("\t I-8014W Input Mode=Differential and can have maximum 8 analog input\n");
	}

	// define the sampling channels array chArr[]
	// Differential Mode: element for chArr[] range from channel 0 ~ 7 ,
	// Single ended Mode: element for chArr[] range from channel 0 ~ 15
	// max element counts for chArr[] can be 16
	// define gain type array for each channel
	// gainArr[] element for gainArr[] range from channel 0 ~ 15
	// Gain value : 0="+/-10V", 1="+/-5V", 2="+/-2.5V", 3="+/-1.25V", 4="+/-20mA"
	// max element counts for gainArr[] can be 16
start:
	printf("\n Input all i8014W_ConfigMagicScan parameters :\n");
	printf("\n Step 1: Define scaned channel counts for magic scan:");

	while ((scanChCount <1)||(scanChCount >maxCh))
	{
		printf("\n Input scaned channel counts (1 to %d) :", maxCh);
		scanf("%d",&scanChCount);
	}

	printf(" Now we have scaned channel counts = %d\n\n",scanChCount);
	printf("\n Step 2: Define %d elements for channel and gain array",scanChCount);
	printf("\n The Gain definition of I-8014W");

	for(i=0;i<5;i++)
	{
	    	printf ("\n\t Select %d :  %s",i,GainStr[i]);
	}
	printf("\n");

	if(maxCh==8) // Differential Mode
    		printf ("\n Differential Mode range : channel 0 to 7\n\r");
	else // Single-Ended mode
    		printf ("\n Single ended Mode range : channel 0 to 15\n\r");

	for(i=0;i<scanChCount;i++)
	{
    		printf (" Select which Channel of Arr[%d] (0 to %d) :",i,maxCh-1);
		scanf("%d",&chArr[i]);
		printf (" Select which Gain of Arr[%d](0 to 4):",i);
		scanf("%d",&gainArr[i]);
	}

	// Sample channel counts
	// scanChCount can be 1 ~ 16 (max =16 for both Differential and Single Ended)

	printf("\n\n Step 3: Define Sample Rate of I-8014W\n");
	printf(" Note1: the real sample rate may not the same as user input\n");
	printf(" Note2: You can input 10 Hz sample rate to take a look for \n\t change of Interrupt Count and  total data count read from FIFO ");
	printf("\n      the function i8014W_ConfigMagicScan return code is the \n real sample rate accepted by I-8014W\n");
  // Sample rate : 2 ~ 250KHz
	sampleRate=0;

	while((sampleRate < 2)||(sampleRate > 250000)) // Sample rate : 2 ~ 250KHz
	{
		printf("Input Sample rate of 8014W (2~250000): ");
		scanf("%f",&sampleRate);
	}
	printf("sampleRate=%f \n", sampleRate);

	// Scan Mode = 1 M1 standard mode, Each Sample clock only samples a single channel
	// Scan Mode = 2 M2 Sample and hold Mode
	printf("\n\n Step 4: Select Scan Mode of I-8014W:\n");
	printf("\t Scan Mode 1= M1 Standart Mode(Each sample clock only samples a single) \n\t Scan Mode 2= M2 Sample and Hold Mode \n\r");

	while((scanMode < 1)||(scanMode > 2))
	{
		printf(" Input Scan Mode of I-8014W (1 or 2) :");
		scanf("%d",&scanMode);
	}
	printf(" scan mode=%d \n", scanMode);

   // trigger source 0, start magic scan via polling Mode, software command can only trigger one slot I-8014
   // trigger source 1, start magic scan via internal interrupt signal Mode, internal interrupt signal can trigger all I-8014Ws on slots at the same time.
   // trigger source 2, start magic scan via external trigger signal Mode, extern trigger can also trigger all I-8014Ws on slots at the same time.
	printf("\n\n Step 5: Select Trigger Source of I-8014W,\n I-8014W can have 3 types of trigger source \n");
	printf("\t trigger source 0= Software Command \n\t trigger source 1= Internal Interrupt Signal \n\t trigger source 2= External Tigger Signal\n\r");
	while((triggerSource <0)||(triggerSource >2))
	{
		printf(" Input trigger source of I-8014W (0 to 2) :");
		scanf("%d",&triggerSource);
	}

  // triggerState only related with external DI trigger signal.
  // if triggerState 0, external DI trigger signal must be high to start magic scan (default)
  // if triggerState 1, external DI trigger signal must be low to start magic scan
	printf("\n\n Step 6: Select Trigger State of I-8014W if select external trigger source.\n");
	if(triggerSource==2)
	{
		printf("\t trigger State 0= external trigger singal high to start magic scan \n\t trigger State 1= external trigger signal low to start magic scan\n\r");
		printf(" Input trigger State of I-8014W (0 or 1) :");
		scanf("%d",&triggerState);
	}
	else
	{
		printf("\tNot external trigger source, trigger state = 0\n");
		triggerState=0;
	}

/*	triggerLevel used to define the FIFO level to trigger the Interrupt ISR function
	for this example, we define triggerLevel = 2,
	means the ISR function will be trigger every time when FIFO get 32 AI short values (64 bytes data)
	The following table
		triggerLevel 0:
			FIFO count to trigger Interrupt ISR = 8 short AI values, 16 bytes
		triggerLevel 1:
			FIFO count to trigger Interrupt ISR = 16 short AI values, 32 bytes
		triggerLevel 2:
			FIFO count to trigger Interrupt ISR = 32 short AI values, 64 bytes
		triggerLevel 3:
			FIFO count to trigger Interrupt ISR = 64 short AI values, 128 bytes
		triggerLevel 4:
			FIFO count to trigger Interrupt ISR = 128 short AI values,  256 bytes
		triggerLevel 5:
			FIFO count to trigger Interrupt ISR = 256 short AI values,  512 bytes
		triggerLevel 6:
			FIFO count to trigger Interrupt ISR = 512 short AI values, 1024 bytes
		triggerLevel 7:	
			FIFO count to trigger Interrupt ISR = 2048 short AI values, 4096 bytes
	*/
	while ((triggerLevel <0)||(triggerLevel>7)) // Sample rate : 2 ~ 250KHz
	{
		printf("\n Input triggerLevel of I-8014W (0 to 7): ");
		scanf("%hd",&triggerLevel);
	}
	printf(" triggerLevel = %d\n\n",triggerLevel);

  // When Configure Sample Rate of Magic Scan, the result sample rate may be different from input sample rate
  // Note i8014W_ConfigMagicScan only tell I-8014W how to start magic scan,it will not start magic scan
  // We have to call i8014W_StartMagicScan to start up the magic scan.
  // i8014W_ConfigMagicScan(int slot,int chArr[],int gainArr[],int scanChCount, float sampleRate,int scanMode,int triggerSource,int triggerState, float* realSampleRate);
	i8014W_ConfigMagicScan(slotIndex,chArr,gainArr,scanChCount, sampleRate, scanMode,triggerSource,triggerState, &realsampleRate);

	printf("The Magic Scan Configurations of I-8014W are:\n");
	printf("\t Scan channel count = %d\n", scanChCount);

	for(i=0;i<scanChCount;i++)
	{
		printf("\t CH[%d]= %d\t Gain[%d]= %d ( %s )\n",i, chArr[i],i, gainArr[i], GainStr[gainArr[i]]);
	}
	
	printf("\t Scan Mode = %d ( %s )\n", scanMode, ModeStr[scanMode-1]);
	printf("\t Trigger Source = %d ( %s )\n", triggerSource, SourceStr[triggerSource]);

	if(triggerSource==2)
		printf("\t Trigger State = %d ( %s )\n", triggerState, StateStr[triggerState]);
	else
		printf("\t Trigger State = %d ( No need for External Trigger Signal )\n",triggerState);
	printf("\t Set Sample Rate = %f  Real Sample Rate = %f \n\n",sampleRate, realsampleRate);
	printf("The Interrupt ISR will be triggered when FIFO reach %d count \n", triggerCnt[triggerLevel]);
	printf("Start magic scan:  \n");
	if(triggerSource==2) //Wait external trigger for I-8014W module
		printf("Wait for external trigger signal source to %s ....\n", StateStr[triggerState]);
	else
		printf("Wait for Magic Scan .....\n");

	// When we InstallMagicScanISR, we can read the data from the FIFO in Interrupt service
	// The main loop function can do other things
	i8014W_InstallMagicScanISR(slotIndex,ISRFUN,triggerLevel);
 	i8014W_StartMagicScan(slotIndex);

	T1=GetTimeTicks_ms();
	totalScanned=0;
	runFlag=1;

	while(runFlag==1)
	{
	 	// We can check the trigger level for ISR here if we use low sample rate
	 	// If you use high sample rate, we have to avoid printf data during interrupt service
	 	// In this demo the trigger level =2 , we can notice the totalScaned increase 32 AI data every time when IntCnt increase
	 	// If you use 10Hz sample rate, you can understand the change between totalScaned and IntCnt.
	 	//test read fifo
	 	// ret_fifo=i8014W_ReadFIFO(slotIndex,rawData+totalScaned, TargetCnt-totalScaned,&readFromFIFO);// <=== get data from FIFO ,long* dataCnt
    //  if(realsampleRate <=100)
    //	{
    //   	printf("ret_fifo:%d, total scaned %05d, read %05ld  left %05ld  Int %010lu \n", ret_fifo, totalScaned,readFromFIFO,TargetCnt-totalScaned,IntCnt);
    // 	}
	//printf("totalScanned is %d\n",totalScanned);
		if(realsampleRate <=100)
	   		printf("total %05d Int %010lu\r",totalScanned,IntCnt);
	    	/*if(readFromFIFO>0)
		{
	    		totalScanned+=readFromFIFO;
			printf("here\n");
		}*/
		// End of demo test
		if(totalScanned>=TargetCnt)
		{
			printf("\nStop magic scan and FIFO data amount = %d  spend time %lu\n", totalScanned, GetTimeTicks_ms()-T1);
			i8014W_UnInstallMagicScanISR(slotIndex);
	    		i8014W_StopMagicScan(slotIndex);
			runFlag=0;
			IntCnt=0;
		}
		usleep(1000);
	}

	T2=GetTimeTicks_ms()-T1; // total time for magic scan to polling data
	printf("Magic scan total spend time = %lu ms  \n\n",T2);
	printf("Press 's' or 'S' to Show AI, others to next step\n\r");
	scanf("%s",&c);
	if(c=='s' || c=='S')
		ShowAI();

	printf("Press 'q' or 'Q' to exit program, others to Start magic scan again!\n\r");
	scanf("%s",&c);
	if(c!='q' && c!='Q'){
		scanChCount=0;
		sampleRate=0;
		scanMode=0;
		triggerSource=-1;
		triggerLevel=-1;
		goto start;  // continue another test
	}
	Close_Slot(slotIndex);
	Close_Slot(9);
	return SUCCESS;
}

// Don't use printf, Getch , Scanf in Interrupt service
void ISRFUN(int slot)
{
	int i, ret, readCnt = 0;

	IntCnt++;
	ret= i8014W_ReadFIFO_InISR(slot,rawData + totalScanned, triggerLevel,&readCnt);	
	i8014W_ClearInt(slot);
	//printf("readCnt=%d\t , ret=%d, \n",readCnt,ret);
	if(ret!=0 || readCnt==MAX_FIFO)
	{
		i8014W_UnInstallMagicScanISR(slot);
		i8014W_StopMagicScan(slot);
		return ;
	}

	if(readCnt>0)
 	{
 		totalScanned+=readCnt;
		if(totalScanned >=TargetCnt)
		{
			i8014W_StopMagicScan(slot);
			//i8014W_UnInstallMagicScanISR(slot);  //winson
		}
 	}
}

void ShowAI(void)
{
	int i, c;
	float calibratedAI=0;
	printf("Start to print all %d data:\n\n\r",totalScanned);

	for(i=0;i<totalScanned;i++)
	{
		i8014W_CalibrateData(slotIndex, gainArr[i %scanChCount],rawData[i],&calibratedAI);
		printf("i=%d: Arr[%d]=%5.4f\t",i,i%scanChCount,calibratedAI);
		if(i%3 == 2)
			printf("\n");
	}
	printf("\n-----------------------------------\n");
}
