通过以太网端口发送数据(verifone vx520)

Sending data via Ethernet port (verifone vx520)

我想使用以太网端口通过创建套接字发送数据。

如何打开以太网端口并设置IP、NETMASK和GateWay? 我可以使用这些功能,但我不知道如何打开以太网端口或如何配置这些功能。

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

好吧,"Verix eVo Volume II OS and Communication Programmers Guide"(尤其是第 5 章)可以帮助您解决一些问题,但在我们开始之前,有一件重要的事情需要考虑——如果您正在使用这个程序,您在 vx520 上编写,您可能希望在将来的某个时候在另一种终端类型上使用它。为此,您可以考虑使用 CommServer。 CommServer 是一个程序,可以帮助从您的代码中抽象出各种类型的硬件,这样您就可以将相同的命令发送到任何终端类型,并让它根据它使用的硬件来确定如何满足您的请求。它已经存在了一段时间,并已移植到大多数 VerFone 终端类型。它由 VeriFone 免费提供(和支持)。它有一些缺点:

  • 它只是增加了 1 个您必须下载的程序(而且它很大)
  • 它要求您通过 Flexi Records 发送请求,一开始设置起来可能有点混乱。
  • 它增加了 1 层移动部件,使调试变得复杂
  • 如果您以前没有使用过 VMAC,那么您现在需要使用它(这是另一个程序,更复杂)

但是,一旦你开始使用它,它真的很棒:

  • 对所有硬件使用相同的代码
  • 如果终端上有多个应用程序 运行 都需要使用 IP 通信,则不需要任何应用程序中的 TCP/IP 库,这通常会导致较小的整体尺寸。

很有可能在某个时候,您需要与另一个第 3 方共享您的终端。如果是这种情况,无论如何,您都需要在 VMAC 之上安装程序 运行,而且他们也很有可能会使用 CommServer。如果是这种情况,"CON" 中的 2 个消失了,"PRO" 中的一个被强调了。

所以现在您必须选择--CommServer,或者不选择CommServer。

如果您选择CommServer,您需要非常熟悉FlexiRecords 的工作原理,作为前提,我建议您阅读"Verix eVo Multi-App Conductor Programmers Guide" 的第7 章。接下来,程序流程将是这样的:

1) 用

初始化事件缓冲区
// 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) 连接

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) 确认您已连接

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) 发送

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) 接收

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) 断开连接

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

它的内容远不止于此,但这就是它的要点。


此时,您可能会想,"That looks complicated--how can I do it WITHOUT CommServer?"好吧,现在我们正在进入一个我不太熟悉的领域,我可能不会那么有帮助,但我确实有进行以下调用的代码示例(请注意,我的代码示例超过 1500 行,因此我无法在此处包含所有内容):

//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);

其中 FillNWIF 定义为

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;
  }
}

实际的connect和send,简而言之,如下:

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);

您可能会觉得有用的其他 API:

//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);

要解决下面的 make 文件注释,您的 make 文件应该有一行类似于以下内容:

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

在此之上,COptionsIncludesAppObjectsLibs都需要定义。

选项

COptions 是您要使用的编译器选项。 "Verix eVo Volume III OS programming tools reference manual" 中有几个可能的选项,但作为示例,您可以将其设置为:

COptions = -p -DLOGSYS_FLAG -DLOGSYS_NEW_API_STYLE
  • -p表示它是针对ARM11处理器的(即这个代码是针对520的,不是570的)
  • -DLOGSYS_FLAG 表示您要启用 LOG_PRINTF 语句和
  • -DLOGSYS_NEW_API_STYLE 表示您要使用新的宏(不需要双括号)

包括

Includes 是告诉编译器在哪里查找头文件 (.h) 的方式。任何时候你使用 #include 语句,你都需要确保 .h 文件所在的目录在你的 Includes 列表中。例如,如果你想 #include <ceif.h> 那么你需要确保你有 -I$(EOSSDK)\include 作为你的包含路径的一部分。您可以如何设置 Includes 的示例可能是:

Includes = -I.\include -I$(EVOSDK)\include -I$(EOSSDK)\include -I$(EVOACT)\include -I$(EVOVCS)include -I$(EVOVMAC)include
  • 注意每个前面都有一个-I。这告诉编译器它是一个 Include 而不是库文件。
  • .\include 指向我制作的 .h 文件。请注意,它使用了一个相对目录,因此它假定我的 include 文件夹在我的 make 文件存在的同一位置可见。
  • EVOSDKEOSSDKEVOACT 中的每一个都可能会在您的所有项目中使用
  • EVOVCS 是如果您使用的是 commserver
  • EVOVMAC 是如果您使用的是 VMAC(如果您使用的是 commserver,则将是)
  • 如果您不使用 VMAC 或 CommServer,请关闭最后两个。

AppObjects

对于您拥有的每个 .c 文件,您需要将其编译成一个对象 (.o) 文件。从技术上讲,您可以使用下面的 Libs 来汇总它,因为它们实际上是同一回事。唯一的区别是你做了这些;它们不是 SDK 或任何东西的一部分。

Libs 可能看起来像这样:

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
  • ceif.o 是您需要使用 ceif.h.
  • 中定义的内容的目标文件
  • 注意每行末尾有一个\(最后一行除外)。这只是告诉 nmake 这一行继续。您可以同样正确地删除每个 \ 并将其全部放在 1 行上。这只是为了便于阅读。

最后一部分,-o $(OutDir)\Project.out只是说你想把编译结果输出到哪里。