lwip板无法维持与另一个lwip板的连接

时间:2019-06-25 21:31:36

标签: c embedded stm32 lwip

我有一个奇怪的问题。一段时间以来,我一直在尝试更换小型协议转换器(基本上是双向串行到以太网...主从),以换取具有更多功能的东西。

背景故事

经过大量的逆向工程之后,我发现了该设备的工作原理,并且我一直在尝试复制它,并且我已经成功地将板子连接到该设备上了……主机和我的板子作为从机,反之亦然,并且一切正常,这实际上更好,因为在更高的速度下没有更多的数据包丢失(连接2个原始数据包会导致数据包丢失)。

但是,当我尝试将设备作为主设备连接而将另一台设备作为从设备..运行完全相同的代码段时,它可以进行2或3次交换,然后停止运行……最终有时几分钟后,它将再次尝试2或3次。

如何进行测试

  • 我连接了一个Modbus主站和从站(modbustools,两个不同的实例)。主站是串行RTU Modbus,从站是串行RTU Modbus;
  • 我将其中一台设备配置为主设备,并将其连接到串行端口,以便它接收串行modbus并将协议发送到与其连接的设备;
  • 我配置了从站,以便它通过串行端口连接到从站Modbus。基本上,它通过创建一个套接字并连接到主站的IP来工作,然后等待通过以太网的主站传输,通过串行将其发送到从站modbus(modbustools),接收响应,将其发送给主站,然后将其发送到modbus主站(modbustools);

我有点困惑,但这就是它的工作方式……我的主人等待套接字连接,然后它们之间的通信开始,因为那是旧的工作方式。

我现在已经编写了一个echo客户程序来测试连接。现在,基本上,我的代码连接到服务器(我的主服务器),它接收一个数据包,然后回复它收到的相同数据包。当我尝试将此连接到我的2个板上时,它们不起作用。它更多地是相同的,需要进行2或3次交换,然后停止,但是当我将其连接到原始设备时,它将继续正常运行。

来源

这是我的TCP主服务器(实际上是服务器)的初始化:

void initClient() {
            if(tcp_modbus == NULL) {
                tcp_modbus = tcp_new();
                previousPort = port;
                tcp_bind(tcp_modbus, IP_ADDR_ANY, port);
                tcp_sent(tcp_modbus, sent);
                tcp_poll(tcp_modbus, poll, 2);
                tcp_setprio(tcp_modbus, 128);
                tcp_err(tcp_modbus, error);
                tcp_modbus = tcp_listen(tcp_modbus);
                tcp_modbus->so_options |= SOF_KEEPALIVE; // enable keep-alive
                tcp_modbus->keep_intvl = 1000; // sends keep-alive every second
                tcp_accept(tcp_modbus, acceptmodbus);
                isListening = true;
            }
}
static err_t acceptmodbus(void *arg, struct tcp_pcb *pcb, err_t err) {
    tcp_arg(pcb, pcb);
    /* Set up the various callback functions */
    tcp_recv(pcb, modbusrcv);
    tcp_err(pcb, error);

    tcp_accepted(pcb);

    gb_ClientHasConnected = true;
}

//receives the packet, puts it in an array "ptransparentmessage->data"
//states which PCB to use in order to reply and the length that was received
static err_t modbusrcv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) {
    if(p == NULL) {
        return ERR_OK;
    } else if(err != ERR_OK) {
        return err;
    }

    tcp_recved(pcb, p->len);

    memcpy(ptransparent.data, p->payload,p->len);
    ptransparent->pcb = pcb;
    ptransparent->len = p->len;
}

串行接收基本上是这样的: 检测到接收到的一个字节,开始超时,当超时结束时,通过已连接到服务器的TCP套接字发送接收到的所有内容。然后,它通过acceptmodbus函数接收数据包并通过串行端口发送。

这是我客户的(从属)代码:

void init_slave() {
    if(tcp_client == NULL) {
        tcp_client = tcp_new();

        tcp_bind(tcp_client, IP_ADDR_ANY, 0);
        tcp_arg(tcp_client, NULL);
        tcp_recv(tcp_client, modbusrcv);
        tcp_sent(tcp_client, sent);
        tcp_client->so_options |= SOF_KEEPALIVE; // enable keep-alive
        tcp_client->keep_intvl = 100; // sends keep-alive every 100 mili seconds
        tcp_err(tcp_client, error);


        err_t ret = tcp_connect(tcp_client, &addr, portCnt, connected);
    }
}

其余代码相同。唯一改变的是操作流程。

  1. 连接到服务器
  2. 等待数据包
  3. 通过串行发送
  4. 等待响应超时(与服务器相同的超时,它只是以不同的方式开始计数...服务器接收到一个字节后启动,客户端通过串行端口发送内容后启动)
  5. 获取响应并将其发送到服务器

观察

在通讯中未检测到错误。经过一些测试,似乎不是导致挂起的交换数量。它会在一段时间后发生。在我看来,这听起来像是断开连接问题或超时错误,但是没有断开连接发生,也没有收到更多数据包。当我停止调试并检查套接字时,没有发现异常。

1 个答案:

答案 0 :(得分:1)

如果我以正确的方式理解了您的问题,则您有一台带有两个串行端口的计算机,每个串行端口运行一个Modbus客户端和服务器实例。从这些目的中的每一个,然后转到STM32板,它们在其串行端口上接收数据,并转发到将它们相互连接的以太网上的TCP。

说起来不容易,但是根据您描述的症状,它肯定看起来像是出现一个或多个超时问题,很可能是串行问题。我认为,如果不进行测试就无法帮助您查明代码中到底有什么问题,如果您不能展示完整的功能片段,肯定不会那么容易。

但是,您可以进行很多改进的是调试方面。 您可以尝试使用为您提供更多详细信息的工具替换 modbustools

获取其他调试信息的最简单解决方案是使用pymodbus,您只需要使用pip安装库并使用examples随附的客户端和服务器。您唯一需要做的修改就是将它们更改为对串行接口添加注释和取消注释的几行。这将为您提供非常有用的调试详细信息。

如果您的计算机上有C开发环境,则最好使用libmodbus。这个库有一组奇妙的unit tests。同样,您只需要编辑代码来设置串行端口的名称并运行服务器和客户端。

最后,我不知道这对您有多大帮助,但您可能想看看SerialPCAP。使用此工具,您可以点击RS-485总线并查看在其上运行的所有查询和响应。我想您有RS-232,它是点对点的,不能与总线上的三个设备一起使用。如果是这样,您可以尝试port forwarding

编辑:更仔细地阅读您的问题,我发现这句话特别麻烦:

  

...检测接收到的一个字节,开始超时,当超时结束时,通过已连接到服务器的TCP套接字发送接收到的所有信息...

您为什么需要引入这种人为延迟?在Modbus中,您有定义明确的软件包,可以通过最小3.5帧间隔来识别,这是 timeout 的意思吗?

无关,但我还记得有一个serial forwarder example包含 pymodbus ,它可能会以某种方式对您有所帮助(也许您可以使用它来模拟您的一个板子?)。 / p>