/*
The I-9014 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=i9014_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-9014) 
	,return 0 this slot is I-9014 	
	
Step2: 
    i9014_ConfigMagicScan( slot, chArr, gainArr, scanChCount, sampleRate, scanMode, triggerSource, triggerState , & realsampleRate);
    for Configure Magic Scan Parameters and return real sample rate that used by I-9014 module	

Step3:
	i9014_InstallMagicScanISR(slotIndex,ISRFUN,triggerLevel);
	to define the trigger level and Interrupt service
	
Step4:
	i9014_StartMagicScan(int slot);
	to start Magic Scan function 
	(If i9014_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:
    i9014_ReadFIFO(int slot, short hexData[], short readCount,short* dataCountFromFIFO);
    to read data from FIFO during Interrupt service
    Notice we have to use i9014_ClearInt(slot); in Interrupt service
    If you don't clear the Interrupt, the Interrupt service will be blocked here.

Step7:
	i9014_UnInstallMagicScanISR(slot);
	i9014_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 i9014_CalibrateDataHex(int slot, short iGain,short dataFromFIFO, short* calibratedAI);
	void i9014_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=-1, chArr[16], gainArr[16], scanChCount=0, runFlag=1, showCnt=0;
int scanMode=0, triggerSource=-1, triggerState;
float realsampleRate, sampleRate=0;
short triggerLevel=-1;
int  rawData[8192],totalScanned=0;
char GainStr[5][32]={"+/-10V","+/-5V","+/-2.5V","+/-1.25V","+/-20mA"};
char ModeStr[2][32]={"Standard Mode", "Virtual Sample and Hold Mode"};
char SourceStr[3][36]={"Software Command", "Internal Hardware Trigger Signal","External Hardware Trigger Signal"};
char StateStr[2][32]={"High","Low"};

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

int main()
{
	int RetValue,slot,ch, maxCh,readFromFIFO=0;
	short ret_fifo=0,i,ret, jumper ;
	char 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("Which slot does I-9014 plut in?...  ");
	scanf("%d", &slot);
	printf("\n");
	if ((slot<0)&&(slot>8)){
		return FAILURE;
  }
  
start: 	      
	Open_Slot(9);
	RetValue = Open_Slot(slot);
	printf("slot=%d, slotIndex=%d\n", slot, slotIndex);
	if (RetValue >0) {
		printf("Open Slot %d failed!\n",slot);
		return FAILURE;
	}
	else
	{ 
		if (i9014_Init(slot) != -1){
			slotIndex=slot;
			printf("\t There is an I-9014 at slot %d\n",slotIndex);
		}
		else {
			printf("Init I-9014 at slot %d failure!\n",slotIndex);
			Close_Slot(9);
			Close_Slot(slotIndex);
			return FAILURE;
		}
	}
  
	jumper= i9014_GetSingleEndJumper(slotIndex);
	if(jumper)
	{
		maxCh=16;
		printf("\t I-9014 Input Mode=Single-End and can have maximum 16 analog input\n");
	}
	else
	{
		maxCh=8;
		printf("\t I-9014 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 i9014_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-9014");
	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-9014\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 i9014_ConfigMagicScan return code is the \n real sample rate accepted by I-9014\n");
	// Sample rate : 2 ~ 250KHz  
	sampleRate=0;
	while ((sampleRate <2)||(sampleRate >2500000)) // Sample rate : 2 ~ 250KHz  
	{ 
		printf (" Input Sample rate of 9014 (2~2500000): ");
		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 Virtual Sample and hold Mode
	printf ("\n\n Step 4: Select Scan Mode of I-9014:\n");
	printf ("\t Scan Mode 1= M1 Standart Mode(Each sample clock only samples a single) \n\t Scan Mode 2= M2 Virtual Sample and Hold Mode \n\r");
	while ((scanMode <1)||(scanMode >2))
	{ 
		printf (" Input Scan Mode of I-9014 (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 hardware trigger signal Mode, internal interrupt signal can trigger all I-9014s on slots at the same time.
	// trigger source 2, start magic scan via external hardware trigger signal Mode, extern trigger can also trigger all I-9014s on slots at the same time.
	printf ("\n\n Step 5: Select Trigger Source of I-9014,\n I-9014 can have 3 types of trigger source \n");
	printf ("\t trigger source 0= Software Command \n\t trigger source 1= Internal Hardware Tigger Signal \n\t trigger source 2= External Hardware Tigger Signal\n\r");
	while ((triggerSource <0)||(triggerSource >2))
	{ 
		printf (" Input trigger source of I-9014 (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-9014 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-9014 (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-9014 (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 i9014_ConfigMagicScan only tell I-9014 how to start magic scan,it will not start magic scan
	// We have to call i9014_StartMagicScan to start up the magic scan.
	// i9014_ConfigMagicScan(int slot,int chArr[],int gainArr[],int scanChCount, float sampleRate,int scanMode,int triggerSource,int triggerState, float* realSampleRate);
	i9014_ConfigMagicScan(slotIndex,chArr,gainArr,scanChCount, sampleRate, scanMode,triggerSource,triggerState, &realsampleRate);	

	printf("The Magic Scan Configurations of I-9014 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-9014 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 
	i9014_InstallMagicScanISR(slotIndex,ISRFUN,triggerLevel);
	
 	i9014_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=i9014_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); 
	  // 	}	   	
      
		if(realsampleRate <=100) 	
			printf("total %05d Int %010lu\r",totalScanned,IntCnt);
	    
	   // if(readFromFIFO>0)
	   // {
	   // 	totalScanned+=readFromFIFO;	
	   // }
	   
	    // End of demo test	
		if(totalScanned>=TargetCnt)
		{	    	
			printf("\nStop magic scan and FIFO data amount = %d  spend time %lu\n", totalScanned, GetTimeTicks_ms()-T1);
			i9014_UnInstallMagicScanISR(slotIndex);
			i9014_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;
	  slot=slotIndex;
	  Close_Slot(9);
	  Close_Slot(slotIndex);
		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)
{
	short ret;
	int i;
	int readCnt=0;

	IntCnt++;
	//rawData+totalScanned indicate the array pointer
	ret= i9014_ReadFIFO_InISR(slot,rawData + totalScanned, triggerLevel,&readCnt);	
	i9014_ClearInt(slot);
	//printf("readCnt=%d\t , ret=%d, \n",readCnt,ret);	
 
	if(ret!=0 || readCnt==MAX_FIFO )
	{
		//i9014_UnInstallMagicScanISR(slot);
		i9014_StopMagicScan(slot); 	     		
		return ;
	}
  
	if(readCnt>0)
 	{
 	    totalScanned+=readCnt; 

		if(totalScanned >=TargetCnt)
		{
			i9014_StopMagicScan(slot); 
			//i9014_UnInstallMagicScanISR(slot);    		
		}
 	}      	    				   
}

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++)
	{
		  i9014_CalibrateData(slotIndex, gainArr[i %scanChCount],rawData[i],&calibratedAI);
		  printf("i=%d: Arr[%d]=%5.4f\t",i,i%scanChCount,calibratedAI);			
	}
	printf("\n-----------------------------------\n");
}
