
#include <string.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <fcntl.h>

#include <apci3600.h>
#include "findboards.h"

//------------------------------------------------------------------------------
/** Filter the "." and ".." entries in the struct dirent ** area set up by the scandir() function (utility function).*/
int get_real_dir_entry (const struct dirent * ent)
{
        if (! strcmp(ent->d_name,"."))
                return 0;
        if (! strcmp(ent->d_name,".."))
                return 0;
                                
        return 1;
}

//--------------------------------------------------------------------------------
/* try to open a device file of the form /dev/apci3600/0 from board index */
static int open_dev_file(int index, int minor, int * fd)
{
	char name[101];
	memset(name,0,sizeof(name));
	snprintf(name,sizeof(name)-1,"/dev/apci3600/%i", (index*(APCI3600_DEV_MINOR_MAX-1)) + minor);

	if ( ( *fd = open(name, O_RDWR)) == -1 )
	{
		perror(name);
		exit(1);
	}
	{
		struct stat file_stat;
		if ( fstat(*fd,&file_stat) )
		{
			perror("fstat");
			exit(1);
		}			
		if (!S_ISCHR(file_stat.st_mode)) 
		{
			/* should never happen !*/
			printf("file %s is not a character device\n",name);
			exit(1);
		}
		printf("%s, major:%d minor:%d \n",name, major(file_stat.st_rdev),minor(file_stat.st_rdev));
	}
	return 0;
} 

//--------------------------------------------------------------------------------
/** this function look up for cards in the /dev/apci3600 directory 
* @param cards A pointer to the card area to fill
* @return The number of cards detected (may be zero if nor cards found).
*/
int apci3600_find_boards(struct apci3600_card_t *** cards_array)
{
    struct dirent **eps;
    int cnt = 0; // number of card found
    char APCI_SPECIAL_FILE_DIR[255]="/dev/apci3600/";
	int i;

	/* scan directory for card entry */
	if ( (cnt = scandir (APCI_SPECIAL_FILE_DIR, &eps, get_real_dir_entry , alphasort)) == -1 )
	{
		perror("scandir");
		return 0;
	}	
	
	if (cnt == 0) return 0;
	
	printf("found %i device entries in %s\n",cnt,APCI_SPECIAL_FILE_DIR);
	
	/* cnt returns how many entry in the directory there is  - the actual board number is cnt / (APCI3600_DEV_MINOR_MAX-1) */
	cnt = cnt / (APCI3600_DEV_MINOR_MAX-1);
	
	printf("it makes %i board\n",cnt);
	
	/* allocate cards area */
	if ( ! ( (*cards_array) = malloc( cnt * sizeof(struct apci3600_card_t) ) ) )
	{
		perror("malloc");
		free(eps);
		return 0;
	}
	for( i=0; i<cnt; i++ )
	{
		open_dev_file(i, APCI3600_DEV_MINOR_BASE, &( (*cards_array)[i]->base) );
		open_dev_file(i, APCI3600_DEV_MINOR_ANALOG_OUTPUT_0 , &( (*cards_array)[i]->analog_output_0 ) );
		open_dev_file(i, APCI3600_DEV_MINOR_ANALOG_OUTPUT_1 , &( (*cards_array)[i]->analog_output_1 ) );
		open_dev_file(i, APCI3600_DEV_MINOR_ANALOG_INPUT_0 , &( (*cards_array)[i]->analog_input_0 ) );
		open_dev_file(i, APCI3600_DEV_MINOR_ANALOG_INPUT_1 , &( (*cards_array)[i]->analog_input_1 ) );
		open_dev_file(i, APCI3600_DEV_MINOR_ANALOG_INPUT_2 , &( (*cards_array)[i]->analog_input_2 ) );
		open_dev_file(i, APCI3600_DEV_MINOR_ANALOG_INPUT_3 , &( (*cards_array)[i]->analog_input_3 ) );
		open_dev_file(i, APCI3600_DEV_MINOR_CHRONO_0 , &( (*cards_array)[i]->chrono_0 ) );
		open_dev_file(i, APCI3600_DEV_MINOR_CHRONO_1 , &( (*cards_array)[i]->chrono_1 ) );
		open_dev_file(i, APCI3600_DEV_MINOR_CHRONO_2 , &( (*cards_array)[i]->chrono_2 ) );
		open_dev_file(i, APCI3600_DEV_MINOR_CHRONO_3 , &( (*cards_array)[i]->chrono_3 ) );
		open_dev_file(i, APCI3600_DEV_MINOR_DIGITAL_INPUT , &( (*cards_array)[i]->digital_input ) );
		open_dev_file(i, APCI3600_DEV_MINOR_DIGITAL_OUTPUT , &( (*cards_array)[i]->digital_output ) );
		open_dev_file(i, APCI3600_DEV_MINOR_EXTERNAL_TRIGGER , &( (*cards_array)[i]->external_trigger ) );
		
	}
		
	return cnt;	
}
