/* Test with I-9057P AO Module and I-9053P AI Module at Slot 8 and 6 of low pass filter feature
   
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software Foundation,
   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
    
   File level history (record changes for this file here.)

   v1.0 2020.4.27 by Golden
  
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/time.h>
#include <termios.h> 
#include <signal.h>
#include <sched.h>
#include "msw.h"
	
#define I9053_SLOT SLOT6
#define I9057_SLOT SLOT8

static int Wave_idx=0;
int Counting_Flag=0;
int Non_Switch_Flag=0;
unsigned int pre_status=0;
long pre_t1_1 = 0, pre_t1_2 = 0;
int idx=0;
int limit_idx=0;
unsigned int idx_log=0;
unsigned long Cnt_log[10000];
unsigned int status_log[10000];
unsigned long WaitCnt[10];
unsigned long HiCnt[10];
unsigned long LoCnt[10];
unsigned long UnknowCnt[10];

void init_sigaction(void);
void init_time();
void stop_time();
void TimerISR(void);
void Test_LPF(int LPF_val);

struct itimerval mytimer;

void DelayUs(unsigned long usec)
{
        struct timeval t1,t2;
        gettimeofday( &t1, NULL );
        while(1)
        {
                gettimeofday( &t2, NULL );
                if(((t2.tv_sec-t1.tv_sec)*1000000+(t2.tv_usec-t1.tv_usec))>=usec)
                        break;
        }
}

void TimerISR()
{
	unsigned short Standby = 0x00ff;
	unsigned short High = 0x3333;
	unsigned short Low = 0xcccc;
	unsigned int status = 0;
        struct timeval t1,t2;

	
        //write(STDERR_FILENO, msg, len);
       	gettimeofday( &t1, NULL );
	idx++;
	status = ~DI_16(I9053_SLOT) & 0xffff;

	if(Counting_Flag == 1)
	{
		idx_log++;
		//printf("%s ... Counting_Flag ... status = 0x%x\n", __FUNCTION__, status);

		if((unsigned short)(status&0xffff)==0x00ff)
		{
			//printf("%s ... Counting_Flag ... status = 0xffff ... WaitCnt++\n", __FUNCTION__);
			WaitCnt[Wave_idx]++;
			//Cnt_log[idx_log]=WaitCnt[Wave_idx];
		}
		else if((unsigned short)(status&0xffff)==0x3333)
		{
			//printf("%s ... Counting_Flag ... status = 0x3333 ... HiCnt++\n", __FUNCTION__);
			HiCnt[Wave_idx]++;
			//Cnt_log[idx_log]=HiCnt[Wave_idx];
		}
		else if((unsigned short)(status&0xffff)==0xcccc)
		{
			LoCnt[Wave_idx]++;
			//printf("%s ... Counting_Flag ... status = 0xcccc ... LoCnt++\n", __FUNCTION__);
			//Cnt_log[idx_log]=LoCnt[Wave_idx];
		}
		else
		{
			//printf("%s ... Counting_Flag ... status = unknown\n", __FUNCTION__);
			UnknowCnt[Wave_idx]++;
			//Cnt_log[idx_log]=UnknowCnt[Wave_idx];
		}
		//status_log[idx_log++]=status;
	}
        
	if(Non_Switch_Flag == 1)
	{
		if(idx >= limit_idx)
		{
			if(pre_status == High)
			{
				DO_16(I9057_SLOT, Low);
				pre_status = Low;
#if 0
				//check the time of changing DO(High to Low)
				gettimeofday( &t2, NULL );
				printf("XXX %s ... DO change(idx = %d, High to Low) ... diff(t1 - pre_t1_1) = %d ms...t2(%ld) - t1(%ld) = %d us\n", __FUNCTION__, idx, ((1000000 * t1.tv_sec + t1.tv_usec) - pre_t1_1)/1000, (1000000 * t2.tv_sec + t2.tv_usec), (1000000 * t1.tv_sec + t1.tv_usec), (1000000 * (t2.tv_sec-t1.tv_sec)+ t2.tv_usec-t1.tv_usec));
				pre_t1_1 = (1000000 * t1.tv_sec + t1.tv_usec);
#endif
				
			}
			else if(pre_status == Low)
			{
				DO_16(I9057_SLOT, High);
				pre_status = High;
#if 0
				//check the time of changing DO(Low to High)
				gettimeofday( &t2, NULL );
				printf("XXX %s ... DO change(idx = %d, Low to High) ... diff(t1 - pre_t1_1) = %d ms ...t2(%ld) - t1(%ld) = %d us\n", __FUNCTION__, idx, ((1000000 * t1.tv_sec + t1.tv_usec) - pre_t1_1)/1000, (1000000 * t2.tv_sec + t2.tv_usec), (1000000 * t1.tv_sec + t1.tv_usec), (1000000 * (t2.tv_sec-t1.tv_sec)+ t2.tv_usec-t1.tv_usec));
				pre_t1_1 = (1000000 * t1.tv_sec + t1.tv_usec);
#endif
			}

                        Wave_idx+=1;
			idx = 0;

			if(Wave_idx == 10)
			{
				Counting_Flag=0;
				Non_Switch_Flag=0;
				stop_time();	//disable timer handler
			}
			
		}
	}
}

void Test_LPF(int LPF_val)
{
	int i=0;
	unsigned long hi_max=0;
	unsigned long hi_min=100000;
	unsigned long lo_max=0;
	unsigned long lo_min=100000;
	int Mag=10;

        //Check DI status
	idx=0;
	limit_idx=(LPF_val * Mag * 2 / 2) * 0.8;
	//printf("Mag = %d, limit_idx = %d\n", Mag, limit_idx);
	Wave_idx=0;
	hi_max=0;
	hi_min=100000;
	lo_max=0;
	lo_min=100000;
	DO_16(I9057_SLOT, 0xff);
        DelayUs(2000000);

	for(i=0;i<10;i++)
	{
		WaitCnt[i]=0;
		HiCnt[i]=0;
		LoCnt[i]=0;
		UnknowCnt[i]=0;
	}

	pre_status=0x3333;
	Counting_Flag=1;
	Non_Switch_Flag=1;

	DO_16(I9057_SLOT, 0x3333);//Start single

        while(Wave_idx<10)
	{
                DelayUs(100000);
	};

        for(i=1;i<10;i++)
	{
		if(i%2==1)
		{
			if(HiCnt[i]>hi_max)
			{
				hi_max=HiCnt[i];
			}

			if(HiCnt[i]<hi_min)
			{
				hi_min=HiCnt[i];
			}
		}
		else
		{
			if(LoCnt[i]>lo_max)
			{
				lo_max=LoCnt[i];
			}

			if(LoCnt[i]<lo_min)
			{
				lo_min=LoCnt[i];
			}
		}
	}

	printf("HI[%4lu,%4lu]  LO[%4lu,%4lu] ... ",hi_max,hi_min,lo_max,lo_min);
	//printf("idx_log = %d, LPF_val = %d, Mag = %d, (LPF_val+1)*Mag*10 = %d, (LPF_val-1)*Mag*10 = %d\n", idx_log, LPF_val, Mag, (LPF_val+1)*Mag*10, (LPF_val-1)*Mag*10);
	if(hi_max!=0 || hi_min!=0 || lo_max!=0 || lo_min!=0){
		printf("Test Error");
	}
	else
	{
		printf("Test OK");
	}

	printf("\n");
        DO_16(I9057_SLOT, 0x00);
        DelayUs(2000000);
}


void init_sigaction(void)
{
        struct sigaction tact;
        tact.sa_handler = TimerISR;
        tact.sa_flags = 0;
        sigemptyset(&tact.sa_mask);
        sigaction(SIGALRM, &tact, NULL);
}

void init_time()
{
        mytimer.it_value.tv_sec = 2;
        mytimer.it_value.tv_usec = 0;
        mytimer.it_interval.tv_sec = 0;
        mytimer.it_interval.tv_usec = 120;	//100 ~ 120us
        setitimer(ITIMER_REAL, &mytimer, NULL);
}

void stop_time()
{
        mytimer.it_value.tv_sec = 0;
        mytimer.it_value.tv_usec = 0;
        mytimer.it_interval.tv_sec = 0;
        mytimer.it_interval.tv_usec = 0;
        setitimer(ITIMER_REAL, &mytimer, NULL);
}

int main()
{
	int RES_time_ms = 655;	//range 1ms ~ 655ms
	int wRetVal, LPF_jumper = 0;

	wRetVal = Open_Slot(I9053_SLOT);
	if (wRetVal > 0) {
		printf("open Slot failed!\n");
		return (-1);
	}

	wRetVal = Open_Slot(I9057_SLOT);
	if (wRetVal > 0) {
		printf("open Slot failed!\n");
		return (-1);
	}

	LPF_jumper = ReadLPFSwitch(I9053_SLOT);

	if(LPF_jumper != 0xfe)
	{
		printf("LPF's jumper isn't CPU!\n");
		return (-1);
	}

	wRetVal = SetLPF(I9053_SLOT, RES_time_ms);
	
	if (wRetVal > 0) {
		printf("Set LPF fail!\n");
		return (wRetVal);
	}
	else
	{
		printf("i-9053P LPF = %d ms\n", GetLPF(I9053_SLOT));
		//printf("LPF = 0x%x = %d ms\n", (inb(I9053_SLOT, 6) << 8) | (inb(I9053_SLOT, 5)), ((inb(I9053_SLOT, 6) << 8) | (inb(I9053_SLOT, 5))) / 100);
	}

        init_sigaction();
        init_time();

	Test_LPF(RES_time_ms);

	Close_Slot(I9053_SLOT);
	Close_Slot(I9057_SLOT);
	return 0;
}
