Main Content

为 TCP/IP 或串行外部模式通信创建传输层

本节帮助您使用自己的底层通信层通过外部模式连接到自定义目标。本节主题包括:

  • 外部模式的设计和操作概述

  • 外部模式源文件说明

  • 修改外部模式源文件和编译可执行文件以处理默认 ext_comm MEX 文件任务的规范

本节假设您熟悉 Simulink® Coder™ 程序的执行过程和外部模式的基本操作。

外部模式的设计

Simulink 引擎与目标系统之间的外部模式通信基于一种客户端/服务器架构。客户端(Simulink 引擎)发送消息,请求服务器(目标)接受参数更改或上传信号数据。服务器通过执行请求来作出响应。

低级传输层处理消息的物理传输。Simulink 引擎和模型代码都独立于此传输层。传输层和直接与传输层对接的代码被分别隔离在不同的模块中,这些模块负责格式化、发送和接收消息及数据包。

此设计使不同的目标可以使用不同的传输层。GRT、ERT 和 RSim 目标通过使用 TCP/IP 和 RS-232(串行)通信来支持主机/目标通信。Simulink Desktop Real-Time™ 目标支持共享内存通信。Wind River® Systems Tornado® 目标仅支持 TCP/IP。

Simulink Coder 产品为客户端和服务器端外部模式模块提供了完整的源代码,如 GRT、ERT、快速仿真和 Tornado 目标以及 Simulink Desktop Real-TimeSimulink Real-Time™ 产品使用的源代码。客户端主模块为 ext_comm.c。服务器端主模块为 ext_svr.c

这两个模块通过以下源文件调用指定的传输层。

内置传输层实现

协议

客户端还是服务器?

源文件

TCP/IP

客户端(主机)

服务器(目标)

串行

客户端(主机)

服务器(目标)

对于串行通信,模块 ext_serial_transport.crtiostream_serial.c 实现客户端传输功能,模块 ext_svr_serial_transport.crtiostream_serial.c 实现对应的服务器端功能。对于 TCP/IP 通信,模块 rtiostream_interface.crtiostream_tcpip.c 同时实现客户端和服务器端功能。您可以编辑这些文件的副本(但不能修改原件)。您可以使用以下模板创建类似的文件,从而使用自己的底层通信层来支持外部模式:

  • 客户端(主机):matlabroot/toolbox/coder/rtiostream/src/rtiostreamtcpip/rtiostream_tcpip.c (TCP/IP) 或 matlabroot/toolbox/coder/rtiostream/src/rtiostreamserial/rtiostream_serial.c(串行)

  • 服务器端(目标):matlabroot/toolbox/coder/rtiostream/src/rtiostreamtcpip/rtiostream_tcpip.c (TCP/IP) 或 matlabroot/toolbox/coder/rtiostream/src/rtiostreamserial/rtiostream_serial.c(串行)

rtiostream_interface.c 文件是外部模式协议和 rtiostream 通信信道之间的接口。有关实现和测试 rtiostream 通信信道的详细信息,请参阅:

可以使用文档中介绍的接口实现您的 rtiostream 通信信道,以免更改文件 rtiostream_interface.c 或与外部模式有关的其他文件。

注意

不能修改工作源文件。请使用 /custom/rtiostream 文件夹中提供的模板作为起点并遵照其中的说明进行操作。

您只需要提供实现底层通信的代码,不需要担心主机与目标之间的数据转换或消息的格式等问题。这些工作由 Simulink Coder 软件完成。

在客户端(Simulink 引擎),通信由 ext_comm(对于 TCP/IP 通信)和 ext_serial_win32_comm(对于串行通信)MEX 文件来处理。

在服务器端(目标),外部模式模块链接到目标可执行文件。如果您选择外部模式,这将在代码生成时自动发生,并且是基于您指定的传输层选项。从主程序和模型执行引擎中调用的模块独立于生成的模型代码。

实现您自己的客户端底层传输协议的一般步骤如下:

  1. 编辑模板 rtiostream_tcpip.c,将底层通信调用替换为您自己的通信调用。

  2. 为您的自定义传输生成 MEX 文件可执行文件。

  3. 在 Simulink 软件中注册您的新传输层,以便能够使用“配置参数”对话框的接口窗格为模型选择该传输。

有关详细信息,请参阅创建自定义客户端(主机)传输协议

实现您自己的服务器端底层传输协议的一般步骤如下:

  1. 编辑模板 rtiostream_tcpip.c,将底层通信调用替换为您自己的通信调用。通常这涉及到为您的目标硬件编写或集成设备驱动程序。

  2. 修改模板联编文件以支持新传输。

有关详细信息,请参阅创建自定义服务器(目标)传输协议

外部模式通信概述

本节从更高的层次概述 Simulink Coder 生成的程序如何与 Simulink 外部模式进行通信。这些说明基于 Simulink Coder 产品附带的 TCP/IP 版外部模式。

要进行通信,服务器(目标)程序和 Simulink 软件都必须处于正在执行的状态。这并不是说服务器系统中的模型代码必须处于正在执行的状态。服务器可以处于等待 Simulink 引擎发出命令以开始执行模型的状态。

客户端和服务器使用携带数据包的双向套接字进行通信。数据包由消息(命令、参数下载和响应)或数据(信号上传)构成。

如果使用 -w 命令行选项调用目标应用程序,程序将进入等待状态,直到它从主机收到消息为止。否则,程序将开始执行模型。当目标应用程序处于等待状态时,Simulink 引擎可以将参数下载到目标并配置数据上传。

当用户从仿真菜单中选择连接到目标选项时,主机将通过发送 EXT_CONNECT message 来启动握手。服务器使用与自身相关的信息来作出响应。这些信息包括:

  • 校验和。主机使用模型校验和来确定目标代码是否准确表达了当前的 Simulink 模型。

  • 数据格式信息。当要下载格式设置数据或解释已上传的数据时,主机会使用此信息。

至此,主机和服务器就建立了连接。服务器要么正在执行模型,要么处于等待状态。(在后一种情况下,用户可从仿真菜单中选择启动实时代码开始执行模型。)

在执行模型的过程中,消息服务器作为后台任务运行。此任务负责接收和处理消息,如参数下载。

数据上传包括信号数据包的前台执行和后台服务。当目标计算模型输出时,它也会将信号值复制到数据上传缓冲区中。这是与每个任务标识符 (tid) 关联的任务的一部分。因此,数据收集发生在前台,而收集到的数据的传输发生在后台。后台任务使用数据包将数据收集缓冲区中的数据发送给 Simulink 引擎。

主机以消息的形式启动大多数交换。目标通常会发送响应,确认它已收到并处理了消息。消息和命令的示例包括:

  • 连接消息/连接响应

  • 开始目标仿真/开始响应

  • 参数下载/参数下载响应

  • 装载数据上传触发器/装载触发器响应

  • 终止目标仿真/目标关闭响应

当模型到达最终时间、主机发送终止命令或 Stop Simulation 模块终止模型执行时,模型执行将终止。终止后,服务器将通知主机模型执行已停止并关闭其套接字。主机也关闭其套接字并退出外部模式。

外部模式源文件

客户端(主机)MEX 文件接口源文件

除非另有说明,MEX 文件接口组件的源文件保存在 matlabroot/toolbox/coder/simulinkcoder_core/ext_mode/host 文件夹(打开)中:

  • common/ext_comm.c

    此文件是外部模式通信的核心。它相当于目标和 Simulink 引擎之间的一个中继站。ext_comm.c 使用一个共享的数据结构体 ExternalSim 与 Simulink 引擎通信,并通过调用传输层与目标通信。

    ext_comm.c 执行的任务包括建立与目标的连接、下载参数以及终止与目标的连接。

  • common/rtiostream_interface.c

    此文件是外部模式协议和 rtiostream 通信信道之间的接口。有关实现 rtiostream 通信信道的详细信息,请参阅Communications rtiostream API。可以使用文档中介绍的接口实现您的 rtiostream 通信信道,以免更改文件 rtiostream_interface.c 或与外部模式有关的其他文件。

  • matlabroot/toolbox/coder/rtiostream/src/rtiostreamtcpip/rtiostream_tcpip.c

    此文件实现必需的 TCP/IP 传输层函数。Simulink Coder 软件附带的 rtiostream_tcpip.c 版本使用的 TCP/IP 函数包括 recv()send()socket()

  • matlabroot/toolbox/coder/rtiostream/src/rtiostreamserial/rtiostream_serial.c

    此文件实现必需的串行传输层函数。Simulink Coder 软件附带的 rtiostream_serial.c 版本使用的串行函数包括 ReadFile()WriteFile()CreateFile()

  • serial/ext_serial_transport.c

    此文件实现必需的串行传输层函数。ext_serial_transport.c 包括 matlabroot/rtw/c/src/ext_mode/serial 文件夹(打开)中的 ext_serial_utils.c,还包含一些客户端和服务器端通用的函数。

  • common/ext_main.c

    此文件是外部模式的 MEX 文件包装器。ext_main.c 使用标准 mexFunction 调用与 Simulink 引擎对接。(有关详细信息,请参阅 mexFunction 参考页和将 MATLAB 与外部编程语言和系统集成。)ext_main.c 包含函数调度器 esGetAction,它将来自 Simulink 引擎的请求发送给 ext_comm.c

  • common/ext_convert.cext_convert.h

    此文件包含用于将数据从主机格式转换为目标格式(或反之)的函数。它们实现的功能包括字节交换(从 big-endian 到 little-endian)、从非 IEEE® 浮点转换为 IEEE 双精度以及其他转换。这些函数可由 ext_comm.c 和 Simulink 引擎调用,后者通过函数指针直接调用这些函数。

    注意

    您不需要通过自定义 ext_convert 来实现自定义传输层,但可能需要为所需的目标自定义 ext_convert。例如,如果目标以 Texas Instruments® 格式表示 float 数据类型,则必须修改 ext_convert 以执行从 Texas Instruments 到 IEEE 的转换。

  • common/extsim.h

    此文件定义 ExternalSim 数据结构体和访问宏。该结构体用于在 Simulink 引擎和 ext_comm.c 之间通信。

  • common/extutil.h

    此文件只包含编译 assert 宏的条件句。

  • common/ext_transport.h

    此文件定义传输层必须实现的函数。

服务器(目标)源文件

这些文件链接到 model.exe 可执行文件。除非另有说明,它们保存在 matlabroot/rtw/c/src/ext_mode 文件夹(打开)中。

  • common/ext_svr.c

    ext_svr.c 类似于主机上的 ext_comm.c,但它通常负责执行更多任务。它相当于主机和生成的代码之间的一个中继站。就像 ext_comm.c 一样,ext_svr.c 也执行诸如建立和终止主机连接之类的任务。ext_svr.c 还包含后台任务函数,用于将下载的参数写入目标模型,或从目标数据缓冲区中提取数据并发送回主机。

  • common/rtiostream_interface.c

    此文件是外部模式协议和 rtiostream 通信信道之间的接口。有关实现 rtiostream 通信信道的详细信息,请参阅Communications rtiostream API。可以使用文档中介绍的接口实现您的 rtiostream 通信信道,以免更改文件 rtiostream_interface.c 或与外部模式有关的其他文件。

  • matlabroot/toolbox/coder/rtiostream/src/rtiostreamtcpip/rtiostream_tcpip.c

    此文件实现必需的 TCP/IP 传输层函数。Simulink Coder 软件附带的 rtiostream_tcpip.c 版本使用的 TCP/IP 函数包括 recv()send()socket()

  • matlabroot/toolbox/coder/rtiostream/src/rtiostreamserial/rtiostream_serial.c

    此文件实现必需的串行传输层函数。本软件附带的 rtiostream_serial.c 版本使用的串行函数包括 ReadFile()WriteFile()CreateFile()

  • matlabroot/toolbox/coder/rtiostream/src/rtiostream.h

    此文件定义 rtiostream_tcpip.c 中实现的 rtIOStream* 函数。

  • serial/ext_svr_serial_transport.c

    此文件实现必需的串行传输层函数。ext_svr_serial_transport.c 包括 serial/ext_serial_utils.c,它包含客户端和服务器端通用的函数。

  • common/updown.c

    updown.c 处理与目标模型交互的细节。在下载参数的过程中,updown.c 负责将新参数安置到模型的参数向量中。对于数据上传,updown.c 包含的函数可从模型的 blockio 向量中提取数据,并将数据写入上传缓冲区。updown.c 同时为 ext_svr.c 和模型代码(例如 grt_main.c)提供服务。它包含使用 ext_svr.c 的后台任务调用的代码,还包含作为高优先级模型执行的一部分调用的代码。

  • matlabroot/rtw/c/src/dt_info.h(包含在生成的模型编译文件 model.h 中)

    这些文件包含用于在不同的计算机架构之间访问多数据类型结构体的数据类型转换信息。此信息用于在主机格式和目标格式之间进行数据转换。

  • common/updown_util.h

    此文件只包含编译 assert 宏的条件句。

  • common/ext_svr_transport.h

    此文件定义必须由服务器(目标)传输层实现的 Ext* 函数。

服务器文件夹中的其他文件

  • common/ext_share.h

    包含主机和目标模块需要的消息代码定义和其他定义。

  • serial/ext_serial_utils.c

    包含串行协议传输层的主机和目标模块需要的 MEX 链接、生成的代码以及用于通信的函数和数据结构体。

  • 串行传输实现包括以下附加文件:

    • serial/ext_serial_pkt.cext_serial_pkt.h

    • serial/ext_serial_port.h

实现自定义传输层

自定义传输层的要求

  • 虽然有用于预分配静态内存的选项,但默认情况下,ext_svr.cupdown.c 使用 malloc 在目标内存中分配缓冲区用于消息、数据收集和其他用途。如果您的目标使用其他内存分配方案,则必须修改这些模块。

  • 假设目标同时支持 int32_Tuint32_T 数据类型。

创建自定义客户端(主机)传输协议

要实现底层传输协议的客户端(主机),请执行以下操作:

  1. 编辑模板文件 matlabroot/toolbox/coder/rtiostream/src/rtiostreamtcpip/rtiostream_tcpip.c,将底层通信调用替换为您自己的通信调用。

    1. 复制该文件并将其重命名为 rtiostream_name.c(将 name 替换为对您有意义的名称)。

    2. 用相同的名称将函数 rtIOStreamOpenrtIOStreamClosertIOStreamSendrtIOStreamRecv 替换为调用您的底层通信基元的函数。您可以通过 rtiostream_interface.c 从其他外部模式模块中调用这些函数。有关详细信息,请参阅Communications rtiostream API

    3. 将您的 rtiostream 实现编译成共享库,以导出 rtIOStreamOpenrtIOStreamClosertIOStreamRecvrtIOStreamSend 函数。

  2. 使用 MATLAB® mex 函数编译自定义的 MEX 文件可执行文件。有关 mex 调用的示例,请参阅用于重新编译 ext_comm 和 ext_serial_win32 MEX 文件的 MATLAB 命令

    如果要保留现有 ext_comm MEX 文件的功能,则不要替换该文件。在这种情况下,请使用 -output 选项命名新的可执行文件,例如,my_ext_comm。有关详细信息,请参阅 mex

  3. 在 Simulink 软件中注册您的新客户端传输层,以便能够使用“配置参数”对话框的接口窗格为模型选择该传输。有关详细信息,请参阅注册自定义客户端(主机)传输协议

用于重新编译 ext_comm 和 ext_serial_win32 MEX 文件的 MATLAB 命令列出了用于重新编译外部模式 MEX 文件的示例命令。

用于重新编译 ext_comm 和 ext_serial_win32 MEX 文件的 MATLAB 命令

下表列出了在 PC 和 UNIX® 平台上编译标准 ext_commext_serial_win32 模块的命令。

平台

命令

Windows®,TCP/IP

cd (matlabroot)
mex toolbox/coder/simulinkcoder_core/ext_mode/host/common/ext_comm.c ...
toolbox/coder/simulinkcoder_core/ext_mode/host/common/ext_convert.c ...
toolbox/coder/simulinkcoder_core/ext_mode/host/common/rtiostream_interface.c ...
toolbox/coder/simulinkcoder_core/ext_mode/host/common/ext_util.c ...
-R2018a ...
-Itoolbox/coder/rtiostream/src ...
-Itoolbox/coder/rtiostream/src/utils_host ...
-Itoolbox/coder/simulinkcoder_core/ext_mode/host/common/include ...
-Irtw/c/src/ext_mode/common ...
-lmwrtiostreamutils -lmwsl_services ...
-DEXTMODE_TCPIP_TRANSPORT ...
-DSL_EXT_DLL -output my_ext_comm

注意

rtiostream_interface.c 函数将 RTIOSTREAM_SHARED_LIB 定义为 libmwrtiostreamtcpip,并动态加载 MathWorks TCP/IP rtiostream 共享库。如果需要加载其他 rtiostream 共享库,请修改此文件。

Linux®,TCP/IP

使用 Windows 命令并进行以下更改:

  • -DSL_EXT_DLL 更改为 -DSL_EXT_SO

  • 用正斜杠替换反斜杠。

Mac,TCP/IP

使用 Windows 命令并进行以下更改:

  • -DSL_EXT_DLL 更改为 -DSL_EXT_DYLIB

  • 用正斜杠替换反斜杠。

Windows,串行

cd (matlabroot)
mex toolbox\coder\simulinkcoder_core\ext_mode\host\common\ext_comm.c ...
toolbox\coder\simulinkcoder_core\ext_mode\host\common\ext_convert.c ...
toolbox\coder\simulinkcoder_core\ext_mode\host\serial\ext_serial_transport.c ...
toolbox\coder\simulinkcoder_core\ext_mode\host\serial\ext_serial_pkt.c ...
toolbox\coder\simulinkcoder_core\ext_mode\host\serial\rtiostream_serial_interface.c ...
toolbox\coder\simulinkcoder_core\ext_mode\host\common\ext_util.c ...
-R2018a ...
-Itoolbox\coder\rtiostream\src ...
-Itoolbox\coder\rtiostream\src\utils_host ...
-Itoolbox\coder\simulinkcoder_core\ext_mode\host\common ...
-Itoolbox\coder\simulinkcoder_core\ext_mode\host\common\include ...
-Irtw\c\src\ext_mode\common ...
-Irtw\c\src\ext_mode\serial ...
-lmwrtiostreamutils -lmwsl_services ...
-DEXTMODE_SERIAL_TRANSPORT -DSL_EXT_DLL ...
-output my_ext_serial_comm

注意

rtiostream_interface.c 函数将 RTIOSTREAM_SHARED_LIB 定义为 libmwrtiostreamserial,并动态加载 MathWorks 串行 rtiostream 共享库。如果需要加载其他 rtiostream 共享库,请修改此文件。

Linux,串行

使用 Windows 命令并进行以下更改:

  • -DSL_EXT_DLL 更改为 -DSL_EXT_SO

  • 用正斜杠替换反斜杠。

Mac,串行

使用 Windows 命令并进行以下更改:

  • -DSL_EXT_DLL 更改为 -DSL_EXT_DYLIB

  • 用正斜杠替换反斜杠。

注意

mex 要求使用 MATLAB API 支持的编译器。有关 mex 函数的详细信息,请参阅 mex 参考页和将 MATLAB 与外部编程语言和系统集成

注册自定义客户端(主机)传输协议

要在 Simulink 软件中注册自定义客户端传输协议,必须将以下形式的条目添加到 MATLAB 路径上的 sl_customization.m 文件中:

function sl_customization(cm)
  cm.ExtModeTransports.add('stf.tlc', 'transport', 'mexfile', 'Level1');
% -- end of sl_customization

其中

  • stf.tlc 是要注册传输协议的系统目标文件的名称(例如,'grt.tlc'

  • transport 是要在“配置参数”对话框的接口窗格的传输层菜单中显示的传输协议的名称(例如,'mytcpip'

  • mexfile 是传输协议的关联外部接口 MEX 文件的名称(例如,'ext_mytcpip_comm'

您可以通过增加 cm.ExtModeTransports.add 行来指定多个目标和/或传输,例如:

function sl_customization(cm)
  cm.ExtModeTransports.add('grt.tlc', 'mytcpip', 'ext_mytcpip_comm', 'Level1');
  cm.ExtModeTransports.add('ert.tlc', 'mytcpip', 'ext_mytcpip_comm', 'Level1');
% -- end of sl_customization

如果您将包含传输协议注册信息的 sl_customization.m 文件放在 MATLAB 路径上,将在后续每个 Simulink 会话中注册您的自定义客户端传输协议。传输协议的名称将显示在“配置参数”对话框的接口窗格的传输层菜单中。当您为模型选择传输协议时,关联的外部接口 MEX 文件的名称将显示在不可编辑的 MEX 文件名字段中,如下图所示。

创建自定义服务器(目标)传输协议

matlabroot/toolbox/coder/rtiostream/src/rtiostream.h 中的 rtIOStream* 函数原型可为服务器端(目标)和客户端(主机)传输层函数定义调用接口。

  • TCP/IP 实现在 matlabroot/toolbox/coder/rtiostream/src/rtiostreamtcpip/rtiostream_tcpip.c 中。

  • 串行实现在 matlabroot/toolbox/coder/rtiostream/src/rtiostreamserial/rtiostream_serial.c 中。

注意

matlabroot/rtw/c/src/ext_mode/common/ext_svr_transport.h 中的 Ext* 函数原型在 matlabroot/rtw/c/src/ext_mode/common/rtiostream_interface.cmatlabroot/rtw/c/src/ext_mode/serial/rtiostream_serial_interface.c 中实现。大多数情况下,您不需要为自定义 TCP/IP 或串行传输层修改 rtiostream_interface.crtiostream_serial_interface.c

要实现底层 TCP/IP 或串行传输协议的服务器端(目标),请执行以下操作:

  1. 编辑模板 matlabroot/toolbox/coder/rtiostream/src/rtiostreamtcpip/rtiostream_tcpip.cmatlabroot/toolbox/coder/rtiostream/src/rtiostreamserial/rtiostream_serial.c,将底层通信调用替换为您自己的通信调用。

    1. 复制该文件并将其重命名为 rtiostream_name.c(将 name 替换为对您有意义的名称)。

    2. 用相同的名称将函数 rtIOStreamOpenrtIOStreamClosertIOStreamSendrtIOStreamRecv 替换为调用您的底层通信驱动程序的函数。

      您必须实现 rtiostream.h 中定义的函数,而且您的实现必须符合该文件中定义的原型。有关指导信息,请参阅原始 rtiostream_tcpip.crtiostream_serial.c

  2. 将传输层的外部模式源文件合并到模型编译过程中。使用编译过程机制(如生成代码之后执行的命令或 before_make 钩子函数)使传输文件在编译过程中可用。有关编译过程机制的详细信息,请参阅Customize Post-Code-Generation Build Processing使用 STF_make_rtw_hook 文件自定义编译过程Customize Build Process with sl_customization.m

    例如:

    • 将上一步创建的文件添加到编译信息中:

      path/rtiostream_name.c
    • 对于 TCP/IP 传输协议,请将以下文件添加到编译信息中:

      matlabroot/rtw/c/src/ext_mode/common/rtiostream_interface.c
    • 对于串行传输协议,请将以下文件添加到编译信息中:

      matlabroot/rtw/c/src/ext_mode/serial/ext_serial_pkt.c
      matlabroot/rtw/c/src/ext_mode/serial/rtiostream_serial_interface.c
      matlabroot/rtw/c/src/ext_mode/serial/ext_svr_serial_transport.c

注意

对于外部模式,请检查并确保 rtIOStreamRecv 不是一个阻碍因素。否则,可能会导致外部模式服务器被阻拦,直到主机通过 comm 层发送数据为止。

小于 64 字节的串行接收缓冲区

对于串行通信,如果目标的串行接收缓冲区小于 64 字节,请:

  1. 使用实际的目标缓冲区大小更新以下宏:

    #define TARGET_SERIAL_RECEIVE_BUFFER_SIZE 64

    在以下文件中实现更改:

    matlabroot/rtw/c/src/ext_mode/serial/ext_serial_utils.c
    matlabroot/toolbox/coder/simulinkcoder_core/ext_mode/host/serial/ext_serial_utils.c
  2. 运行命令以重新编译 ext_serial_win32 MEX 文件。请参阅用于重新编译 ext_comm 和 ext_serial_win32 MEX 文件的 MATLAB 命令

相关主题