/** @file sample_apcie2200_Timer_event.c
 
   This sample demonstartes how to use Timer 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   28.01.2010
   
   @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 Rheinmuenster
   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 <apcie2200.h>
#include <apcie2200-events.h>

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

unsigned char ucStopFlag;
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 */ 
}; 

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

//------------------------------------------------------------------------------
void * fn_thread (void * arg)
{
	struct thread_arg_t *thread_args = (struct thread_arg_t *) arg;	
	printf("Timer with events\n");

	{
		struct
		{
			uint32_t ressourceType;
			uint32_t mode;
			uint32_t timeBaseUnit;
			uint32_t timeBaseValue;
			uint32_t irq;
		} param;
		
		{			
			param.ressourceType = 1;	/* Timer */
			param.mode = 2;				/* Only mode 2 is available at this time */
			param.irq = 1;				/* Enable the interrupt */
			
			printf ("Enter the timer reload value:\n");
			param.timeBaseValue = get_integer (1,0xFFFF);

			printf ("Set the reload value unit:\n");
			printf ("- 1: us.\n");
			printf ("- 2: ms.\n");
			printf ("- 3: s.\n");
			param.timeBaseUnit = get_integer (1,3);

			if (ioctl (thread_args->fd, CMD_APCIE2200_TimerWatchdogInitAndStart, &param) != 0)
			{
				perror("ioctl");
				exit (1);
			}
		}
		
		configured = 0;
		
		{
			printf("CMD_APCIE2200_EventEmpty\n");
			{   
				if (ioctl (thread_args->fd,CMD_APCIE2200_EventEmpty,NULL) != 0)
					perror("ioctl");
			}
                        while(ucStopFlag == 0)
			{
				{   
					apcie2200_event_t evt;
					if (ioctl (thread_args->fd,CMD_APCIE2200_EventWait, &evt) != 0)
						perror("ioctl");
						
					switch (evt.source)
					{
						case 0:
							printf("source: Digital inputs.\n");
						break;

						case 1:
							printf("source: Timer.\n");
						break;

						case 2:
							printf("source: Watchdog.\n");
						break;

						default:
							printf("source: Unknown.\n");
						break;
					}

					printf("\n");
				}
			}
		}
	}
	
	pthread_exit(NULL);
}

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

int main(int argc, char** argv)
{
	int ret = 0;
	int i = 0;
	int nbr_boards = 1; // only 1 Board is tested
	pthread_t *thread = NULL;
	struct thread_arg_t *thread_args = NULL;
	
	int apcie2200_card_fd;

	if (argc < 2 )
	{
            printf("Not enough arguments.\n");
            printf("Usage: %s /dev/apcie2200_[0..15]\n", argv[0]);
            exit(1);
	}

	if ( ( apcie2200_card_fd = open(argv[1], O_RDWR)) == -1 )
	{
		perror("open");
		exit(1);
	}

	{
		struct stat file_stat;
		if ( fstat(apcie2200_card_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",argv[1]);
			printf("failed");
			exit(1);
		}
		printf("%s, major:%d minor:%d \n",argv[1], major(file_stat.st_rdev),minor(file_stat.st_rdev));
	}

	printf("\n+++++++++++++++++++++++++++++++++++++\nrunning test on device %s  \n+++++++++++++++++++++++++++++++++++++\n\n\n",argv[1]);


        ucStopFlag = 0;
	configured = 1;

	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 = apcie2200_card_fd;	/**< 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");
	{
		struct
		{
			uint32_t ressourceType;
			uint32_t value;
		} param;

                while (ucStopFlag == 0)
		{
			if (!configured)
			{
				param.ressourceType = 1;

				for (i=0; i<nbr_boards; i++)
				{
					if (ioctl (thread_args->fd, CMD_APCIE2200_TimerWatchdogRead, &param) != 0)
						perror("ioctl");
						
					printf ("Timer board %d = %i ", i, param.value);
				}
				printf ("\r");
			}
		}
		sleep(1);
	}

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

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