/*
 *            Copyright (c) 2002-2005 by Real Time Automation
 *
 *  This software is copyrighted by and is the sole property of
 *  Real Time Automation (RTA).  All rights, title, ownership, or other 
 *  interests in the software remain the property of RTA.  This
 *  software may only be used in accordance with the corresponding
 *  license agreement.  Any unauthorized use, duplication, transmission,
 *  distribution, or disclosure of this software is expressly forbidden.
 *
 *  This Copyright notice MAY NOT be removed or modified without prior
 *  written consent of RTA.
 *
 *  RTA reserves the right to modify this software without notice.
 *
 *  Real Time Automation
 *  2825 N. Mayfair Road               USA 414.453.5100
 *  Suite 11                           http://www.rtaautomation.com
 *  Wauwatosa, WI 53222                software@rtaautomation.com
 *
 *************************************************************************
 *
 *     Module Name: eipc_usermain.c
 *         Version: 1.01
 *   Original Date: 9/16/2005
 *          Author: Jamin D. Wendorf (jwendorf@rtaautomation.com)
 *        Language: Ansi C
 * Compile Options: N/A
 * Compile defines: N/A
 *       Libraries: N/A
 *    Link Options: N/A
 *
 * Description.
 * ====================================================================
 * This file contains the sample main application for driving the 
 * EtherNet/IP Tag Client.
 *
 *
 * Edit Date / Ver  Edit Description
 * ===============  ===================================================
 * 09/16/2005 1.01  Initial Version
 *
 */

/* ========================== */
/*	 INCLUDE FILES	          */
/* ========================== */
#include "eipc_system.h"
#include <time.h>

/* ========================== */
/* GLOBAL FUNCTION PROTOTYPES */
/* ========================== */

/* ========================== */
/*	 EXTERN DATA	          */
/* ========================== */

/* ========================== */
/*	 GLOBAL DATA	          */
/* ========================== */
WSADATA WSData;
uint16 SampleServerHandle;
uint16 Ticker1;

/* ========================= */
/* LOCAL FUNCTION PROTOTYPES */
/* ========================= */
void   local_init_ticker (void);
uint32 local_get_ticks_passed (void);

/* ========================= */
/*	 LOCAL DATA	             */
/* ========================= */

/* ========================= */
/*	 MISCELLANEOUS	         */
/* ========================= */

/* NEW PAGE */
/* ==================================================== */
/*		   GLOBAL FUNCTIONS	                            */
/* ==================================================== */
/* ****************************************************
  Function: main
Parameters: N/A
   Returns: N/A

This function serves as the main driver.  Be sure to
use non-blocking calls so the timer processing is called
frequently.
******************************************************* */
int main (void)
{
    /* local variables */
    int     error;
    uint8   ipaddr_byte[4];
    uint32  ipaddr32;
    int16   server_handle, return_code;
    uint8   i, j, tag_num, rw_toggle;
    uint16  loop_cnt;
    EIPC_TAG_STRUCT tags[EIPC_USEROBJ_MAXTAGS_PER_MSG];

    /* ---------------------------------------------- */
    /*		   SOCKET INITIALIZATION BEGIN            */
    /* ---------------------------------------------- */
    // initialize WinSock
    error = WSAStartup(0x0020, &WSData);

    /* printf if we received an FAILURE */
    switch(error)
    {
        case WSASYSNOTREADY:     
            eipc_user_dbprint0("WSAStartup: \"WSASYSNOTREADY\"\r\n");    
            exit(1);
        case WSAVERNOTSUPPORTED: 
            eipc_user_dbprint0("WSAStartup: \"WSAVERNOTSUPPORTED\"\r\n"); 
            exit(1);
        case WSAEINPROGRESS:
            eipc_user_dbprint0("WSAStartup: \"WSAEINPROGRESS\"\r\n");
            exit(1);
        case WSAEPROCLIM:
            eipc_user_dbprint0("WSAStartup: \"WSAEPROCLIM\"\r\n");
            exit(1);
        case WSAEFAULT:
            eipc_user_dbprint0("WSAStartup: \"WSAEFAULT\"\r\n");
            exit(1);
    };
    /* ---------------------------------------------- */
    /*		   SOCKET INITIALIZATION END              */
    /* ---------------------------------------------- */

    // call the initialization code (RTA's init routines)
    eipc_rtasys_init(0);
   
    // initialize timer code
    local_init_ticker();

    // **********************************************
    // Server Connection Configuration 192.100.100.25 
    // **********************************************

    // store the IP address
    ipaddr_byte[0] = 192;
    ipaddr_byte[1] = 100;
    ipaddr_byte[2] = 100;
    ipaddr_byte[3] = 25;
    ipaddr32 = rta_GetBigEndian32(ipaddr_byte);

    // allocate a connection to server 1
    server_handle = eipc_tagclient_connectToPLC(ipaddr32);

    // zero out the ticker
    Ticker1 = 0;

    // default to write (1); read is (0)
    rw_toggle = 0; // write first (value is toggled prior to send)

    // we want to data to change
    loop_cnt = 0;

    /* --------------------------------------------- */
    /*               RUN FOREVER                     */
    /* --------------------------------------------- */
    for(;;)
    {
        /* process the state */
        eipc_rtasys_process(local_get_ticks_passed());

        /* send a message every second */
        if(Ticker1 > 500)
        {
            // reset the ticker 
            Ticker1 = 0;

            // alternate between reads and writes for the demo
            rw_toggle ^=1;

            // increment the loop count (writes only)
            if(rw_toggle)
                loop_cnt++;

            // ***************************************
            // Build the Request (5 tags)
            // ***************************************

            // set the tag count to 5
            tag_num = 5;


            // ***************************************
            // Configure all 5 Tags
            //
            // Tag 1 : TestTag[0], 1 Element
            // Tag 2 : TestTag[1], 1 Element
            // Tag 3 : TestTag[2], 1 Element
            // Tag 4 : TestTag[3], 1 Element
            // Tag 5 : TestTag[4], 1 Element
            // ***************************************
            for(i=0; i<tag_num; i++)
            {            
                // zero out the tag configuraiton
                memset(&tags[i], 0, sizeof(EIPC_TAG_STRUCT));

                // store the tag name and tag name length
                strcpy(tags[i].tag_name, "JohnTag");
                tags[i].tag_name_len = strlen("JohnTag");

                // store the number of elements to read/write
                tags[i].tag_num_elements = 1;

                // stote the tag offset to read/write
                // usually 0, unless you are acessing an array
                tags[i].tag_offset = i;

                // update the write data on writes
                if(rw_toggle == 1)
                {
                    // store the data type (INT)
                    tags[i].tag_data_type = CL_DATATYPE_INT;

                    // store the data size in bytes
                    tags[i].tag_data_len = tags[i].tag_num_elements*2;
                
                    // store the data (default to i for the demo)
                    for(j=0; j<tags[i].tag_num_elements; j++)
                    {   
                        rta_PutLitEndian16((uint16)(i+loop_cnt), &tags[i].tag_data_ptr[j*2]); 
                    }
                }
            }

            // ***************************************
            // Send Write Request
            // ***************************************
            if(rw_toggle == 1)
            {
                /* server handle, timeout, slot, num tags, tags */
                return_code = eipc_tagclient_sendTagWrite(server_handle, 100, 0, tag_num, &tags[0]);            
            }

            // ***************************************
            // Send Read Request
            // ***************************************
            else
            {
                /* server handle, timeout, slot, num tags, tags */
                return_code = eipc_tagclient_sendTagRead(server_handle, 100, 0, tag_num, &tags[0]);            
            }

            // ***************************************
            // Process the Response (print the errors)
            // ***************************************
            switch(return_code)
            {
                // SUCCESS - Do Nothing
                case EIPC_CLIENT_UCMMERR_SUCCESS:
                    break;

                // Server Handle Invalid or Not Connected
                case EIPC_CLIENT_UCMMERR_SERVHAND:
                    eipc_user_dbprint0("EIPC_CLIENT_UCMMERR_SERVHAND\r\n");

                    // ---------------------------------------------
                    // try to reconnect to the server (if necessary)
                    // ---------------------------------------------
                    server_handle = eipc_tagclient_connectToPLC(ipaddr32);
                    break;

                // Message Already in Progress to the Server Handle
                case EIPC_CLIENT_UCMMERR_BUSY:
                    eipc_user_dbprint0("EIPC_CLIENT_UCMMERR_BUSY\r\n");

                    // try to resend the message later
                    break;

                // Tag Count Exceeds Max Allowed
                case EIPC_CLIENT_UCMMERR_TAGCNT:
                    eipc_user_dbprint0("EIPC_CLIENT_UCMMERR_TAGCNT\r\n");

                    // try to read/write less tags in a single request
                    break;

                // Tag Configuration Pointer is Invalid
                case EIPC_CLIENT_UCMMERR_TAGPTR:
                    eipc_user_dbprint0("EIPC_CLIENT_UCMMERR_TAGPTR\r\n");
        
                    // don't pass a NULL configuration pointer
                    break;

                // Tag Format is Invalid or Too Large for a Single Message
                case EIPC_CLIENT_UCMMERR_TAGFMT:
                    eipc_user_dbprint0("EIPC_CLIENT_UCMMERR_TAGFMT\r\n");

                    // try to read/write less tags in a single request
                    break;

                // Timeout is Too Small
                case EIPC_CLIENT_UCMMERR_TMOINVALID:
                    eipc_user_dbprint0("EIPC_CLIENT_UCMMERR_TMOINVALID\r\n");

                    // increase the timeout value on send requests
                    break;
            };
        }
    }
}

/* ================================================ */
/*              LOCAL FUNCTIONS                     */
/* ================================================ */
/* ****************************************************
  Function: local_init_ticker
Parameters: N/A
   Returns: N/A

This function initializes the tick_passed variables.
******************************************************* */
clock_t tick_base, tick_elapsed;
void local_init_ticker (void)
{
    tick_base = clock();
    tick_elapsed = tick_base;
}

/* ****************************************************
  Function: local_get_ticks_passed
Parameters: N/A
   Returns: ticks passed

This function returns the number of ticks that have
passed since the last call to this function.
******************************************************* */
uint32 local_get_ticks_passed (void)
{
    uint32 return_val;

    tick_elapsed = clock();

    // we rolled over (this shouldn't happen)
    if(tick_elapsed < tick_base)
    {
        // ignore the ticks that passed prior to rolling over
        // just count the ticks since rolling over
        return_val = tick_elapsed;
    }

    else
    {
        // calculate the ticks passed
        return_val = (uint32)(tick_elapsed - tick_base);
    }

    //start over the ticks passed
    tick_base = tick_elapsed;

    // we need some sort of time base for our sample code
    Ticker1 = (Ticker1 + (uint16)return_val);

    //return the ticks passed
    return(return_val);
}

/* *********** */
/* END OF FILE */
/* *********** */

