/** @file sample_apci3701.c
*
* @author Sylvain Nahas
* @Jordan Rose: add a lot of samples
*
* This software 
* - scans the /proc/sys/apci3701/ directory 
* - run a serie of test on each detected boards
*/

/** @par LICENCE
* @verbatim
 Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code and the documentation.
        
        ADDI-DATA GmbH
        Dieselstrasse 3 
        D-77833 Ottersweier
        Tel: +19(0)7223/9493-0
        Fax: +49(0)7223/9493-92
        http://www.addi-data-com
        info@addi-data.com

    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 of the License, 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 shoud find the complete GPL in the COPYING file accompanying 
    this source code. 
* @endverbatim
*/


#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <dirent.h>
#include <string.h>
#include <sys/sysmacros.h> /* major() minor() */

#include <apci3701.h>
#include <apci3701-events.h>
#include "findboards.h"

int scenario_1(int fd);
int scenario_2(int fd);
int scenario_3(int fd);
int scenario_4(int fd);

int choose_and_do_scenario( int fd );

double apci3701_convert_raw_data(uint32_t val, int len);

int init_transducer( int fd, int channel_index, int transducer_index );
int test_secondary_line_open_circuit ( int fd, int channel_index, int transducer_type );
int test_secondary_line_short_circuit ( int fd, int channel_index, int transducer_type);

int main(int argc, char** argv)
{
	int * apci3701_card_fd;
	int apci3701_card_number = 0;
	apci3701_card_number = apci_find_boards("apci3701",&apci3701_card_fd);
	{
		int i;
		for (i=0;i< apci3701_card_number; i++)
		{
			printf("Choose the scenario for card %d \n", i );
			choose_and_do_scenario(apci3701_card_fd[i]);
		}
	}

	return 0;
}
//--------------------------------------------------------------------------------
int choose_and_do_scenario( int fd )
{
	int choice = 0;
	printf("Scenario of test available : \n");
	printf("1 : Test the secondary line of all the channels \n");
	printf("2 : Test the primary line short circuit with interruption \n");
	printf("3 : Test the primary line open and short circuit without interruption \n");
	printf("4 : Read all the analog inputs \n");
	printf("Your choice : \n");

	scanf("%d", &choice);

	switch(choice)
	{
		case 1:
			printf("Scenario 1 chosen \n");
			scenario_1(fd);
			break;
		case 2:
			printf("Scenario 2 chosen \n");
			scenario_2(fd);
			break;
		case 3:
			printf("Scenario 3 chosen \n");
			scenario_3(fd);
			break;
		case 4:
			printf("Scenario 4 choosen \n");
			scenario_4(fd);
			break;
		default:
			printf("No scenario chosen, exit \n");
	}

	return 0;
}


/*
 * Enables to do the initialization of a channel
 * channel_index: the index of the channel, from 0 to 15
 * transducer_index: the index of the channel in the IO MAPPING. For example, 5 for solartron AX1
 */
int init_transducer( int fd, int channel_index, int transducer_index )
{
	uint32_t arg[2] = {0};

	printf("Channel %d , transducer index : %d \n", channel_index, transducer_index);

	arg[0] = channel_index;
	arg[1] = transducer_index;

	if ( (ioctl(fd,CMD_apci3701_initialize_transducer,arg)) != 0 )
	{
		printf("CMD_apci3701_initialize_transducer failed\n");
		exit (EXIT_FAILURE);
		return -1;
	}

	return 0;
}

/*
 * Enables to do the test of the secondary line open circuit on a channel
 * channel_index : the index of the channel, from 0 to 15
 * transducer_type: the type of the transducer. It is the index in the addi data database. For example, 24 for solartron AX1. See set3701
 */
int test_secondary_line_open_circuit ( int fd, int channel_index, int transducer_type )
{
	int ret = 0;
	uint32_t arg[2] = {0};

	arg[0] = channel_index;
	arg[1] = transducer_type;

	if ( (ret = ioctl(fd,CMD_apci3701_test_channel_secondary_line_open_circuit,arg)) != 0 )
	{
		printf("CMD_apci3701_test_channel_secondary_line_open_circuit failed\n");
		printf("Ret value : %d \n", ret );
		exit (EXIT_FAILURE);
		return -1;
	}

	if ( arg[0] == 1 )
	{
		printf("Open circuit detected on channel %d \n", channel_index);
	}
	if ( arg[0] == 0 )
	{
		printf("No open circuit on channel %d \n", channel_index);
	}

	return 0;
}

/*
 * Enables to do the test of the secondary line open circuit on a channel
 * channel_index : the index of the channel, from 0 to 15
 * transducer_type: the type of the transducer. It is the index in the addi data database. For example, 24 for solartron AX1. See set3701
 */
int test_secondary_line_short_circuit ( int fd, int channel_index, int transducer_type)
{
	int ret = 0;
	uint32_t arg[2] = {0};

	arg[0] = channel_index;
	arg[1] = transducer_type;

	if ( (ret = ioctl(fd,CMD_apci3701_test_channel_secondary_line_short_circuit,arg)) != 0 )
	{
		printf("CMD_apci3701_test_channel_secondary_line_short_circuit failed\n");
		printf("Ret value : %d \n", ret );
		exit (EXIT_FAILURE);
		return -1;
	}

	if ( arg[0] == 1 )
	{
		printf("Short circuit detected on channel %d \n", channel_index);
	}
	if ( arg[0] == 0 )
	{
		printf("No short circuit on channel %d \n", channel_index);
	}

	return 0;
}

// A scenario that enables to test the secondary line of all the channel
// For the moment, this scenario is assuming that you only use one transducer that is a solartron AX1
int scenario_1(int fd)
{
	/*
	 * Initialize all the channels
	 */
	printf("***************************************************************************************************\n");
	printf("Channel initialization \n");
	int i = 0;
	for ( i = 0 ; i < 16; i++ )
	{
		init_transducer(fd, i, 5);
	}

	/*
	 * Test the open circuit
	 */
	printf("***************************************************************************************************\n");
	printf("Secondary open circuit test \n");
	for ( i = 0; i < 16; i++ )
	{
		test_secondary_line_open_circuit(fd, i, 24);
	}

	/*
	 * Test the short circuit
	 */
	printf("***************************************************************************************************\n");
	printf("Secondary short circuit test \n");
	for ( i = 0; i < 16; i++ )
	{
		test_secondary_line_short_circuit(fd, i, 24);
	}

	return 0;
}

// A scenario that enables to test the primary interruption and rearm when there is a short circuit on the primary line
int scenario_2(int fd)
{
	int foo = 0;

	printf("Enable the short circuit interruption for the primary line \n");

	if ( (ioctl(fd,CMD_apci3701_enable_disable_primary_short_circuit_interrupt,1)) != 0 )
	{
		printf("CMD_apci3701_enable_disable_primary_short_circuit_interrupt failed\n");
		close(fd);
		exit(EXIT_FAILURE);
	}

	/* Empty the event buffer */
	printf("Empty the event buffer \n");
	{
		if ( ioctl (fd,CMD_apci3701_EventEmpty,NULL) != 0 )
		{
			printf("Error CMD_apci3701_EventEmpty \n");
			close(fd);
			exit(EXIT_FAILURE);
		}
	}

	printf("Now wait until a short circuit ... \n");
	{
		apci3701_event_t evt;
		if ( ioctl (fd,CMD_apci3701_EventWait, &evt) != 0 )
		{
			printf("Error CMD_apci3701_EventWait \n");
			close(fd);
			exit(EXIT_FAILURE);
		}
		printf("source: %d\n",evt.source);
	}

	printf("Short circuit detected, enter a number to rearm the primary line \n");
	scanf("%d", &foo );

	printf("Rearming the primary line short circuit \n");

	if ( (ioctl(fd,CMD_apci3701_ream_primary_open_short_circuit_test,NULL)) != 0 )
	{
		printf("CMD_apci3701_ream_primary_open_short_circuit_test failed\n");
		close(fd);
		exit(EXIT_FAILURE);
	}

	printf("Disable the short circuit interruption for the primary line \n");

	if ( (ioctl(fd,CMD_apci3701_enable_disable_primary_short_circuit_interrupt,0)) != 0 )
	{
		printf("CMD_apci3701_enable_disable_primary_short_circuit_interrupt failed\n");
		close(fd);
		exit(EXIT_FAILURE);
	}

	return 0;
}

// A scenario used to test the primary line : short and open circuit
// If a short circuit is detected, you will have to rearm the primary line
int scenario_3(int fd)
{
	uint32_t arg[1] = {0};
	int choice = 0;
	int ret=0;

	printf("Enable the open circuit test for the primary line \n");

	if ( (ioctl(fd,CMD_apci3701_enable_disable_primary_open_circuit_test,1)) != 0 )
	{
		printf("CMD_apci3701_enable_disable_primary_open_circuit_test failed\n");
		close(fd);
		exit(EXIT_FAILURE);
	}

	printf("Enter a number to continue \n");
	scanf("%d", &choice);

	printf("Test the status \n");
	if ( (ret = ioctl(fd,CMD_apci3701_test_primary_line,arg)) != 0 )
	{
		printf("REt :%d \n", ret);
		printf("CMD_apci3701_enable_disable_primary_open_circuit_test failed\n");
		close(fd);
		exit(EXIT_FAILURE);
	}

	if ( arg[0] == 0 )
	{
		printf("Nothing detected \n");
	}
	if ( arg[0] == 1 )
	{
		printf("Open circuit detected \n");
	}
	if ( arg[0] == 2 )
	{
		printf("Short circuit detected \n");
	}
	if ( arg[0] == 3 )
	{
		printf("Open and short circuit detected detected \n");
	}

	if ( arg[0] == 2 || arg[0] == 3 )
	{
		printf("Do you want to rearm the primary line diagnostic ? \n");
		printf("0: No, 1: Yes \n");
		scanf("%d", &choice );

		if ( choice == 1 )
		{
			printf("Rearming the primary line .... \n");
			if ( (ioctl(fd,CMD_apci3701_ream_primary_open_short_circuit_test,NULL)) != 0 )
			{
				printf("CMD_apci3701_ream_primary_open_short_circuit_test failed\n");
				close(fd);
				exit(EXIT_FAILURE);
			}
		}

	}

	printf("Disable the open circuit test for the primary line \n");

	if ( (ioctl(fd,CMD_apci3701_enable_disable_primary_open_circuit_test,0)) != 0 )
	{
		printf("CMD_apci3701_enable_disable_primary_open_circuit_test failed\n");
		close(fd);
		exit(EXIT_FAILURE);
	}
	return 0;
}

int scenario_4(int fd)
{
	uint32_t arg[1] = {0};
	int i = 0;
	int ret = 0;

	printf("Reading the 16 channels thanks to the function read 1 analog input \n");

	for ( i = 0 ; i < 16; i++ )
	{
		printf("Value of channel %d : \t", i);
		arg[0] = i;
		if ( ( ret = ioctl(fd, CMD_apci3701_read_one_analog_input, arg)) != 0 )
		{
			printf("Error  : CMD_apci3701_read_one_analog_input \n");
			close(fd);
			exit(EXIT_FAILURE);
		}
		printf("%x \t", arg[0]);

		printf("%f \n", apci3701_convert_raw_data(arg[0], 1));

	}

	return 0;
}

/**
@param val: raw value to convert
@param len: course of the transducer in millimeter  (example 2 for a +/- 2 mm)

@return the converted value in micrometers units
*/
double apci3701_convert_raw_data(uint32_t val, int len)
{
   double sign = 0;
   double metric = 0;
   /* raw value is 16 bit wide, D15 is the sign bit */
   if ((val & 0x8000) == 0x8000)
	   sign = -1;
   else
	   sign = 1;

   /* eliminate the sign bit */
   val = val & 0x7FFF;

   metric = val;
   /* 32767.0 : maximal value on 15 bits (0x7FFF) */
   metric = sign * len * (metric / 32767.0);
   metric = metric * 1000.0; // result in micrometers

   return metric;
}
