/*-------------------------------------------------------------------------
 * Name:   acm.h
 * Author: ali & mlu
 *
 * Copyright 1991-99 Telelogic AB, All rights reserved.
 * 
 * This Program is owned by Telelogic and is protected by national
 * copyright laws and international copyright treaties. Telelogic
 * grants you the right to use this Program on one computer or in one
 * local computer network at any one time.  Under this License you may
 * only modify the source code for the purpose of adapting it to your
 * environment. You must reproduce and include any copyright and
 * trademark notices on all copies of the source code.  You may not
 * use, copy, merge, modify or transfer the Program except as provided
 * in this License.  Telelogic does not warrant that the Program will
 * meet your requirements or that the operation of the Program will be
 * uninterrupted and error free. You are solely responsible that the
 * selection of the Program and the modification of the source code
 * will achieve your intended results and that the results are
 * actually obtained.
 */

/* Autoduck command... */
/* @doc */

#ifndef ACM_H
#define ACM_H

#include "gci.h"

/* Keep the compiler from complaining about parameters which are not used.
 */
# if defined (ghs) || defined (__GNUC__) || defined (__hpux) || defined (__sgi) || defined (DEC_CXX) || defined (__KCC) || defined (__rational__) || (__USLC__)
#   define ACM_UNUSED_ARG(a) {if (&a) /* do nothing */ ;}
# else
#   define ACM_UNUSED_ARG(a) (a)
# endif

#ifndef ACM_MALLOC
#define ACM_MALLOC malloc
#endif 

#ifndef ACM_FREE
#define ACM_FREE free
#endif

#ifndef ACM_STRLEN
#define ACM_STRLEN strlen
#endif

#ifndef ACM_STDERR
#define ACM_STDERR stderr
#endif

#ifndef ACM_FPRINTF
#define ACM_FPRINTF fprintf
#endif

#ifndef ACM_MEMCPY
#define ACM_MEMCPY memcpy
#endif

#ifndef ACM_MEMMOVE
#define ACM_MEMMOVE memmove
#endif

#ifndef ACM_MEMSET
#define ACM_MEMSET memset
#endif

/* define the proper import export macro for different platforms */

#ifndef ACM_Export

#if defined(WIN32)

# if defined(ACM_BUILD_DLL) /* Building the dll */
#define ACM_Export _declspec (dllexport)
#else /* using the dll */
#define ACM_Export _declspec (dllimport)
#endif /* ACM_BUILD_DLL */

#else /* Non win32 platform */
#define ACM_Export 
#endif

#endif /* ACM_Export */

/* Define that we have winsocket version 2,0 */
#ifndef TCP_WINSOCKET_VERSION
#define TCP_WINSOCKET_VERSION 2,0
#endif

/* Address types */
#define ACM_ADDRESS_TCPIP 1

typedef enum {
  acm_no_error = 0,
  
  acm_use_errno,          /* Check the variable errno for a system error. */

  acm_nonexisting_timer,  /* The timer has not been CREATEd. */
  acm_null_time,          /* The time object is NULL. */
  acm_illegal_time_unit,  /* The unit of time is undefined. */
  acm_no_running_timers,  /* There are no timers in the Running queue. */
  acm_no_timer_handle,    /* There is no timer handler registered */
#if defined (WIN32)
  acm_winsock_bad_init,     /* WIN32: WSAStartUp() failed. */
  acm_winsock_old_version,  /* WIN32: WinSock 2.0 is required. */
  acm_winsock_bad_cleanup,  /* WIN32: WSACleanUp() failed. */
  acm_winsock_listen_error, /* WIN32: listen() failed. */
#endif

  acm_socket_create_error,  /* Failed to create socket. */
  acm_socket_bind_error,    /* Failed to bind socket. */
  acm_socket_listen_error,  /* listen() failed */
  acm_socket_connect_error, /* connect() failed. */
  acm_socket_send_error,    /* Sending failed. */
  acm_socket_select_error,  /* select() failed */

  acm_unconnected_pco,      /* The PCO is not connected to a port. */
  acm_null_address,         /* The address specified was NULL. */
  acm_wrong_address_type,    /* The GciAddress was of the wrong communication type */
  acm_no_decode_handle,     /* The decode handle is not registered */
  acm_buffer_overflow,      /* The buffer is overflowed */
  acm_no_gcireceive,        /* No GciReceiveFunction registered */
  acm_callback_failed       /* Calling a registered callback function failed*/
    
} ACM_Error_Number;

/************************************************************************
  Definition of used data types...
*/

/* @struct This structure is a buffer structure used to store 
           data that should be sent and received.
*/
typedef struct GciBuffer {
  char* buffer;			/* @field The character buffer (could contain zeros) */
  int   max_length;		/* @field The allocated length of the buffer */
  int current_length;		/* @field The Current used length of the buffer */
} GciBuffer;

typedef struct _GciAddress {
  int     type;        /*  Address type 0 - 100 is reserved by Telelogic */
  char*   buffer;      /* The address stored in a buffer */
} GciAddress;

/* @enum Describes the role the ETS should play in a connection, client or server.
*/
typedef enum
{ 
  ACMClient,			/* @emem client */
  ACMServer			/* @emem server */
} ACMConnectionType;

/* Declaration of Timeoute handling function... */
typedef GciStatus (*ACMTimeoutHandler)(GciTimerID);
/* Declaration of Decode handling function....*/
typedef GciStatus (*ACMDecodeHandler)(const GciBuffer*, unsigned int*, GciValue**);

typedef GciStatus	(*GciReceiveHandler)(int, GciValue*);

typedef struct _ACMTime {
  unsigned long time_val;
  GciTimeUnit unit;
} ACMTime;

/*************************************************************************
  @func Initializes the communication module.
  @parm const ACMTime | *max_timeout | [in] The maximum time to wait for incomming 
                                       messages if no timer are used or running.
  @parm GciTimeUnit | time_tick_unit | [in] The internal time unit size. All time
                                       values are internaly converted into this unit.
                                       
  @rdesc GciOk on success.
  */
ACM_Export GciStatus ACMInit(const ACMTime* max_timeout, GciTimeUnit time_tick_unit);


/*************************************************************************
  @func Registration of timer callback function.
  @parm ACMTimeoutHandler | timeouthandler | Pointer to a timeout handling
                                              function.
  @rdesc GciOk on success..
*/
ACM_Export GciStatus ACMRegisterTimeoutHandler(ACMTimeoutHandler timeouthandler);


/*************************************************************************
  @func Register default decode function. This function will be used to 
        decode the receive buffer into GciValues.
  @parm ACMDecodeHandler | decode_handler | [in] Pointer to the decoding function.
  @rdesc GciOk on success....
*/
ACM_Export GciStatus ACMRegisterDefaultDecodeHandler(ACMDecodeHandler decode_handler);


/*************************************************************************
  @func Registration of a decode function associated to a specific pco.
        This will override the default Decode Handler function. Note that
        the pco must be connected first have created the pco before this function
        can be called. 
  @parm ACMDecodeHandler | decode_handler | [in] Pointer to the decoding function.
  @parm GciPCOID | pco_id | [in] The pco that the decoder_handler should be associated with.
  @rdesc GciOk on success....
*/
ACM_Export GciStatus ACMRegisterDecodeHandler(ACMDecodeHandler decode_handler, GciPCOID pco_id);


/*************************************************************************
  @func Registration of a receive callback function.
  @parm GciReceiveHandler | receive_fp | [in] Function pointer to a receive callback
                                         function. This is typically a pointer
                                         to the GciReceive function.
  @rdesc GciOk on success..
*/
ACM_Export GciStatus ACMRegisterReceiveHandler(GciReceiveHandler receive_callback);

   
/*************************************************************************
  @func Creates and open a connection associated to a pco_id. 
  @parm GciPCOID | pco_id | [in] The associated pco identifier.
  @parm const GciAddress | *address | [in] Address to the destination (IUT).
  the destination should be blocking or non-blocking.
  @parm ACMConnectionType | type | [in] The type the ets has in the connection,
  should it be a client or server.
  @parm unsigned int | buffer_size | [in] The maximum size of a "value" that should be sent
  @rdesc GciOk if the connection was successfully created and openend.

  */
ACM_Export GciStatus ACMConnect(GciPCOID pco_id, 
                                const GciAddress* address, 
                                ACMConnectionType type, unsigned int buffer_size);


/*************************************************************************
  @func Disconnects the connection to the IUT for a given pco identifier.
  @parm GciPCOID | pco_id | [in] The Assiciated pco identifier.
*/  
ACM_Export void ACMDisconnect(GciPCOID pco_id);


/************************************************************************
  @func Cancel all timers even those who may be expired. Clear all
        pco buffers. This function is typically called before starting
	a new session (testcase) to ensure that all old data is removed
	and to put the ACM Module into a inital status mode.
  @redesc GciOk on success.
*/
ACM_Export GciStatus ACMReset();

/************************************************************************
  @func Sends a buffer to the destination associated with the pco_id. 
        ACMSend will block until the hole buffer is sent or an error
	occurs.
  @parm GciPCOID | pco_id | [in] The pco to send to.
  @parm GciBuffer | *buffer | [inout] The data buffer that will be sent. 
  @rdesc GciOk if send was ok.
*/
ACM_Export GciStatus ACMSend(GciPCOID pco_id, GciBuffer *buffer);


/************************************************************************
  @func Recveives a buffer of data from the destination (port) associated
        to the pci_id. Receive does not block. If no data received the
	buffer will be empty.
  @parm GciPCOID  | pco_id | [in] The pco identifier.
  @parm  GciBuffer | *buffer | [inout] The data that have been received. The buffer
                               must be allocated and initalized by the caller.
  @rdesc GciOk on success and GciNotOk on error.
  */
ACM_Export GciStatus ACMReceive(GciPCOID pco_id, GciBuffer *buffer);


/************************************************************************
  @func Changes timer status to running calculates when to timeout.
  @parm GciTimerID | timer_id | [in] Unique identifier for the timer
  @parm ACMTime | timeout | [in] The amount of time before the timer fires.
  @rdesc GciOk if the timer was started successfully, GciNotOk on error.
*/
ACM_Export GciStatus ACMStartTimer(GciTimerID timer_id, const ACMTime* timeout);


/***********************************************************************
  @func Stops a timer. The timer status is changed to stopped.
  @parm GciTimerID | timer_id | [in] Unique identifier fo the timer to be stopped.
  @rdesc GciOk on success and GciNotOk on error.
*/
ACM_Export GciStatus ACMCancelTimer(GciTimerID timer_id);

/***********************************************************************
  @func Stops all timers. The all timers will have status stopped after
        this function is called. Note that all even timers that has expired
	will have status stoped.
  @rdesc GciOk on success...
*/
ACM_Export GciStatus ACMCancelAllTimers();

/**********************************************************************
  @func Returns the "Current" time. Note that this has not to be the
        same as the systemtime it is totally implementation specific
	for each implementation of this library.
  @parm ACMTime | *current_time | [inout] The current time. Note that current_time
                                  must be allocated by the caller.
  @rdesc GciOk on success and GciNotOk on error.
*/
ACM_Export GciStatus ACMCurrentTime(ACMTime *current_time);


/*********************************************************************
  @func Get the first timed out timer_id
  @rdesc Returns the position of the first timed out timer. If
         ACMGetTimedOutPos returns NULL if not timer has timed out.
*/
ACM_Export GciPosition ACMGetTimedOutPos();

/*********************************************************************
  @func Get next timed out timer_id
  @parm GciPosition | *position | [inout] position will be updated
                                          in this call. Position will
					  points to the next timer that
					  has timed out. If position is 
					  NULL then there is no
					  more timers in the list.
*/
ACM_Export GciTimerID ACMGetNextTimedOut(GciPosition* position);

/**********************************************************************
  @func Reads the timer and returns the amount of time before timeout.
  @parm GciTimerID | timer_id | [in] The timer id of the timer to read.
  @parm ACMTime | *time_before_timeout | [out] The amount of time before timeout.
  @rdesc GciOk on success and GciNotOk on error.
*/
ACM_Export GciStatus ACMReadTimer(GciTimerID timer_id, ACMTime *time_before_timeout);

/***********************************************************************
  @func returns the amount of time before the first timer times out.
  @parm ACMTime | *time_before_timeout | [out] The amount of time before
                                         timeout.
  @rdesc GciOk on success and GciNotOk on error.
*/
ACM_Export GciStatus ACMTimeLeft(ACMTime *time_before_timeout);

/**********************************************************************
  @func Returns the timer status for a given timer.
  @parm GciTimerID | timer_id |[in] Unique identifier for the timer.
  @parm GciTimerStatus | *timer_status | [out] The status of the timer.
  @rdesc GciOk on success.
*/
ACM_Export GciStatus ACMTimerStatus(GciTimerID timer_id, GciTimerStatus *timer_status);

/**********************************************************************
  @func Waits for the next event to happen. It could either be a receive
        a timeout event or a max timeout event. A max timeout happens 
        when no data received and no timer could timeout. This is to 
        prevent deadlock.
  @rdesc GciOk on success..
 */
ACM_Export GciStatus ACMWaitForEvent();

/**********************************************************************
  @func Synchronize all timers and call the timeout handler for the 
        timed out ones.
  @parm ACMTimeoutHandler timeout_handler
  @rdesc GciOk on success.
*/
ACM_Export GciStatus ACMSynchronizeTimers(ACMTimeoutHandler timeout_handler);

/***********************************************************************
  @func This is a Function will wait for events to happen and it will
        call the registered timeout callback and decoder callback functions.
*/
ACM_Export GciStatus ACMSnapshot();

/***********************************************************************
  @func Get the position to the first pco that has received data.
  @rdesc Returns the position of the first pco that has received data.
  NULL if no pco has received any data.
  */
ACM_Export GciPosition ACMGetReceivedPCOPos();

/**********************************************************************
  @func Get the next pco id that has received data.
  @parm GciPosition | *position | [inout] position will be updated in this call
                      to the next position.
  @rdesc The pco id.
*/
ACM_Export GciPCOID ACMGetNextReceivedPCO(GciPosition* position);

/*************************************************************************
  @func Sets the error number.
  @parm ACM_Error_Number | errno | The error number.
  */
ACM_Export void ACMSetLastError(ACM_Error_Number errornumber);

/*************************************************************************
  @func Returns the last set error message.
  @rdesc The last set error message string.

  */
ACM_Export const char* ACMGetLastErrorMessage();

/*************************************************************************
  @func Returns the last set error number.
  @rdesc The last set error number.

  */
ACM_Export ACM_Error_Number ACMGetLastError();

#endif
