用XML实现1-Wire®标签

用XML实现1-Wire®标签

作者联系方式

摘要

本文介绍XML中的1-Wire标签格式,它用来描述组织、分组以及检测操作。可以把1-Wire标签想象成驻留在一个传统数据库中的数据,或者是硬盘、甚至是1-Wire器件存储器中的一个文件。此数据指明1-Wire器件的用途、位置和服务及操控需要的特定的软件类别。利用1-Wire器件簇承载1-Wire标签,一个簇在连接到新的主控制器时可以自我描述和自动配置。

绪论

Maxim所有1-Wire器件以及iButton®产品,都被指定了各自唯一的64位1-Wire网络地址值。每个地址值光刻在每片器件的只读存储器中。Maxim管理着达1019个之多的地址数值池,保证了分配给每片器件的地址值都是唯一的。

一旦用户从Maxim买到这些1-Wire器件,他们中的大多数会将1-Wire网络地址值与一个实体对象联系起来。然后将此地址值存入数据库中,并用于实体对象的跟踪过程中。随着一些更复杂的、可执行一些精密复杂的检测操作而不是仅仅局限于对象跟踪的1-Wire器件的出现,已经可以对对象进行分析甚至操控。这些用法结合将1-Wire器件按实现系统功能分组成簇的要求形成了对1-Wire标签方案的需要。

假想一个有两个开关的1-Wire网络的情形。其中一个开关用来隔开由其它一些1-Wire器件组成的一个分支,而另一个用来打开一个有高度安全要求的门。1-Wire控制软件不通过尝试难以区别这两个开关的差异。但如果做此尝试,则可能意外打开高度安全的门。如果1-Wire控制软件不能事先知道这两个开关的不同用途,在上述情形中会使安全性大打折扣。解决这一问题的办法就是利用1-Wire标签。

此篇文档将介绍1-Wire标签格式,它用来描述在前面提到的组织、分组以及检测操作。可把1-Wire标签想象成驻留在一个传统数据库中的数据,或是硬盘上甚至是1-Wire器件存储器中的一个文档。此数据指明1-Wire器件的用途、位置和服务及操控需要的特定的软件类别。利用1-Wire标签中关于1-Wire器件簇的部分,使得一个簇在连接到新操控应用时可以按簇进行自我描述和自动配置。

掌握这种1-Wire标签方案需要读者对XML的基础知识有一定的了解。若要进一步了解XML,请访问万维网联盟(W3C)的网站:www.w3.org。W3C是定义XML的工业标准理事机构。网上还有一些XML的培训材料,可从下列网址找到:www.w3schools.com/xml/default.asphttp://java.sun.com/j2ee/1.3/docs/tutorial/doc/IntroXML2.html

1-Wire标签规范

此处定义的1-Wire标签文档规格可以存储于1-Wire检测器上的文档中(实际地)或是其它的诸如在主机(本地)或是服务器(远程)数据库的文档系统中。当这个文档驻留在属于某1-Wire簇的1-Wire器件的存储器中时(实际地),则必须是具有1-Wire文档格式的文档。这种文档可存储于类似DS1993、DS2406或是DS2433的任何1-Wire存储器器件中。关于1-Wire文档格式 的说明可参考Maxim的应用笔记114,"1-Wire File Structure"。

1-Wire标签文档中包含了在XML中用来描述1-Wire器件特性和操作和/或一个或多个1-Wire器件簇的数据。1-Wire标签文档中的内容由应用程序来进行解析获得适用于有关器件或簇的特性和操作、以及为甚至包括未知组成的检测器簇在内的器件提供自注册能力。在1-Wire器件中建议将此文档命名为TAGX.000。

1-Wire标签定义

一个1-Wire标签是一个有效的XML数据对象(可以想象成一个文档或是数据流),它包含事先定义好的用来描述1-Wire器件或描述由1-Wire器件组成的簇的多个XML元素及属性。这些XML数据对象由应用程序(例如Java程序)读取和解析,并且软件目标被创建用来读取、操纵1-Wire器件,指出该器件与其它器件不同关系或说明其在1-Wire网络上的位置的软件对象。

设计目标

下面是关于制定这一规范时所贯彻的设计目标简表。

  1. 在设计XML 1-Wire标签时,要尽可能小且同时应保持人工可读性。

    1. 保持1-Wire标签元素要小。
    2. 在将标签文档写入到1-Wire器件中时,要清除掉所有多余的空白空间。
    3. 在小容量存储器的情况下,使用叫做缩微标签的内容空白的XML元素。
  2. 主机应用程序应能解析多重1-Wire标签,以便描述整个1-Wire网络;多重标签既可驻留在本地、远端,也可驻留在1-Wire器件本身中。
  3. 在解析1-Wire标签时,主机应用程序需要创建可充分描述、读取和操纵每片已标记1-Wire器件的一系列软件对象。此系列应尽量保持“平展”、简易、并尽可能小。主机应用程序需要返回1-Wire网络分支和嵌套分支拓扑构造数据。
  4. 利用任一已有的标准API实现与1-Wire器件的通信。有三种API可用:面向Java的1-Wire API、TMEX以及1-Wire网络公众域组件。关于以上三个API的详细资料可从下述网址找到:https://www.analog.com/cn/product-category/ibutton-products.html。面向Java的1-Wire API 1.00 Alpha版及更高版本中包括一个本文所述的1-Wire标签格式的参考例程作为它的API的一部分。请注意此参考例程不一定要完全符合本文规范。
  5. 使用XML简化API (SAX),用基于事件的解析器来解析XML标签。由于其占用空间小并且不需要在存储器中保存大的数据对象,使用SAX能使小器件(包括MxTNI和手持设备)可使用本文档中描述的1-Wire XML标签格式。到撰写本文时,已经证实了至少两个基于SAX的XML解析器能在MxTNI上成功的运行,可以利用其进行设计验证。第一个解析器是MinML,可从以下网址获得:www.wilson.co.uk/,它专为MxTNI设计;第二个是NanoXML,可从以下网址获得:http://nanoxml.sourceforge.net

父元素

有四个用来构成1-Wire标签文档的XML父元素。在本规范中1-Wire器件可被归类为三种不同的对象之一(统称器件标签),这就是前三个XML父元素:分支(branch)检测器(sensor)执行器(actuator)。第四个元素是簇(cluster),它代表所标记器件的一个特定分组。请记住XML的特性是区分大小写的,并且这些父元素要小写。

分支

一个标签为分支的器件代表的是Maxim的1-Wire开关产品系列(DS2406DS2408DS28EA00等)。可以把一个1-Wire网络看作是树形,要对某个特定的已标记器件进行读取或操作,就必须通过一些分支来完成,下面是个XML分支元素的实例。

例1. XML分支元素

<branch addr="77000000023CEC12">
        <label>Weather Station Switch</label>
        <channel>1</channel>
        <init>0</init>
                .
                .
                .
        (其它的检测器执行器分支可放在这里)
                .
                .
                .
</branch>

XML元素<branch>由唯一的addr属性连同至少三个子元素<label>、<channel>和<init>一起组成。addr的属性值就是标记器件的1-Wire网络地址;子元素<label>是分支的文本描述;第二个子元素<channel>用来指出要关掉标记器件上的这个数字所代表的开关;<init>是用来表示开关初始状态的一个数字。

还可能有其它的子元素,它们可以是<sensor>、<actuator>甚至是另外的<branch>元素;请注意分支是可以嵌套的。

检测器

一个标签为检测器的器件代表任意一个能用来“读取”或是“检测”某些事情的1-Wire器件。这些事情可能简单到检测一片特定的1-Wire器件是否在1-Wire总线上,也可能复杂到从许多个不同已有温度计器件中的一个来读取一个温度值。以下是关于XML中检测元素的实例。

例2. 检测器XML元素

<sensor addr="DD0000020057A101" type="Contact">
        <label>Northeast</label>
        <max>Making contact</max>
        <min>No contact</min>
</sensor>

XML的<sensor>元素包括两条属性,addrtype,与它们一起的子元素对于特定的类型来说被认为是必要的。其中,addr的属性值就是所标记器件的1-Wire网络地址。type作为第二个属性指的是检测器的类型。在解析XML文档时,type属性将决定为这个特定的类型创建哪类软件对象。在上面的例子中,检测器的类型是“Contact”,根据此“Contact”类型(请查看本篇文档中的 表1,题为“每种类型用到的子元素”)决定了后面的子元素必须是:<label>、<max>和<min>。;

子元素<label>就是检测器的文本描述;子元素<max>是用来描述处在一定状态下的标记器件出现何种状况的一种文本消息。在此例中,<max>表明了所标记器件出现在1-Wire总线上。类似的,子元素<min> (通常与<max>相反)也是一种文本信息,只不过它是用来描述所标记器件未连接到1-Wire总线上时的状态。

执行器

执行器代表任意一种可被执行动作或过程的被标记器件。它可以简单到翻转一个开关和使蜂鸣器发出声音,也可以复杂到设定1-Wire电位器滑动触点的值和调整房间里灯光的亮度。以下是关于XML中执行器元素的实例。

例3. 执行器XML元素

<actuator addr="B700000018AE3212" type="Switch">
        <label>Buzzer</label>
        <max>Buzz!!!</max>
        <min>Sleep</min>
        <channel>0</channel>
        <init>0</init>
</actuator>

XML的<actuator>元素由两条属性组成:addrtype,与它们一起的子元素对特定的类型来说被认为是必要的。addr的属性值就是所标记器件的1-Wire网络地址;type作为第二个属性指的是执行器的类型;在上例中,是“Switch”类型。不同的执行器所含的子元素数目也不同,就拿作为“Switch”的特定执行器来说,所需的子元素有:<label>、<max>、<min>、<channel>和<init>。类型属性非常重要。在解析XML文档时,类型属性将决定为特定的标记器件创建哪一类的软件对象。关于检测器和执行器的类型的详细列表,请参阅本文档中的“类型”部分。

子元素<label>是执行器的文本描述。子元素<max>是代表一种选择或执行器可能进入的一个状态选项的文本字段,可以把它想象成应用软件中下拉菜单的一个选项。在上例中,<max>就是接通开关使蜂鸣器发出声响的选择。子元素<min>与<max>类似,只不过通常它指的内容与<max>相反,即<min>是让蜂鸣器关掉或是处于“Silent” (静音)状态的选择。

指的是一组被标记器件和/或其它簇。它由一个标签以及一条简单的XML属性“name” (名称)组成。簇还可以包含由1-Wire父元素(分支、检测器、执行器或簇)组成的子元素。因此是一种可以嵌套的元素。以下是关于XML中簇元素的实例。

例4. XML簇元素

<cluster name="Weather Station">
                .
                .       (其它元素,例如分支、检测器、执行器或者甚至是可以放在这里)。
                .
</cluster>

子元素

子元素只能结合所标记器件的父元素(<branch>、<sensor>和<actuator>)来使用。八个子元素分别是:<label>、<max>、<min>、<channel>、<init>、<scale>、<hightrip>和<lowtrip>。按照规定,所有的子元素可以属于任意一标记器件。解析成软件对象时,每个软件对象(代表一片标记器件)应该包含对应每个子元素的数据项。然而,根据所标记器件的类型属性,某些元素将不会用到。以下是关于XML子元素的实例。

例5. 子元素实例

联络实例:
<sensor addr="490000000212D016" type="Contact">
        <label>Employee 22 badge</label>
        <max>Making contact</max>
        <min>No contact</min>
</sensor>

开关实例:
<actuator addr="B700000018AE3212" type="Switch">
        <label>Buzzer</label>
        <max>Buzz!!!</max>
        <min>Sleep</min>
        <channel>0</channel>
        <init>0</init>
</actuator>

上述联络的例子说明检测器的类型是“Contact”,它用到了<label>、<max>和<min>子元素。可是,在解析时,所创建的软件对象为此特定标记器件建立的数据项中将包含所有的八个子元素。上面开关的例子标记了一个类型是“Switch”的执行器并用到了八个子元素中的五个。

注意对于每种“类型”所标记器件的来说,子元素不一定非要代表相同的事情。尽管在所有的类型中<label>元素有普遍的含义,但其它大多数元素都没有。

上面的两个例子说明了<max>和<min>子元素有着不同的含义。在联络的例子中,用<max>和<min>来描述进行“Contact”的标记器件可能存在的两种不同的状态。在开关的例子中,<max>和<min>用来作为状态选项。此处它们用来选择所标记器件可能进入的状态。最后,下面的这个实例中<max>由器件自己作为事件消息使用。

例6. 子元素<max>用法

<sensor addr="B200000018BC2A12" type="Event">
        <label>Switch #1</label>
        <max>Activity sensed!</max>
        <channel>1</channel>
</sensor>

下面的表1列出了类型和每种类型用到的子元素。其中“x”表示“用到”了的元素。

表1. 每种类型用到的子元素
Type Child Elements
label max min channel init scale hightrip lowtrip
Switch x x x x x      
Contact x x x          
Event x x   x        
Level x x x x        
Thermal x x x       x x
Humidity x x x       x x
A2D x x x x     x x
Pressure x x x       x x
Date x x   x   x x  

Label (标签)

<label>子元素主要用来描所述标记器件。它可用来标示器件、给出位置信息和提供修订数据或日期。下面是关于<label>子元素的实例。

例7. <label>子元素

<sensor addr="E200000006283826" type="Humidity">
        <label>Indoor Humidity Sensor</label>
</sensor>

在上面的例子中,<label>子元素描述了“Humidity” (湿度)检测器作为一个“Indoor Humidity Sensor” (室内湿度检测器)使用。

Max (最大)

<max>子元素可以数种不同的方式使用。本文展示了<max>的三种特定方式,参见上面的例5和例6。请注意<max>和其它的子元素都不受本文档中所包含的定义的限制。由开发者个人在创建一个新的检测器或执行器的“类型”时来给子元素赋予含义。

Min (最小)

<min>子元素也以数种不同方式使用,但作用与<max>相反。在“Contact”类型的被标记器件中(参阅本文的“类型”部分),<min>用来描述器件可能存在的两种不同状态中的一个。在“Switch”类型标记器件的例子中<min>是用来作为一个状态选择。最后,虽然还没有任何一种被标记器件的类型这样使用,<min>也可作为与上文讨论过的<max>类似的事件信息由器件自身使用。

Channel (通道)

<channel>子元素一般用来从一组选项中做出一个特定的选择。<channel>利用一个整数来表示。例如,在“Branch”、“Switch”和“Event”类型中,子元素<channel>可用来从一个2个开关的阵列中挑出一个特定的开关来。在下面的例子中,<channel>属性值是“1”,说明将要选中的是第二个开关。

例8. 子元素<channel>在“Event”类型下的实例

<sensor addr="B200000018BC2A12" type="Event">
        <label>Switch #1</label>
        <max>Activity sensed!</max>
        <channel>1</channel>
</sensor>

Init (初始化)

<init>子元素通常用作标记器件的初始化状态,特别是对执行器而言。若被标记器件在被使用之前应处在某种状态下,那就要用到<init>子元素了。其数据可以是任何一种数据类型。在下面的实例中,“Switch”类型的标记器件就用子元素<init>来将“Switch”初始化到“关断”状态(在此用数字0来表示)。

例9. 子元素<init>

<actuator addr="B700000018AE3212" type="Switch">
        <label>Buzzer</label>
        <max>Buzz!!!</max>
        <min>Sleep</min>
        <channel>0</channel>
        <init>0</init>
</actuator>

Scale (刻度)

当标记器件(主要是执行器)需要一个刻度范围显示结果或选择若干状态显示组之一时通常需要使用<scale>子元素。

Hightrip (高位门限)

一般当所标记器件,通常是检测器,需要一个高位门限值监测一个高值时要使用<hightrip>子元素。例如检查一个房间里的温度是否已太高而需要开启制冷空调系统就是一种用法。另外,还可以用于闹钟和湿度或湿度、压力检测等。

Lowtrip (低位门限)

一般当所标记器件需要一个低位门限值监视和测量一个低值时要使用<lowtrip>子元素。例如检查一个房间里的温度是否已太低而需要开启加热系统的应用。也可用于湿度或压力检测。下面是关于<lowtrip>和<hightrip>的例子。

例10. 子元素<hightrip>和<lowtrip>

<sensor addr="E200000006283826" type="Thermal">
        <label>Indoor Temperature</label>
        <lowtrip>18.0</lowtrip>
        <hightrip>30.0</hightrip>
        <min>It's too cold, please turn up the heat</min>
        <max>It's too hot, please turn on the air conditioner</max>
</sensor>

用户自定义的子元素

程序设计员或最终用户并不局限于只使用上面所列举的子元素。使用XML的优势就在于它的扩展能力。使用更多的元素不会对本文档中提到的规范造成消极的影响。实际上,还鼓励使用更多的子元素。建议考虑建立以下子元素:<manufacturer>、<date>、<netregistration>和<enum>。其中<manufacture>元素可包含1-Wire部件或簇/子系统的生产厂商信息。当然,<date>标签将能提供制造日期。许多公司都采用WWYY的格式,其中WW表示工作周序号,YY代表年号。<netregistration>元素则可包含一个连接到制造商网站URL,或者可能连接到服务器并通过此连接来自动下载或运行用于特定1-Wire部件或簇的软件程序;最后,<enum>元素可能规定成一个能对实际1-Wire部件或簇进行跟踪的序号,使每个部件或簇都能得到一个唯一的递增的数字号码。然后这个数字号码存入数据库内以便使部件具有可跟踪性。

类型

对1-Wire标签来说类型是非常重要的。对于每片被标记器件(无论是检测器、执行器还是分支)都要根据它的类型创建各自唯一的软件对象。尽管软件对象包含了上面列出的所有数据项子元素,但各自的实现方式是不同。具体情况将由对某个标记器件的类型属性的解析来决定。到撰写此文时,已经确定了九种类型:Contact (联络)、Event (事件)、Switch (开关)、Level (分级)、Thermal (温度)、Humidity (湿度)、A2D (模数变换器)、Pressure (压力)和Date (日期)。请注意,在1-Wire标签中,类型值应该总是用大写字母开头。在XML 1-Wire标签方案的Java实现过程中,类型就是软件对象实际的名称,而且在运行时被动态地说明。

1-Wire标签的类型可被分为两组:执行器和检测器(分支作为一个独立的类型)。这些分组直接与<actuator>和<sensor> XML父元素关联。如前所述,执行器就是那些可执行动作或过程的被标记器件,检测器就是可用来按照要求监控或检测某一特定条件和给出一个读数的被标记器件。在九种类型中,有一种被分类成执行器,其余八种是检测器。执行器类型为Switch。因此,如果一个1-Wire标签标记为<actuator>元素,则可知它的类型是Switch。相反地,如果一个1-Wire标签标记为<sensor>元素,则可知它的类型将是以下检测器类型之一:Contact、Event、Level、Thermal、Humidity、A2D、Pressure或是Date。请注意在下一部分中列出的例子都是带有说明适用XML的题头的、完整的1-Wire标签。

执行器类型

本文中确定的执行器类型是Switch。Switch类型代表了1-Wire开关系列中的任意一片器件。这其中包括DS2406、DS2413和 DS28EA00。用XML解析器解析Switch时,将产生一种软件对象、该对象被查询时将给出一个可供选择的状态选项组。当选定了一个特定的选项后,执行器就转变到选择的状态。对Switch类型来说,选项不是断开连接就是接通连接。

Switch

一个“Switch”执行器有五个子元素:<label>、<max>、<min>、<channel>和<init>。在下面的例子中,<label>用来描述此执行器是一个蜂鸣器。<max>子元素描述了一种状态选择。如果<max>的状态一经选定,那么“Buzzer” (蜂鸣器)就会发出“Buzz (嗡嗡声)!!!”。<min>子元素也是用来描述一种状态选择,但是,显然它与<max>相反。如果<min>的状态一经选定,蜂鸣器就会停止发出嗡嗡声并处于“Sleep” (睡眠状态)。<channel>子元素标签将要使用1-Wire标签器件上的特定的开关。<init>子元素描述开关的初始状态,在此例中是断开状态(用整数0来表示)。

例11. “Switch” 1-Wire标签

<?xml version="1.0" encoding="UTF-8"?>
<actuator addr="B700000018AE3212" type="Switch">
<label>Buzzer</label>
        <max>Buzz!!!</max>
        <min>Sleep</min>
        <channel>0</channel>
        <init>0</init>
</actuator>

检测器类型

本文确认的检测器类型分别是:Contact、Event、Level、Thermal、Humidity、A2D、Pressure和Date。任何1-Wire器件都使用Contact类型,它的用途是检测被标记的器件是否在1-Wire总线上。一个Event检测器的用途是来探测在某一特定的1-Wire开关上是否发生了活动。Level检测器用于检测1-Wire开关的电平,即为导通或非导通。顾名思义,Thermal检测器用来检测周围的环境温度,用于任意一款1-Wire数字温度计。下面是部分温度检测器列表:DS1921DS1920DS2438DS18S20DS18B20。Humidity检测器用来检测湿度,到撰写本文时为止,主要就是DS1923。A2D利用1-Wire器件中的模数转换器检测电压值。其型号包括DS2438和DS2450。Pressure检测器用来检测压力,由于到目前还没有可用作商业用途的1-Wire压力检测器,本文中列出的压力检测器只作为一个占位符。最后,来说Date检测器,它用来读取某个过去的时间。

Contact

一个“Contact”检测器有三个子元素:<label>、<max>和<min>。<label>用来描述这个检测器。在下面的例子中,<label>指出此1-Wire器件是雇员号为22的名牌。<max>子元素描述在其出现1-Wire总线上的状态。<min>子元素描述的是与<max>相反的状态。注意类型值“Contact”是用大写字母开头。带有适用的XML题头说明的、完整的“Contact”类型的1-Wire标签见下例所示。

例12. “Contact” 1-Wire标签

<?xml version="1.0" encoding="UTF-8"?>
<sensor addr="490000000212D016" type="Contact">
        <label>Employee 22 badge</label>
        <max>Making contact</max>
        <min>No contact</min>
</sensor>

Event

“Event”检测器有三个子元素:<label>、<max>和<channel>。当然,<label>用来描述检测器。在下面的例子中,<label>指明这个1-Wire器件是1-Wire总线上的“Switch #1” (可能另外还有许多开关)。<max>子元素是在开关上检测到发生动作的事件消息。<channel>子元素表示检测的是所标记1-Wire器件中的哪个特定的开关。

例13. “Event” 1-Wire标签

<?xml version="1.0" encoding="UTF-8"?>
<sensor addr="B200000018BC2A12" type="Event">
        <label>Switch #1</label>
        <max>Activity sensed!</max>
        <channel>1</channel>
</sensor>

Level

一个“Level”检测器有四个子元素:<label>、<max>、<min>和<channel>。同理,<label>还是用来描述检测器的。在下面的示例中,簇名属性确定了所指出的1-Wire器件是DS2406。实际上,DS2406是由两片被标记器件组成的一个簇。其中,第一个是“Level”类型的、第二个是“Switch”类型的。对“Level”检测器来说,<label>元素是“Refrigerator Door Light” (冰箱内门灯)的检测器。<max>子元素是说明开关处于导通状态的事件消息。因此,此消息就是“Light is on” (灯亮)。相反地,<min>子元素是说明开关断开状态的事件消息即“Light is off” (灯灭)消息;<channel>子元素说明检测的是所标记1-Wire器件中的哪个特定开关。

例14. “Level” 1-Wire标签

<?xml version="1.0" encoding="UTF-8"?>
<cluster name="DS2406 Demo">
        <sensor addr="36000000000F2212" type="Level">
                <label>Regrigerator Door Light</label>
                <max>Light is on</max>
                <min>Light is off</min>
                <channel>0</channel>
        </sensor>
        <actuator addr="36000000000F2212" type="Switch">
                <label>Contact Maker</label>
                <min>Open Circuit</min>
                <max>Make Contact</max>
                <channel>1</channel>
                <init>0</init>
        </actuator>
</cluster>

Thermal

一个“Thermal”检测器有五个子元素:<label>、<lowtrip>、<hightrip>、<max>和<min>。显然,<label>用来描述检测器。在下面的例子中,<label>指出这个标记器件是室内温度检测。

作为选项,一个类型为“Thermal”的标记器件既可有高位门限值也可有低位门限值。就像一个恒温器,既可能需要温度超过了给定温度时报告、也可能需要在低于给定值时报告。为实现上述操作,要用<hightrip>和<lowtrip>元素来设定检测的高低限(采用浮点数)。<min>和<max>用来存放在指示超过门限值的简单文本消息。详情参阅下面的例子。

例15. “Thermal” 1-Wire标签

<?xml version="1.0" encoding="UTF-8"?>
<sensor addr="E200000006283826" type="Thermal">
        <label>Indoor Temperature</label>
        <lowtrip>18.0</lowtrip>
        <hightrip>30.0</hightrip>
        <min>It's too cold, please turn up the heat</min>
        <max>It's too hot, please turn on the air conditioner</max>
</sensor>

Humidity

“Humidity”检测器的第一个子元素是<label>。在下面的例子中,<label>指出这个特定的被标记器件是室外湿度计。

作为选项,一个类型为“Humidity”的标记器件既可有高位门限值也可有低位门限值。既可能需要在湿度超过了给定程度时报告、也可能需要在低于给定程度时报告。为实现上述操作,需要用<hightrip>和<lowtrip>元素来设定检测的高低限。这些限值使用浮点数表达。<min>和<max>用来存放指示超过限值的简单文本消息。详情请参阅下面的例子。

例16. “Humidity” 1-Wire标签

<?xml version="1.0" encoding="UTF-8"?>
<sensor addr="E200000006283826" type="Humidity">
        <label>Outdoor Humidity</label>
        <lowtrip>20.0</lowtrip>
        <hightrip>90.0</hightrip>
        <min>It's too dry</min>
        <max>Expect fog or rain</max>
</sensor>

A2D

“A2D”检测器有六个子元素:<label>、<channel>、<lowtrip>、<hightrip>、<min>和<max>。“A2D”检测器的第一个子元素是<label>。在下例中,<label>指出这个特定的被标记器件是检测电压的。A2D所标记器件有多个进行模数转换的通道,<channel>用来确定读取哪路通道的数据。在此情形下,<channel>元素用一个整数表达。在下例中,<channel>元素指出是第一条通道,即通道0,是要读取的通道。

同样,可以选择有上限或下限监测门限值点的“A2D”标记器件。相应地当电压值超过或低于给定值时,要给出<min>和<max>文本消息。<hightrip>和<lowtrip>元素来代表所监控的高低电平限,为浮点数。

例17. “A2D” 1-Wire标签

<?xml version="1.0" encoding="UTF-8"?>
<sensor addr="E200000006283826" type="A2D">
        <label>Voltage Monitor</label>
        <channel>0</channel>
        <lowtrip>2.0</lowtrip>
        <hightrip>4.0</hightrip>
        <min>Voltage too low</min>
        <max>Voltage too high</max>
</sensor>

Pressure

“Pressure”检测器由五个子元素组成:<label>、<lowtrip>、<hightrip>、<min>和<max>。压力检测器的第一个子元素是<label>。在下例中,<label>指出该特定的标记器件是室外气压计。

一个类型为“Pressure”的标记器件可有高位和低位监测门限值。当压力值超过以及低于给定值时能够知道是有利的。用<hightrip>和<lowtrip>元素来设定监测的高低限(利用浮点数),同时<min>和<max>元素可以用来作为超过限值时所发送的简单文本消息的来源。请参阅下例。目前,Pressure类型还只是一个占位符,知道在撰写本文档时,还没有直接支持压力测量的1-Wire器件。

例18. “Pressure” 1-Wire标签

<?xml version="1.0" encoding="UTF-8"?>
        <sensor addr="E200000006283826" type="Pressure">
        <label>Outdoor Barometric Pressure</label>
        <lowtrip>28.0</lowtrip>
        <hightrip>31.0</hightrip>
        <min>Low pressure</min>
        <max>High pressure</max>
</sensor>

Date

“Date”标记器件之所以是监测器是因为它被用来读取并显示时间/日期值。许多不同的1-Wire器件符合这种情况。其中包括DS1904、DS1921、DS2417和DS2438。

例19. “Date” 1-Wire标签

<?xml version="1.0" encoding="UTF-8"?>
<sensor addr="27000000036D9B24" type="Date">
        <label>My iButton Clock</label>
        <hightrip>1000000</hightrip>
        <max>Time to buy another car</max>
</sensor>

“Date”检测器第一个子元素是<label>。在上例中,<label>指出这个特定的标记器件是一个iButton时钟。“Date”类型的标记器件也有可设定一个比较点的选项。当时间/日期值超过某一确定时间值(比较点)时,就会发出一条适当的文本信息。在上例中,<hightrip>元素设置为自1970年以后1000000秒,只要计时一超过1000000秒,就会发送出由<max>元素指定的信息:“Time to buy another car” (该去买辆新车了)。请注意<hightrip>表示自从1970年以后的所走过的秒数,要用长整数表示,<max>元素是超时情况下的文本消息。

缩微标签

由于1-Wire器件上内存容量有限,极需要1-Wire XML标签所占的容量能尽可能地小。在极端情况下当正常的XML标签过大时,也可以使用标签。简而言之,缩微标签就是单个内容空白的XML元素。它以ASCII码的形式直接存放在1-Wire的存储器中。根据本文规范,如果不是在1-Wire器件中使用、则无需考虑使用缩微标签。建议只在绝对需要时使用这种缩微标签。缩微标签从两个角度偏离了XML工业标准。其一它们本身并不是有效的XML文档(只是有效的XML元素)。其二缩微标签可读性不好。

缩微标签格式

缩微标签采用标准ASCII码并具有<TTNNCI/>的格式。TT是所标记器件“Type”的由两位字母组成的识别代码。NN是反映器件型号的两位数字代码。“C”是可选项,是与<channel>子元素标签相对应的一个数字。“I”指的是与<init>子元素标签相对应的一个数字,它也是可选项。请参阅本文档“1-Wire XML子元素”中与<channel>和<init>有关的部分;在少量场合会只有“I”而没有“C”,此时要在本来“C”数字应处的地方置下划线。

以空的XML元素<HU10/>为例,如果它在1-Wire器件的存储器中被发现,它将被看成一个缩微标签。它是由7个ASCII字节组成的:3C 48 55 31 30 2F 3E。依照上面所讲的格式,我们得知此零件的两位字母代码是HU。通过查看下面的缩微标签表,我们发现“HU”代表标记器件的类型为“Humidity”。同样,我们得知此零件的两位数字代码NN为“10”。尽管NN从本质上讲是主观想象出来的,但是在此例中选择的数字还是附带了一些意义,它代表湿度检测器器件型号的后2位数字。对此缩微标签<HU10/>来说,“C”和“I”标签不必要,因此没有包括在内。

表2. 缩微标签类型的缩写
缩微标签的2字母
缩写
类型
SW Switch (执行器)
CO Contact (检测器)
EV Event (检测器)
LV Level (检测器)
TH Thermal (检测器)
HU Humidity (检测器
AD A2D (检测器)
PR Pressure (检测器)
DT Date (检测器)

缩微标签的转换

显然,缩微标签并不是一个完整的可用来解析的XML文档,但可以很容易地将其转换成这样的文档。这个过程就叫做缩微标签的转换。它就是将缩微小型标签转换成1-Wire标签XML文档。例如,缩微标签<HU10/>可以被转换到下例中的1-Wire标签XML文档。

例20. 缩微标签<HU10/>的转换

<?xml version="1.0" encoding="UTF-8"?>
<sensor addr="E200000006283826" type="Humidity">
</sensor>

将缩微标签转换到XML文档中的第一步是先建立一个如下的XML题头:<?xml version=”1.0” encoding=”UTF-8”?>。第二步是在上表中查找缩微标签中两个字母类型识别代码并找到其类型属性和父元素。在本例中,类型属性是“Humidity”、父元素是<sensor>。最后是确定标记器件的addr属性。当然,这个值就是1-Wire网络地址值,根据1-Wire搜索协议它事先已被获取(通过发现器件和读器件存储器中的内容)。

XML 1-Wire标签嵌套

下面给出了分支嵌套的例子。第一个分支是一个“Hub Switch” (集线器开关),第二个分支是一个气象工作站簇并且建立了一个“Contact”检测器来确定是否在刮北风。类似地,簇也可以嵌套

例21. 嵌套分支的1-Wire标签

<?xml version="1.0" encoding="UTF-8"?>
<branch addr="B700000018AE3212" >
        <label>Hub Switch #1</label>
        <channel>1</channel>
        <init>0</init>
        <cluster name="1-Wire Weather Station #2">
                <sensor addr="E200000006283826" type="Thermal">
                        <label>Outdoor Temperature</label>
                </sensor>
                <branch addr="77000000023CEC12" >
                        <label>Wind Vane Switch</label>
                        <channel>1</channel>
                        <init>0</init>
                        <sensor addr="0E00000200522401" type="Contact">
                                <label>North Wind</label>
                                <max>Making contact</max>
                                <min>No contact</min>
                        </sensor>
                </branch>
        </cluster>
</branch>

软件实现

本文的上述部分提供了有关组成XML 1-Wire标签的数据以及如何进行书写。对上述内容有所了解后,就可以详细讨论实现解析和使用这些标签的软件的例子了。在撰写这篇文档期间,已经利用面向Java的1-Wire API成功地在Java中实现了一个例程,所以下面的论述将围绕Java以及伴随面向对象的术语为中心来展开。面向Java的1-Wire API可在下列网址找到并下载:https://www.analog.com/cn/product-category/ibutton-products.html

解析器

正如上文所述,XML 1-Wire标签的Java实现基于SAX兼容的XML解析器。选择此类解析器的原因是它的实现规模小以及其可以在MxTNI这样的小型手持设备上使用的能力。任何一种SAX解析器都可用于XML 1-Wire标签,公认的、运行较好的两个Java SAX解析器是:MinML (www.wilson.co.uk/)和NanoXML (http://nanoxml.sourceforge.net)。

软件对象的创建

如图1所示,SAX解析器先接收XML 1-Wire标签文档,然后对其进行解析并利用1-Wire标签软件库,生成两个软件对象集合。这是软件对象创建程序的顶层视图。第一个集合是所标记器件的软件对象的动态数组。在Java实现例程中,所标记器件的软件对象的类名是TaggedDevice,一个动态数组被称作一个Vector (向量)。

第二个集合是反映1-Wire网络的网络拓扑结构的软件对象动态数组,在其它场合也被称作1-Wire路径,本质上来说,可把它们想象成通过一组分支(1-Wire开关)到达特定执行器或检测器的路径。在Java实现例程中,该“路径”对象的类名是OWPath。

图1. 软件对象创建程序的顶层视图

图1. 软件对象创建程序的顶层视图

标记器件的软件对象

标记器件软件对象有三种风格的细分:分支、检测器和执行器。分支起到的作用就像一个开关或路径,检测器用来“读取”或“检测”一个测量值或活动,执行器是用来使用或进行处理的器件。所有标记器件的软件对象都有相同的数据项,但并不是在每种类型的标记器件中都用得到。在Java实现中,标记器件软件对象是“TaggedDevice”。TaggedDevice对象的数据项机器简要介绍,请参阅下表。在用其它软件实现时,至少要做到使用下面列出的这些数据项等效的项目。

表3. TaggedDevice数据项说明
数据项 说明
label 字符串,相当于
max 字符串,相当于子元素。
min 字符串,相当于子元素。
channel 整型数,相当于子元素。
init 字符串,相当于子元素。
scale 字符串,相当于子元素。
hightrip 浮点数,相当于子元素。
lowtrip 浮点数,相当于子元素。
type 字符串, 相当于类型属性。
clusterName 字符串,代表到标记器件的簇路径。若有嵌套,clusterName由前面所有的
clusterName组成并用“/”隔开。例如:
“BuildingC/Roof/WeatherStation#5”。
deviceContainer 标记器件的特定OneWireContainer容器。
branchPath 到标记器件的1-Wire路径。参阅下文中论述的1-Wire路径。

标记器件软件对象的数据项应严密地映射到上面论述的XML子元素。这可以在上面表中TaggedDevice的Java实现例程中看到。如下是关于TaggedDevice的论述。

TaggedDevice的前八个数据项代表的八个子元素除channelhightriplowtrip以外,均为字符串。按应用所需,数据项中channel是整型数,hightriplowtrip是浮点数。数据项clusterName是个字符串,它包含被标记器件软件对象所从属的簇的簇名。簇可嵌套,如果存在嵌套,则类似于计算机上文件路径的表达,clusterName项中前面要加上路径簇名。例如:“Building C/Room165/North Wall”对任意一个在“North Wall”簇中的TaggedDevice是有效的clusterName。以上表明簇有三层嵌套,注意它们之间用一个正向斜线“/”隔开。

XML解析时,利用基于startDocument事件创建的字符串堆栈产生clusterName项。当在分析过程中发现了一个新的<cluster>元素时,其名称文本字符串“压入”堆栈;当<cluster>元素结束时,<cluster>名称字符串从堆栈中“弹出”。所有在一个<cluster>元素的开始到结束这段时间内创建的TaggedDevice对象都使用堆栈快照,并用“/”作为分隔符将它们存入到clusterName数据项中。

deviceContainer是TaggedDevice中非常重要的一个数据项。它指专用于1-Wire器件的OneWireContainer。它包含对一个特定标记器件进行完全访问和操作所必需的全部方法和域。OneWireContainer对象是面向Java的1-Wire API的一部分并在其中有充分描述。进行XML解析期间,当处理至addr属性、即所标记器件的1-Wire网络地址时,一个TaggedDevice对象的OneWireContainer将被初始化。

请注意OneWireContainer软件对象只有在面向Java的1-Wire API中是可用的。所以在其它可能的XML 1-Wire标签非Java实现中,开发者将需要利用一个变量集和其它1-Wire软件库中的功能来构造一个等同于deviceContainer部分。

最后,TaggedDevice的最末一个数据项是branchPath。它是所标记器件的1-Wire通路。1-Wire通路指的是一条通过一组1-Wire开关后到达特定的执行器或检测器的路径。在Java实现例程中,1-Wire路径软件对象命名为OWPath。与OneWireContainer对象类似,OWPath对象也在面向Java的1-Wire API中进行了充分描述。接下来是关于1-Wire通路和其Java等效对象OWPath的讨论。

1-Wire通路的软件对象

创建1-Wire通路的软件对象的目的就是使其起到通路的作用。其性质类似计算机上的文件路径。只是这里的“路径”它指的是通过许多嵌套分支(1-Wire开关)后来访问一个特定的标记器件。1-Wire通路软件对象至少由几个基本的数据项和方法组成。其中一个重要的数据是组成通路的许多1-Wire开关的1-Wire网络地址的集合。另一个重要的数据项是访问所期望的检测器或执行器时将要使用的在每片器件上的特定通道的集合(一些1-Wire开关器件其单片上含有多个开关)。同样,在1-Wire通路软件对象中还应该包括建立和关断通路的方法。其中,要“建立”通路,意味着要贯穿在1-Wire通路中列出的每片1-Wire分支器件、选取适当的开关以及将每个开关打到“导通”状态。相反地,“关断”1-Wire通路就是将适当的开关拨到它们的“非导通”位置上。

在1-Wire标签的Java实现例程中,把1-Wire通路软件对象叫做OWPath。它组成了前面表3列出的TaggedDevice对象的branchPath数据项。OWPath对象还组成了前面图1所示、XML解析过程中生成的1-Wire通路软件对象的动态数组(向量)。OWPath对象是通过面向Java的1-Wire API取得的,在标记的实现例程中广泛利用。

在实现例程中有两处需要OWPath对象。第一处是TaggedDevice的branchPath数据项。第二种情况是在解析XML标签的返回向量中。在第一种情况中,每片TaggedDevice的branchPath是在XML分析过程中通过对分支栈的跟踪来创建的。此处提到的栈就是已公认定义的、与“压入”和“弹出”方法关联的那种软件结构“堆栈”。分支栈就是记录1-Wire分支(或开关)的一个堆栈。当在XML解析过程中一个TaggedDevice对象被创建出来时,当前的分支堆栈被复制到属于TaggedDevice的一个临时堆栈。接着,在XML文档分析完全结束时,遍历所有TaggedDevice对象、重复迭代组成了向量,其间每个堆栈所存储的内容用来创建OWPath对象。

在第二处需要OWPath对象的地方情况类似。为了从单个XML标签的解析产生返回向量,要使用上述相同的分支栈。唯一的不同的是分支栈在“弹出”前被复制到一个临时向量。到XML文档分析完全结束,分支栈被遍历、重复迭代,并且用它来创建OWPath对象向量。

扩展标记器件的软件对象

从面向对象的角度出发,解析除分支器件以外的1-Wire标签时返回的被标记器件软件对象组数组实际上也应是扩展的标记器件软件对象。也就是说,它们都具有数据项和与标记器件软件对象关联的方法,也可能还有唯一针对其类型的附加数据项、方法和/或实现方法的过程。例如,“Contact”器件有与“Switch”器件不同的方法和/或实现方法的过程。本文中予以确认的类型列表请参见表1 “每种类型用到的子元素”。

器件的每个类型都有唯一的、与其相关的标记器件软件对象。因此,如果新设计的1-Wire器件属于一个新的类型,将需要编写新的软件对象。对于Java实现例程,标记器件的每个“type”都由一个在其原代码中包含“extends TaggedDevice” (扩展标记器件)声明的类文件。例如:Contact类型有专用的Contact.class类文件。这些软件对象在XML解析与其相关的1-Wire标签时被引用。另外的好处是,1-Wire的Java实现例程中这些软件对象是在运行时动态地引用的。

检测器接口和执行器接口

作为进一步的抽象化,本文规定了可用于每个标记器件软件对象的检测器接口和执行器接口。这里所应用的接口的概念是Java意义下的接口。接口简单地讲相当于如果任意一个软件对象声称它实现某个接口,则它应须实现接口定义的特定方法。例如,在Java中称作TaggedSensor的检测器接口,由单个方法readSensor()组成。这个接口所定义的方法readSensor()返回一个代表检测器当前读数的字符串。通过贯彻实现这个接口,软件对象将保证提供名为readSensor()的方法;这个方法不接收变量、返回一个字符串。因此,所有检测器类标记器件都会有readSensor()方法。举例来讲,调用检测器类型“Thermal”中的readSensor()方法时(位于Java的Thermal.class类中),将返回“23.5 degrees Celsius” (摄氏23.5度)这样的可能温度值。

同样地,执行器接口也是由若干特定的方法定义组成的。在Java实现中,它叫做TaggedActuator。执行器接口由以下三个方法组成:getSelections()、setSelection(String selection)和initActuator()。第一个方法getSelections(),用来提取某执行器可能变化或可能执行的状态选项组。在Java实现中,它们作为一个动态字符串数组或字符串向量返回。第二个方法setSelection(String selection),实际上是将执行器用与其状态选项相符的字符串、设置到给定的状态。最后,第三个方法initActuator(),将执行器初始化成预定的状态。这种方法的调用应在其它两种的前面。

按照此规定的Java实现中,一个新的TaggedDevice对象在其源代码中将同时包括“extends TaggedDevice”和“implements TaggedSensor”或“implements TaggedActuator”这样的声明。例如:类型为“Contact”的TaggedDevice对象的源代码包括下面的行:“public class Contact extends TaggedDevice implements TaggedSensor”。

主应用程序

主应用程序是用来运行标记软件库的程序。它负责与用户进行接口、线程管理、1-Wire同步、捕捉1-Wire异常及搜索标签和缩微标签的分支。本文包括一个符合本文规定的Java主应用程序的例子。这是应用Java 1-Wire标签库的良好编程实践。

有时还需要为主应用程序创建生成1-Wire标签的应用程序或将这个功能作为主应用程序的一个部分。1-Wire标签生成程序专门为开发程序简单地创建XML 1-Wire标签文件。它可以是以提示程序的方式就标签元素帮助使用者,并且当填写完成后将XML文件或缩微标签写入适当的1-Wire器件或文件。在1-Wire标签的Java参考例程有这样一个例子。

结论

在软件设计中应用本文的概念,不但可以解决本文绪论中提出的普遍性问题,并且还可以拓宽和简化1-Wire器件在实际应用中的使用。绪论中谈到的问题是一个有两个开关的1-Wire网络情形。其中一个开关用于分支、其后有另外的1-Wire器件,另一个开关则用于开启一个有高度安全要求的门。在这里,问题在于不经过启动难以区别这两个器件以及意外开启安全门。

解决的办法就是利用XML 1-Wire标签。下面是能事先区别这两个开关功能的标签示例。

例22. 高度安全门的1-Wire标签

<?xml version="1.0" encoding="UTF-8"?>
<cluster name="Area 51">
        <branch addr="2700000016EF3A12" >
        <label>Secure Room #1</label>
        <channel>1</channel>
        <init>0</init>
        <sensor addr="490000000212D016" type="Contact">
                <label>Government Badge #52</label>
                <max>Making contact</max>
                <min>No contact</min>
        </sensor>
                .
                .       (其它可能的分支、执行器检测器)
                .
        </branch>
        <actuator addr="B700000018AE3212" type="Switch">
                <label>High Security Door: Alien Room</label>
                <max>Security cleared, door opened!</max>
                <min>Door shut and locked!</min>
                <channel>0</channel>
                <init>0</init>
        </actuator>
</cluster>

由上面的例22可以看出,安全门的问题解决了。第一个开关被显示是一个分支,并明确的标注为“Secure Room #1”。在这一开关后面,我们可以看到一个Contact检测器、被注为“Government Badge #52”。在第一个开关的这一面还可能有任意数量的1-Wire检测器、执行器或其它分支。

第二个开关明确地标注为“High Security Door: Alien Room”,而且确定它是个“Switch”类型的执行器。根据这个1-Wire器件的XML元素的内容,我们可知这个门在通道0 (即这个1-Wire器件上的第一个开关)的控制下,而且通道0的开关在程序启动时被初始化为0或“非导通”状态。也就是说,在程序启动时,门被关闭和锁牢。

按上述情况,不但问题得以解决、还得到了像分组化甚至类似数据库功能等其它有用的特性。如所有这些1-Wire标签集中在一起形成一个名为“Area 51”的簇。这表明1-Wire器件很容易扩展为1-Wire簇或分组。它还包括带有“嵌套”开关的1-Wire网络拓扑的概念以及像可跟踪记录进入安全门的人等简单的、类似数据库的特性。作为结论,1-Wire标签不但解决了这一问题,它还利用工业标准XML,加强了开发人员和用户对1-Wire器件的应用和推广。