利用网络代理扩展1-Wire范围

描述

本文档将介绍一种使用代理将1-Wire范围扩展到近无穷大极限的方法。描述基本代理的最佳类比是想象大多数公司的代理服务器(有时称为公司防火墙)。在此设置中,只有一台计算机(代理)具有与 Internet 的实际连接,其余用户计算机只能访问代理。LAN 上用于 LAN 外部计算机的所有网络数据包在 WAN 上重复,反之亦然。这一理念可以应用到1-Wire网络上。通过代理连接到1-Wire网络需要几个软件模块:客户端模块和主机模块。主机模块是在1-Wire代理服务器(PC、MxTNI™或微控制器)上运行的代码,该服务器具有对1-Wire网络的硬件访问权限。客户端模块是在仅具有网络访问权限以访问主机模块的远程计算机上运行的代码。主机模块可能访问客户端模块,而不是对1-Wire网络的硬件访问,而客户端模块将引用另一个主机模块。通过这种方式,可以将到达1-Wire网络的代理链接在一起。

介绍

1-Wire协议的最初设计源于通过短连接与附近设备通信的愿望。尽管通过仔细考虑,可以将此连接的长度延长到比最初预期的更远,但限制仍然非常真实。

本文档将介绍一种使用代理将1-Wire范围扩展到近无穷大极限的方法。描述基本代理的最佳类比是想象大多数公司的代理服务器(有时称为公司防火墙)。通常,公司为其员工提供LAN(局域网),用于连接彼此的计算机并共享文件。公司通常需要提供一种访问互联网(非常广域网)的方法。在此设置中,只有一台计算机(代理)具有与 Internet 的实际连接,其余计算机只能访问代理。代理代表 LAN 上的所有计算机发出所有互联网数据请求。在此示例中,代理充当 WAN 和 LAN 之间的接口。LAN 上用于 LAN 外部计算机的所有网络数据包在 WAN 上“重复”,反之亦然。

1-Wire


图1.代理服务器示例。

图 1 说明了代理服务器提供的基本服务,即提供对内部计算机通常无法访问的网络的访问权限。更具体地说,可以通过 LAN 访问代理的内部计算机在没有代理帮助的情况下没有其他方式访问 WAN。通过代理服务器路由信息请求,现在可以访问以前无法访问的外部服务器。尽管很多细节都发生了变化,但同样的基本思想可以应用于1-Wire网络。图 2 说明了此应用程序的基础知识。

1-Wire


图2.1-Wire代理示例。

图2中的应用代表希望接入1-Wire网络,但无论出于何种原因无法直接访问该网络的所有应用。原因可能是它们离网络太远,或者它们在不允许硬件访问的环境中运行(即在 Java 驱动的手机上运行的 Java™ 应用程序)。由于电气限制,使用1-Wire网络的应用通常运行在距离200-Wire从器件不到1米的硬件上。在图2所示的场景中,应用只需要访问网络介质和合适的1-Wire代理服务器即可。网络介质可以是任何内容,例如 RF 无线网络、IR 点对点链路或 TCP/IP 以太网网络。得益于被称为互联网的超大型广域网,外部计算机与实际1-Wire网络之间的距离不再是问题。

概述

通过代理连接到1-Wire网络需要几个模块:客户端模块和主机模块。主机模块是在1-Wire代理服务器(PC、MxTNI或微控制器)上运行的代码,该服务器具有对1-Wire网络的硬件访问权限。客户端模块是在仅具有网络访问权限以访问主机模块的远程计算机上运行的代码。主机模块(而不是对1-Wire网络的硬件访问)可以访问客户端模块,该客户端模块将引用另一个主机模块。通过这种方式,可以将到达1-Wire网络的代理链接在一起。图3显示了1-Wire应用、客户端模块、主机模块和1-Wire网络之间的交互性。

1-Wire

图3.客户端/主机配置。

PC在1-Wire网络上的通信方式通常是使用适配器,通常使用合适的1-Wire主站来产生正确的时序。例如,DS9097U适配器使用DS2480B串行1-Wire线路驱动器芯片。PC 使用串行端口连接到 DS9097U。通过串行端口发送的命令到达DS2480B,然后转换为1-Wire网络命令。DS2480B通过PC的串行端口返回任何1-Wire网络命令的输出。但是,当通过1-Wire代理与1-Wire网络通信时,PC将调用客户端模块向主机模块发送命令。这些命令将通过网络介质(例如因特网)传输到主机模块。然后,主机模块将通过1-Wire主站与物理1-Wire网络进行通信。1-Wire通信的结果将通过网络介质返回到客户端模块的缓冲区中。

实现

发生重复的软件应用层可以是许多地方中的任何一个。1-Wire应用主要由以下几层组成:

应用—保持有关如何使用1-Wire数据的知识(即,如何将1-Wire通信块转换为以华氏度为单位的温度结果)。

演示 - 维护有关不同数据格式的知识,并将其包装到可能有用的 API 中。

传输—保持有关如何将数据块传输到1-Wire网络或从<>-Wire网络传输数据块的知识。

链路—保持如何重置1-Wire网络并传输<>或<>的知识。

在链路层安装代理需要通过网络传输串行或并行端口命令。例如,如果主机的某个串行端口上装有DS9097U适配器,则客户端模块将发送直接针对DS2480B主芯片的命令。iButton 网站上提供的串行到以太网示例(请参阅本文档末尾的链接部分)完全演示了这一原则。此示例允许电脑具有虚拟 COM 端口。发送到此虚拟COM端口的所有命令都通过网络传输到另一台设备(PC或MxTNI)。如果主机设备的串行端口上有DS9097U,则客户端可以将DS9097U视为直接连接。

在传输层安装代理的想法由IEEE® 1451.4的协议规范处理。在这一层,客户端模块不会关注用于连接1-Wire网络的实际硬件,而是将链路层视为主机处理的理所当然的东西。客户端将主要向主机传输重置命令和数据块。

最高的层,也可能是最有效的层,将是表示层。这种代理包含在1-Wire API for Java Kit中。在1-Wire API for Java中,每个适合1-Wire连接的适配器都由DSPortAdapter的一个子类表示。在面向对象的语言中,这意味着各种适配器(串行、并行或 USB)的所有实例都可以被视为其父类 DSPortAdapter 的实例。这是在面向对象程序员应该非常熟悉的演示文稿中隐藏实现的情况。由于1-Wire API中的这种设计选择,因此添加DSPortAdapter的新子类非常简单,该子类仅实现上述客户端模块。图 4 的类图中描述了此客户端模块及其与主机模块的关系。

1-Wire

图4.类交互图。

使用1-Wire代理的最大问题是数据包延迟。如果网络介质的数据包周转时间为一秒,则大多数实时应用程序根本不可能实现。理想情况下,网络数据包延迟(有时称为 PING 时间)应小于 PC 在连接外部硬件时产生的延迟。例如,如果发送到串行端口和从串行端口读取的任何数据的数据包周转时间为 20 毫秒,则 5 毫秒的网络数据包延迟几乎不会明显。如果网络数据包延迟明显更高,则可能需要更高层的实现来提高应用程序的实时响应能力。为了说明这一点,以下是链路层代理的示例数据包交换可能的样子:

 

Client Module transmits a serial write command to reset the DS2480B
        Packet = {XMIT_SERIAL, DS2480B_COMMAND_MODE, DS2480B_CMD_RESET}

Server Module writes bytes to serial port.

Client Module transmits a serial read command with a number of bytes to read
        Packet = {RECV_SERIAL, NUM_BYTES_TO_RECV}

Server Module transmits bytes read from serial port, representing return value of reset command
        Packet = {NUM_BYTES_TO_RECV, however many bytes...}

Client Module interprets return value

对于发送的每个数据包,为数据包延迟添加一个乘数。如果以这种方式连续多次调用DS9097U,很明显,它可以相当快地增加大量网络流量。在表示层,可以按如下方式再现完全相同的1-Wire活动:

 

Client Module transmits reset command
        Packet = {ADAPTER _CMD_RESET}

Server Module transmits reset command to serial port. Then reads bytes back from serial port, and
interprets the return value of reset command. Server Module transmits return value
        Packet = {RET_SUCCESS}
 

将1-Wire代理实现方案移至应用层可以显著减少数据包延迟问题。但是,由于这一层的实现是高度不可移植的(即,应用层的实现本质上与特定应用程序绑定),因此目前没有可用的参考实现。为了便于说明,让我们检查一下与一个特定应用的区别:温度轮询。用于温度转换的可能网络数据包交换将在链路层和表示层生成大量数据包。需要发送“1-Wire复位”命令、“匹配ROM”命令和“执行温度转换”命令。客户端模块将负责解释每个命令的返回值,因为它以网络数据包的形式从主机模块接收。如果在应用层实施1-Wire代理,则客户端模块只需发送“执行完整温度转换”命令。来自服务器的返回值(在单个数据包中)可能只是温度转换的结果。

软件接口示例

在1-Wire API for Java Kit中使用客户端模块非常简单,只需创建NetAdapter的实例并将连接字符串传递给初始化方法即可。连接字符串的格式为:

::

主机名是运行主机模块的 PC(或 MxTNI)的主机名或该计算机的 IP 地址。端口是主机正在侦听的 TCP/IP 端口。共享密钥用于简单形式的身份验证。当客户端模块连接到主机模块时,主机会向客户端发出随机质询。然后,客户端查找随机质询字节和共享密钥的 CRC-16。然后将此CRC-16传输回主机进行验证。如果 CRC-16 与主机计算的内容匹配,则认为用户已通过身份验证。请注意,NetAdapter 中还有一种附加的初始化方法,该方法允许通过接受已建立的 TCP/IP 套接字(可能是加密连接)来执行进一步的步骤来保护连接。

在1-Wire API for Java Kit中,有一个示例程序可以简化主机模块的使用。此应用程序将主机模块的所有参数作为命令行上的参数,并使用这些参数创建 NetAdapterHost 的实例。桌面和 MxTNI 都包含预构建的二进制文件。图 5 显示了在 COM9097 串行端口上使用 DS1U 适配器在桌面上启动主机模块的命令行。当前工作目录是1-Wire API for Java Kit中StartNetAdapterHost的应用程序文件夹。

java -cp ".;" StartNetAdapterHost -adapterName DS9097U
        -adapterPort COM1 -listenPort 6161 -secret "this is my secret"

图5.在 PC 上启动主机模块。

在 PC 上执行图 5 中所示的行将启动 NetAdapterHost,它将在端口 6161 上创建一个侦听 TCP/IP 套接字。用于简单身份验证的共享密钥是“这是我的密钥”。在 MxTNI 上启动主机模块几乎相同。只需将 StartNetAdapterHost.tini 文件通过 ftp 到 MxTNI 机器即可。然后登录并使用图 6 中所示的命令行。

java StartNetAdapterHost.tini -adapterName TINIExternalAdapter
        -adapterPort serial1 -listenPort 6161 -secret "this is my secret"

图6.在 MxTNI 上启动主机模块。

主机模块启动后,将接受来自客户端模块的传入连接。数字 图8所示为远程温度演示,演示如何连接到主机并与1-Wire器件交互。此应用程序将连接到指定的主机并查找任何温度设备。它 然后轮询每个设备,并以摄氏度和华氏度显示当前温度。自 使用示例应用,只需将代码复制并粘贴到名为 RemoteTemperatureDemo.java 的文件中即可。 更改类顶部的常量以反映实际设置(即,确保主机名 变量具有启动 NetAdapterHost 的计算机的主机名)。然后执行 图 7 中所示的命令来编译和执行此类。

javac -classpath ".;" RemoteTemperatureDemo.java

java -classpath ".;" RemoteTemperatureDemo

图7.编译并运行远程温度演示。

该程序的输出应为找到的每个温度器件的64位1-Wire地址,后跟当前温度。如果未找到设备,将显示一条错误消息,指示这一点。

有关使用 NetAdapter 和 NetAdapterHost 的更多信息,请参阅这些类的 JavaDocs。所有1-Wire类的JavaDocs都包含在1-Wire API for Java Kit中。

 

import com.dalsemi.onewire.adapter.*;
import com.dalsemi.onewire.container.*;
import com.dalsemi.onewire.utils.*;
import java.util.Enumeration;

public class RemoteTemperatureDemo {
        // update these variables to reflect your setup
        public static final String hostname = "shughes.dalsemi.com";
        public static final int port = 6161;
        public static final String secret = "this is my secret";

        public static void main (String[] args) {
                OneWireContainer owc = null;
                TemperatureContainer tc = null;

                // create the NetAdapter object
                NetAdapter adapter = new NetAdapter();

                try {
                        // connect to the NetAdapterHost
                        adapter.selectPort(hostname + ":" + port + ":" + secret);
                        adapter.beginExclusive(true);

                        // find the first temperature device
                        Enumeration e = adapter.getAllDeviceContainers();
                        while (tc==null && e.hasMoreElements()) {
                                // get the next container
                                owc = (OneWireContainer)e.nextElement();
                                // check if it is a temperature device
                                if(owc instanceof TemperatureContainer) {
                                        tc = (TemperatureContainer)owc;
                                        System.out.println("Device: " + owc.getAddressAsString());

                                        // poll the temperature device
                                        byte[] state = tc.readDevice();
                                        tc.doTemperatureConvert(state);
                                        double temp = tc.getTemperature(state);

                                        // display temeprature result
                                        System.out.print(" " + temp + " C (");
                                        System.out.println(Convert.toFahrenheit(temp) + " F)");
                                }
                        }
                        
                        // if no temperature devices were found
                        if(tc==null)
                                System.out.println("No temperature devices found!");
                } catch (Exception e) {
                        System.out.println(e.getMessage());
                } finally {
                        adapter.endExclusive();
                        try {
                                adapter.freePort();
                        } catch(Exception e) {;}
                }
        }
}

图8.远程温度演示。

审核编辑:郭婷


打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分