/** @file sample_apcie1532_counter_event.c
 
   This sample demonstartes how to use counter event in user mode.
   The thread is not necessary, it permits an easier management of events and sample stop.
 
   @par CREATION  
   @author Krauth Julien
   @date   08.01.09
   
   @par VERSION
   @verbatim
   $LastChangedRevision:$
   $LastChangedDate:$
   @endverbatim   
   
   @par LICENCE
   @verbatim
   Copyright (C) 2009  ADDI-DATA GmbH for the source code of this module.
        
   ADDI-DATA GmbH
   Airpark Business Center
   Airport Boulevard B210
   77836 Rheinmünster
   Germany
   Tel: +49(0)7229/1847-0
   Fax: +49(0)7229/1847-200
   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 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

   You shoud also 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 <sys/time.h>
#include <signal.h>
#include <errno.h>
#include <assert.h>
#include <pthread.h>

#include <apcie1532.h>
#include <apcie1532-events.h>

#include "findboards.h"
#include "input.h"

unsigned char stop;
unsigned char configured;

//------------------------------------------------------------------------------

/**@struct thread_arg_t
 * 
 * This structure is used to transmit some parameters to threads.  
 */
struct thread_arg_t 
{
	int threadnbr;	/**< This is the minor ID of the board */
	int fd;			/**< File descriptor of the board */ 
}; 

//------------------------------------------------------------------------------

/** this function look up for cards in the /proc/sys/apcie1532/ 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 apcie1532_find_cards(int ** cards)
{
	return apci_find_boards("apcie1532", cards);
}

//------------------------------------------------------------------------------

/** Exit callback function.
 *
 * This function is called on Ctrl+c key combination.
 * It set the stop flag status.
 */
static void v_ControlExit (int notused)
{
      stop = 0;
      printf("Sample abort.\n");
}

//------------------------------------------------------------------------------

void * fn_thread (void * arg)
{
	struct thread_arg_t *thread_args = (struct thread_arg_t *) arg;	
	printf("Counter with events\n");
	printf("CMD_APCIE1532_CounterReset\n");
	{
		if (ioctl (thread_args->fd,CMD_APCIE1532_CounterReset,index) != 0)
			perror("ioctl");
	}

	{
		struct
		{ 
			uint32_t ReloadValue;
			unsigned long DirectionSelection;
			unsigned long LevelSelection;
		} param;
		
		{			
			printf ("Enter the counter reload value:\n");
			param.ReloadValue = get_integer(1,65535);
			
			printf ("Enter the counter direction:\n");
			printf ("- 0: Count down.\n");
			printf ("- 1: Count up.\n");
			param.DirectionSelection = get_integer(0,1);
			
			printf ("Count on:\n");
			printf ("- 1: Count on falling edge.\n");
			printf ("- 2: Count on rising edge.\n");
			printf ("- 3: Count on both edges.\n");
			param.LevelSelection = get_integer(1,3);
			
			if (ioctl (thread_args->fd,CMD_APCIE1532_CounterInitAndStart,&param) != 0)
				perror("ioctl");
		}
		
		configured = 0;
		
		{
			uint32_t Value = 0;
			if (ioctl (thread_args->fd,CMD_APCIE1532_ReadCounterValue,&Value) != 0)
				perror("ioctl");
		}
		
		printf("Please generates events on counter (the first input channel)\n");		
		{
			printf("CMD_APCIE1532_EventEmpty\n");
			{   
				if (ioctl (thread_args->fd,CMD_APCIE1532_EventEmpty,NULL) != 0)
					perror("ioctl");
			}
			while(stop)
			{
				/* read a character from input */
				printf("CMD_APCIE1532_EventWait\n");
				{   
					apcie1532_event_t evt;
					if (ioctl (thread_args->fd,CMD_APCIE1532_EventWait, &evt) != 0)
						perror("ioctl");
						
					printf("source: %d param1: 0x%lX\n",evt.source, evt.param1);
					printf("\n");
				}
			}
		}
	}
	
	pthread_exit(NULL);
}


//------------------------------------------------------------------------------

int main(int argc, char** argv)
{
	int ret = 0;
	int i = 0;
	int *fd;
	int nbr_boards = 0;
	pthread_t *thread = NULL;
	struct thread_arg_t *thread_args = NULL;
	
	stop = 1;
	configured = 1;
	
	/* Search for APCIE-1532 boards */
	if ((nbr_boards = apcie1532_find_cards(&fd)) == 0) 
	{
		printf("No APCIE-1532 found\n");
		exit(EXIT_FAILURE);
	}
	
	thread = malloc (sizeof (pthread_t) * nbr_boards);	
	if (thread == NULL) 
	{
		printf("Can't allocate memory for thread\n");
		exit(EXIT_FAILURE);
	}
	
	thread_args = malloc (sizeof (struct thread_arg_t) * nbr_boards);	
	if (thread_args == NULL) 
	{
		printf("Can't allocate memory for thread_args\n");
		exit(EXIT_FAILURE);
	}	
	
	/* Set the v_ControlExit callback function on Ctrl+c key combination.
	 * Once Ctrl+C are pressed, the v_ControlExit function is called to end the 
	 * sample.
	 */
	signal (SIGINT, v_ControlExit);	
	
    for (i=0; i<nbr_boards; i++) 
    {
		
		thread_args[i].threadnbr = i;	/**< This is the minor ID of the board */
		thread_args[i].fd = fd[i];		/**< File descriptor of the board */
		
		/* Create a thread for each board */
		if ((ret = pthread_create (&thread[i], NULL, fn_thread, &thread_args[i])) != 0) 
		{
		   printf("%d : %s", i, strerror(ret));
		   exit(EXIT_FAILURE);
		}
		printf ("Create and start thread for board %d\n", i);
    }
    
	/* Wait Ctrl+c key combination */
	printf ("TO STOP THE SAMPLE PRESS CTRL+C\n");
	{
		uint32_t Value = 0;
		while (stop) 
		{
			if (!configured)
			{
				for (i=0; i<nbr_boards; i++)
				{
					if (ioctl (fd[i],CMD_APCIE1532_ReadCounterValue,&Value) != 0)
						perror("ioctl");
						
					printf ("Counter board %d = %i ", i, Value);
				}
				printf ("\r");
			}
		}
		sleep(1);
	}

	/* Stop threads */
    for (i=0; i<nbr_boards; i++) 
    {
		pthread_cancel (thread[i]);
		
		printf("CMD_APCIE1532_CounterReset\n");		
		if (ioctl (thread_args[i].fd, CMD_APCIE1532_CounterReset, NULL) != 0)
			perror("ioctl");
    }

    free (thread);
    free (thread_args);
	
	return 0;
}
