point-of-saleverifone

Sending data via Ethernet port (verifone vx520)


I want to use Ethernet port to send data with create socket.

How can I open the Ethernet port and set IP, NETMASK and GateWay? I can use these functions but I don't know how to open the Ethernet port or how to configure these functions.

ceSETNWParamValue();
ceGetNWParamValue();
ceSetDDParamValue();

Solution

  • Well, The "Verix eVo Volume II OS and Communication Programmers Guide" (esp. chapter 5) can help you out a bit, but before we get into that, there is one important thing to consider--if you are using this program that you are writing on a vx520, you will likely want it on another terminal type at some point in the future. To that end, you may consider using CommServer. CommServer is a program that helps abstract the various types of hardware out of your code so you can send the same commands to any terminal type and let it determine how to fulfill your requests based on what hardware it is using. It has been around for a while and has been ported to most of the VerFone terminal types. It is provided (and supported) by VeriFone for free. There are a few downsides to it:

    However, once you get it working, it's really nice:

    There is a good chance that at some point, you'll need to share your terminal with another 3rd party. If that's the case, you'll need to have your program running on top of VMAC, anyway, AND there is a good chance they'll be using CommServer, too. If this is ever the case, 2 of the "CON"s just disappeared and one of the "PRO"s was just emphasized.

    So now you have to choose--CommServer, or no CommServer.

    If you choose CommServer, you'll need to get very familiar with how FlexiRecords work so as a prerequisite, I suggest you read Chapter 7 of the "Verix eVo Multi-App Conductor Programmers Guide". Next, the program flow will go something like this:

    1) Initialize the event buffer with

    // Initializes the buffer provided to store a new flexi-record structure. 
    // This is a flexirecord public interface function.
    vVarInitRecord(buffer, sizeof(buffer), 0);
    
    // Assigns the buffer passed as a parameter to the global space of the Extended 
    // Flexi-record API.This is a mandatory function call for the rest of the Extended 
    // Flexi-record APIs.The buffer should be initialized using vVarInitRecord()
    // function before calling this API.
    ushInitStandardFlexi(buffer);
    
    //send the event (you'll need some other boiler plate code)
    // you'll probably want to turn this into a "SendEvent" method
    EESL_send_event("COMMSVR", VCS_EVT_INIT_REQ, buffer, bufferSize);
    
    // read the response from CommSever (again, this is a skeletal sample)
    // This will become a "ReadEvent" method
    while(strcmp(sendername, "COMMSVR") || eventID != VCS_EVT_INIT_RESP)
        eventID = EESL_read_cust_evt(buffer, sizeof(buffer), &bufferSize, sendername);
    

    2) Connect

    vVarInitRecord(eco->Buffer, sizeof(buffer), 0);
    ushInitStandardFlexi(buffer);
    
    // shVarAddData will add an un-typed field to a variable record
    // The field VCS_FLD_CONN_URL is defined as a URL or an IP address to connect to. 
    // All syntax validation of URL or IP address is performed by the TCP/IP library.
    shVarAddData(VCS_FLD_CONN_URL, hostip, strlen(hostip));
    
    // shVarAddUnsignedInt adds (unsurprisingly) an unsigned int to the Flexi-record.
    // The constant VCS_FLD_CONN_PORT defines the TCP/IP port number
    shVarAddUnsignedInt(VCS_FLD_CONN_PORT, port);
    
    // The value VCS_FLD_CONN_HOSTSSL represents a flag that indicates whether SSL
    // is supported or not: (1 - SSL supported, 0 - SSL not supported)
    shVarAddUnsignedInt(VCS_FLD_CONN_HOSTSSL, useSSL);
    // (if you are going to use SSL, you'll need to add some other values, too)
    
    //Honestly, I don't know what this is, but I don't think it works without it
    shVarAddUnsignedInt(VCS_FLD_CONN_HOSTCTX, (unsigned short)0);
    
    //send the event (you'll need some other boiler plate code)
    EESL_send_event("COMMSVR", VCS_EVT_CONN_REQ, buffer, bufferSize);
    
    // read the response from CommSever (use the same "receive" code from above, 
    // but you are looking for the response "VCS_EVT_CONN_RESP"
    EESL_read_cust_evt(buffer, sizeof(buffer), &bufferSize, sendername);
    

    3) Verify you are connected

    vVarInitRecord(buffer, sizeof(buffer), 0);
    ushInitStandardFlexi(buffer);
    // Add Status ID buffer to the parameter list
    shVarAddData(VCS_FLD_STATUS_IDS, (unsigned char*)statusIDs, (sizeof(int) * 2));
    
    // do your "sendEvent" from above with the event VCS_EVT_STATUS_REQ
    SendEvent(VCS_EVT_STATUS_REQ);
    
    // do your "ReceiveEvent" from above, looking for VCS_EVT_STATUS_RESP
    ReadEvent(VCS_EVT_STATUS_RESP);
    
    // Extract data from event buffer
    ushInitStandardFlexi(buffer);
    
    //This is the eVo (520) version:
    shVarGetUnsignedInt(VCS_FLD_CONN_STATUS, (unsigned short*)&connStatus);
    //This is the Verix/Vx version
    //shVarGetData(VCS_FLD_CONN_STATUS, (unsigned char*)&connStatus, 
                   sizeof(unsigned short), &dataLength);
    
    if (connStatus == 1) {/* you are connected */}
    

    4) Send

    vVarInitRecord(eco->Buffer, sizeof(buffer), 0);
    ushInitStandardFlexi(buffer);
    
    //Add length parameter to the data stack.
    shVarAddUnsignedInt(VCS_FLD_SEND_BUFSIZE, p_size);
    
    // Send Event to server. Note that this doesn't actually send the data, it simply
    // tells CommServer that data will be coming shortly. It also advises the length
    // of the data to be sent
    SendEvent(VCS_EVT_SEND_REQ); // this is your function, remember?
    
    
    /* Send the raw data to the host via Comm Server */
    EESL_send_event("COMMSVR", VCS_EVT_DATA_RAW, buffer, sendLength);
    
    
    // Read Comm Server's response message. Note that this isn't yet the host response
    // message. We're simply checking to make sure that our data was delivered correctly
    // to Comm Server. We'll get the actual response later...
    ReadEvent(VCS_EVT_SEND_RESP); // your function
    

    5) Receive

    vVarInitRecord(buffer, sizeof(buffer), 0);
    ushInitStandardFlexi(buffer);
    
    /* Add parameters to send to server */
    shVarAddUnsignedInt(VCS_FLD_RECV_BUFSIZE, p_size);
    shVarAddUnsignedInt(VCS_FLD_RECV_TIMEOUT, p_timeout);
    
    
    // Send Event to server. Again, note that this doesn't actually receive any data,
    // it simply prepares comm server for sending us the raw data and will
    // tell us how many bytes we should be expecting
    SendEvent(VCS_EVT_RECV_REQ);
    
    // Read event from server
    ReadEvent(VCS_EVT_RECV_RESP);
    
    // Extract data from event buffer. We're particularly interested in the number
    // total of bytes available to read. Note that we haven't actually read anything
    // at this point. We simply got the number of bytes AVAILABLE to read
    ushInitStandardFlexi(eco->Buffer);
    
    //Now do the actual read
    EESL_send_event("COMMSVR", VCS_EVT_DATA_RAW, (unsigned char *)buffer, readSize);
    

    5) Disconnect

    vVarInitRecord(buffer, sizeof(buffer), 0);
    ushInitStandardFlexi(buffer);
    SendEvent(VCS_EVT_DISC_REQ)
    ReadEvent(VCS_EVT_DISC_RESP);
    

    There's going to be more to it than that, but that's the gist of it.


    At this point, you are likely thinking to yourself, "That looks complicated--how can I do it WITHOUT CommServer?" Well, now we are venturing into a realm that I am less familiar with and I probably won't be that helpful, but I do have a code sample that makes the following calls (note that my code sample is over 1500 lines long, so I can't include it all here):

    //important includes:
    #include <ctype.h>
    #include <svc_net.h>
    #include <ceif.h>
    #include <vos_ddi_ini.h>
    
    // Init Comm Engine
    ceRegister();
    
    // Subscribe to notification events from CommEngine
    ceEnableEventNotification();
    
    
    // Check how many network interfaces (NWIF) are available and store in stNIInfo
    g_NICount=ceGetNWIFCount();
    g_NIInfo = (unsigned char*) malloc (g_NICount * sizeof (stNIInfo));
    ceGetNWIFInfo((stNIInfo*)g_NIInfo, g_NICount, &nwInfoCount);
    FillNWIF ((stNIInfo*)g_NIInfo, g_NICount);
    
    // Check the link speed
    ceGetDDParamValue (g_currMediaInfo.niHandle, "GET_LINK_SPEED",
                sizeof (szLinkSpeed), szLinkSpeed, &linkValueLen);
    

    Where FillNWIF is defined as

    void FillNWIF (stNIInfo stArray[], int arrayCount)
    {
      int cntr = 0;
      for (cntr = 0; cntr < arrayCount; cntr++)
      {
        if (strcmp (stArray [cntr].niCommTech, CE_COMM_TECH_ETH) == 0) 
          g_Devices.devEthernet.iDevHandle = stArray [cntr].niHandle;
        else if (strcmp (stArray [cntr].niCommTech, CE_COMM_TECH_PPPDIAL) == 0)
          g_Devices.devDialPPP.iDevHandle = stArray [cntr].niHandle;
        else if (strcmp (stArray [cntr].niCommTech, CE_COMM_TECH_DIALONLY) == 0)
          g_Devices.devDial.iDevHandle = stArray [cntr].niHandle;
      }
    }
    

    The actual connect and send is, in a nutshell, as follows:

    struct sockaddr_in  sockHost;
    
    memset (&sockHost, 0, sizeof (struct sockaddr_in));
    memset (&timeout, 0, sizeof (struct timeval));
    
    sockHost.sin_family = AF_INET;
    sockHost.sin_addr.s_addr = htonl (inet_addr (g_AppConfig.szHostIP));
    sockHost.sin_port = htons (g_AppConfig.iPort);
    
    sockType = SOCK_STREAM;
    sockHandle = socket (AF_INET, sockType, 0);
    
    connect (sockHandle, (struct sockaddr*)&sockHost, sizeof (struct sockaddr_in));
    
    send (iSockHandle, szSendBuff, uiSendSize, 0);
    recv (iSockHandle, szRecvBuff, sizeof (szRecvBuff), 0);
    

    Other APIs you may find useful:

    //get network interface start mode
    ceGetNWIFStartMode (g_currMediaInfo.niHandle);
    
    // Get the total number of network interface from this terminal
    g_NICount=ceGetNWIFCount();
    
    //Get network interfaces
    ceGetNWIFInfo((stNIInfo*)g_NIInfo, g_NICount, &nwInfoCount);
    
    // only open the NWIF
    ceStartNWIF (g_currMediaInfo.niHandle, CE_OPEN);
    
    //close NWIF
    ceStopNWIF (g_currMediaInfo.niHandle, CE_CLOSE);
    
    // connect
    ceStartNWIF (g_currMediaInfo.niHandle, CE_CONNECT);
    
    //get connection status
    ceGetNWParamValue (iNWIFHandle, IP_CONFIG, &ipConfig, sizeof (stNI_IPConfig), &pLen);
    
    //link up
    ceStartNWIF (g_currMediaInfo.niHandle, CE_LINK)
    
    //network up
    ceStartNWIF (g_currMediaInfo.niHandle, CE_NETWORK);
    
    //network down
    ceStopNWIF (g_currMediaInfo.niHandle, CE_NETWORK);
    
    //link down
    ceStopNWIF (g_currMediaInfo.niHandle, CE_LINK);
    
    //Disconnect
    ceStopNWIF (g_currMediaInfo.niHandle, CE_DISCONNECT);
    
    // Get the version;
    ceGetVersion (CE_VER_VXCE, sizeof (g_szVXCEVersion), g_szVXCEVersion);
    ceGetVersion (CE_VER_CEIF, sizeof (g_szCEIFVersion), g_szCEIFVersion);
    

    To address the make file comments below, your make file should have a line that is something like the following:

    $(EVOSDK)\bin\vrxcc $(COptions) $(Includes) $(AppObjects) $(Libs) -o $(OutDir)\Project.out`. 
    

    Above that, each of COptions, Includes, AppObjects, and Libs need to be defined.

    COptions

    COptions are the compiler options you want to use. Several possible options are in your "Verix eVo Volume III OS programming tools reference manual", but as an example, you might set it to:

    COptions = -p -DLOGSYS_FLAG -DLOGSYS_NEW_API_STYLE
    

    Includes

    Includes is how you tell the compiler where to look for your header (.h) files. Any time you use a #include statement, you need to make sure that the directory where that .h file lives is represented in your Includes list. For example, if you want to #include <ceif.h> then you need to make sure you have -I$(EOSSDK)\include as part of your includes path. An example of how you may set your Includes might be:

    Includes = -I.\include -I$(EVOSDK)\include -I$(EOSSDK)\include -I$(EVOACT)\include -I$(EVOVCS)include -I$(EVOVMAC)include
    

    AppObjects

    For each .c file you have, you need to compile it into an object (.o) file. You could technically roll this up with Libs below as it is really the same thing. The only difference is that you made these; they aren't part of the SDK or anything.

    Libs

    Libs might look something like this:

    Libs =  $(EOSSDK)\lib\svc_net.o \
            $(EOSSDK)\lib\ssl.o \
            $(EOSSDK)\lib\ceif.o \
            $(EOSSDK)\lib\elog.o \
            $(EVOACT)\Output\RV\Files\Static\Release\act2000.a
    

    The last part, -o $(OutDir)\Project.out is just saying where you want to output the result of your compilation.