/*
 ******************************************************************************
 *  Copyright 1998 DeltaLink bv. All Rights Reserved.
 ******************************************************************************
 *
 * File: sapi_fl.c
 *
 * This module contains the communication with FactoryLink.
 *
 */
#ifdef WIN32
#pragma warning( disable : 4121 )

#define NOMSG             /* typedef MSG and associated routines */
#define _OLE2_H_          /* no ole */

#include  <windows.h>
#include  <process.h>

#undef ERROR

#endif


#include  <stdlib.h>
#include  <string.h>
#include  <stdio.h>
#include  <stdarg.h>


#include  <flib.h>						 /* FactoryLink definitions */
#include  <fl_utils.h>
#include  <g_utils.h>

#pragma warning( disable : 4214 )
#include  <imx.h>              /* Mailbox Communication Interface definitions */
#include  <imx_mt.h>           /* Mailbox Communication Interface definitions */
#include  <imx_fmt.h>          /* Mailbox Communication Interface definitions */
#pragma warning( default : 4214 )
#include  <modules.h>          /* Mailbox Communication Interface definitions */

#include  <protocol.h>				 /*  DeltaLink SAPI definitions */
#pragma warning( disable : 4115 )
#include  <sapi_s7.h>					 /*  Siemens SAPI definitions   */
#pragma warning( default : 4115 )
#include  <sapi.h>						 /*  DeltaLink SAPI definitions */

#include  "..\..\..\version.h"					 /*  DeltaLink SAPI definitions */

/* function prototypes */

int fl_main( void *);

/*
 * Task global variables
 */
TASK_ID       *Task_fl;                   /* */
TASK_ID       Task_win;                   /* */
//TASK_ID       Callback;                   /* Callback task identification */

HINSTANCE hLib = NULL;                    //crahs support

VFD						*Vfd;
int						Nr_vfd;

extern id_t   Signal_Task_id;

FLMSG           Imx_buf;                    /* buffer for receiving with IMX */
FLMSG           Sapi_buf;                   /* buffer for receiving SAPI events */

DEVICE				**Device;										/* array of defined devices */
ushort				Nr_devices;

IMXDS					**Ds;												/* array of all datasets defined */
ushort				Nr_ds;											/* total number of datasets */

XLATOR				*Decoder;										/* array of all decoders defined */
ushort				Nr_decoders;								/* total number of decoders */

/*
 * The following header gives the control codes required for
 * a READ to a SIEMENS S5
 */
H1_HDR _H1_read = {
                   'S', '7',          /* system identifier */
                    0x10,             /* header length */

                    H1_OPCODE_ID,     /* OP code id */
                    H1_OPCODE_LEN,    /* OP code length */
                    H1_READ_REQUEST,  /* OP code */

                    H1_ORG_ID,        /* ORG block id */
                    H1_ORG_LEN,       /* ORG BL length */
                    0x00,             /* ORG type */
                    0x00,             /* DB number */
                    0x0000,           /* Start address of data */
                    0x0000,           /* Length of data */

                    0xFF, 0x02        /* Empty Block (if 0xFF) of 2 characters */
                  };
/*
 * The following header gives the control codes required for
 * a WRITE to a SIEMENS S5
 */
H1_HDR _H1_write = {
                     'S', '7',        /* system identifier */
                     0x10,            /* header length */

                     H1_OPCODE_ID,    /* OP code id */
                     H1_OPCODE_LEN,   /* OP code length */
                     H1_WRITE_REQUEST,/* OP code */

                     H1_ORG_ID,       /* ORG block id */
                     H1_ORG_LEN,      /* ORG BL length */
                     0x00,            /* ORG type */
                     0x00,            /* DB number */
                     0x0000,          /* Start address of data */
                     0x0000,          /* Length of data */

                     0xFF, 0x02       /* Empty Block (if 0xFF) of 2 characters */
                   };

H1_HDR _H1_ack =  {
                     'S', '7',        /* system identifier */
                     0x10,            /* header length */

                     H1_OPCODE_ID,    /* OP code id */
                     H1_OPCODE_LEN,   /* OP code length */
                     H1_WRITE_ACK,    /* OP code */

                     H1_ACK_ID,       /* ACK block id */
                     H1_ACK_LEN,      /* ACK BL length */
                     0x00,            /* Error */

                     0xFF, 0x07,      /* Empty Block (if 0xFF) of 2 characters */
										 0x00,
										 0x0000,
										 0x0000
                   };

char                fnc_desc[ 3 ][ 10 ] = { "Read", "Write", "Recv"};


/*-----------------------------------------------------------------------------
 * FUNCTION: int  main(int argc, char *argv[])
 *
 * PURPOSE: Task main function
 -----------------------------------------------------------------------------*/
#pragma warning(disable:4100)
int fl_main( void *dummy)
{
  int ret;
  char xl_msg[255] = "";


  /* initialize first the task structure */

  strcpy( Task_win.name, "SAPI_S7");
  strcpy( Task_win.desc, "Sapi S7 Protocol Driver");

  Task_win.dl_id    = SAPI_S7;
  Task_win.version  = ( (rmj << 8) & 0xFF00) | ( rmm & 0x00FF);

	/* initialize this task */

  if( ( ret = dl_init_task( &Task_win )) != GOOD)
	{
    if( ret == DLE_DEMO_INIT)
		{
      //fl_xlate_init( Task_win.name, NULL, 0);
      /* task already started in demo mode */
      //fl_status( &Task_win, "DEMO_MODE", FLS_INACTIVE);
      #ifndef _DEBUG
      //dl_exit_task( &Task_win, 1); //exit to OS
      #endif
		}
    #ifndef _DEBUG
		else
			exit( 1);
    #endif
  }

	/* Set up for message translation */
	fl_task_xlate_load( &Task_win );

  /* indicate startup state */
	fl_status( &Task_win,"START", FLS_STARTING );
	fl_sleep( 100 );

  //blackbox crash handler initialisation
  if( (strstr( Task_win.k.e_cmd, "-b")) != NULL)
  {
    hLib = LoadLibrary("BlackBox.dll");

    if (hLib == NULL)
      fl_status( &Task_win, strcpy(xl_msg, "INIT_BLACKBOX"), FLS_ERROR);
  }

  /*
   * initialise the critical section functionality for accessing
   * the RTDB from more than one thread.
   */

  if ( fl_init_critical( &Task_win, &Task_fl ) != GOOD )
  {
    fl_status( &Task_win, "INIT_CRITICAL", FLS_ERROR);    
    dl_exit_task( &Task_win, 1);                         
  }

  /*
   * get a third task id to handle kernel actions within the call-back function
   *'/
  memcpy( &Callback, &Task_win, sizeof( TASK_ID ) );
  sprintf( Callback.name, "S7CALL%d", Task_win.id);
  
  //make the description
  sprintf( Callback.desc, "Call back process for SAPI driver '%s'", Callback.name );

  strcpy( Callback.fl_name, Task_win.fl_name );
  strcpy( Callback.fl_domain, Task_win.fl_domain );
  strcpy( Callback.fl_user, Task_win.fl_user );

  if (( Callback.id = fl_proc_init_app(  Callback.name,
                                         Callback.desc,
                                         Callback.fl_name,
                                         Callback.fl_domain,
                                         Callback.fl_user )) < 0 )
  {
    fl_status( &Task_win, "Error init callback id", FLS_ERROR);    
    dl_exit_task( &Task_win, 1);                         
  }*/
  
  /* try to get hold of the Real-Time Database */
  fl_enter_critical( FLS_NORMAL ); //23-07-2007

  /* load task configuration */
	ctload();
  debug_log( &Task_win, "Ct Tables loaded", 8);

  if (!strlen( xl_msg))
  {

	  if( Task_win.mode & LIC_DEMO) 
      strcpy( xl_msg, "DEMO_RUN"); /* indicate demo state */
  	else
      strcpy( xl_msg, "RUN"); /* indicate running state */
  }
  else
    xl_msg[0] = '\0';

  fl_status( &Task_win, xl_msg, FLS_ACTIVE);

  /*
   * Continuously loop, processing all input until
   * a terminate message has been sent to this task.
   */
  while ( dl_test_term_flag( &Task_win ) == OFF )
	{
    if( ( ret = fl_wait_event( &Task_win )) != GOOD )
      fl_status( &Task_win, "FL_CHG_WAIT", FLS_ACTIVE, ret);

    /*
     * release the real-time database so that other threads can have
     * access, 23-07-2007
     */
    fl_leave_critical( FLS_NORMAL );
    fl_sleep( 0);
    fl_enter_critical( FLS_NORMAL );
  }

  fl_status( &Task_win,"CLOSE", FLS_STOPPING );

  #ifndef _COMSIM
	shutdown_all( &Task_win);
  #endif

  /*win_exit();*/

  /*
   * exit the critical section functionality
   */
  fl_exit_critical();

  //fl_proc_exit( Callback.id ); 

  /*
   * exit the task
   */
  dl_exit_task( &Task_win, GOOD );

  if (hLib != NULL) FreeLibrary(hLib);

  return GOOD;
} //fl_main
#pragma warning(default:4100)

/*-----------------------------------------------------------------------------
 *
 * FUNCTION: connect_all
 *	
 * PURPOSE: connect all logical defined devices to physical entity
 *
 -----------------------------------------------------------------------------*/
void connect_all( TASK_ID *task)
{
	int			i; 
  #ifndef _COMSIM
  int fnc,ret;
  #endif

	/* /oop and connect */
	for ( i = 0; i < Nr_devices; i++ )
	{

    #ifndef _COMSIM

		for ( fnc = 0; fnc < 3; fnc++ )
		{

			if( ( ret = sapi_connect( Device[ i ], fnc )) != GOOD )
			{
				fl_status( task, "COM_CONNECT", FLS_ERROR, ret, Device[ i ]->name, Device[ i ]->connection );
			}

		}

    #else

  	Device[i]->connect	= CS_DISCONNECTED;

    Device[i]->disable[ IMX_READ  ][ INTERNAL ] = 1;
    Device[i]->disable[ IMX_WRITE ][ INTERNAL ] = 1;

    #endif
	}
} //connect_all


/*-----------------------------------------------------------------------------
 *
 * FUNCTION: disconnect_all
 *	
 * PURPOSE: disconnect all logical defined devices from their physical entity
 *
 -----------------------------------------------------------------------------*/
void shutdown_all ( TASK_ID *task)
{
	int			i;
	ANA     status = PD_CLOSED;

	/*
	 * loop and connect
	 */
	for ( i = 0; i < Nr_devices; i++ )
	{
		if( fl_write(	task->id, &Device[ i ]->status, 1, &status ) == FL_ERROR )
		{
			fl_status( task, "FLWRITE", FLS_ERROR, fl_errno( task->id ));
		}

		sapi_disconnect( Device[ i ], IMX_READ );
	}

	sapi_shutdown();
} //shutdown_all


/*-----------------------------------------------------------------------------
 *
 * FUNCTION: update_status
 *	
 * PURPOSE:  Updates the status tag of the device
 *
 -----------------------------------------------------------------------------*/
void update_status ( TASK_ID *task, DEVICE *device, ANA status)
{
  /*
   * check if the tag has been defined
   */
	if( fl_gettype( &device->status ) != FL_UNDEFINED )
	{
		if( fl_write(	task->id, &device->status, 1, &status ) == FL_ERROR )
		{
			fl_status( task, "FLWRITE", FLS_ERROR, fl_errno( task->id ));
		}
	}

  return;
} //update_status

/*-----------------------------------------------------------------------------
 *
 * FUNCTION: update_count
 *	
 * PURPOSE:  Updates the status tag of the device
 *
 -----------------------------------------------------------------------------*/
void update_count ( TASK_ID *task, DEVICE *device, ANA count)
{
  /*
   * check if the tag has been defined
   */
	if( fl_gettype( &device->c_count ) != FL_UNDEFINED )
	{
		if( fl_write(	task->id, &device->c_count, 1, &count ) == FL_ERROR )
		{
			fl_status( task, "FLWRITE", FLS_ERROR, fl_errno( task->id ));
		}
	}

  return;
} //update_count