Personal Universal Controller
Appliance Specification Language Documentation
Documention originally written by Jeffrey Nichols and
Mathilde Pignol.
Language design by the personal universal controller working group:
Michael Higgins, Joe Hughes, Peter Lucas, Brad A. Myers, Jeffrey
Nichols, and Mathilde Pignol. Speech interface contributions by
Thomas K. Harris.
The personal universal controller (PUC) project's goal is to build a software framework running on top of a personal digital assistant (PDA) or other mobile device that is capable of providing an interface that will allow users to control any appliance within their environment. In essence, the PUC is a device-independent, appliance-independent, user-dependent remote control device.
Because of the universal nature of the PUC, it is not reasonable to pre-program the controller device with an interface for every appliance that might be encountered. Similarly, it is not reasonable to require each appliance to provide hard-coded interfaces for several device form factors, and expect the controller devices to interpolate to their actual form factor. This approach ignores user interface conventions that may differ among controller platforms, which cannot easily be interpolated between. For example, certain platforms may not have support for certain types of widgets, and it is possible to imagine a future device that would differ significantly from the devices of today (e.g. a watch with a circular display that uses several physical dials for input).
We have chosen to automatically generate user interfaces on the controller device from an interface-independent specification language. This specification language describes the functions of the appliance and provides knowledge about how these functions relate to each other. We hope that many different kinds of interfaces can be generated from this specification, including interfaces for handhelds, WAP cellular phones, and future devices with new and different interaction styles. We also plan to explore the use of our specification with the automatic generation of speech interfaces.
This document describes the specification language that we have designed for supporting automatic generation of user interfaces. It begins with a description of the conceptual basis for the language, and then defines the language in concrete terms. The document concludes with a section detailing planned additions to the specification language.
Users of this document may also be interested in documentation of the network protocol that is used by PUCs to communicate with appliances.
Date | Name | Comments |
---|---|---|
02/22/2002 | jwn | Fixed typos and added information about new tags for supporting the creation of speech interfaces from the specification language. See <phonetic> tag and the label dictionary explanation. |
02/23/2002 | jwn | Made priority a parameter of <group>, <state>, <command>, and <explanation> instead of having its own tag. |
02/27/2002 | jwn | Made changes to support the DTD and its formatting requirements. Added the DTD section. Updated the example spec to reflect all of the recent language revisions. Added the <apply-type> and <object-ref> tags to support the reuse of type declarations and multiple occurences of the same object within the group tree. This was previously included as a feature that was incompatible with the restrictions of the DTD. Added the <number> tag to make numeric values symmetrical with the use of <refvalue>, again for DTD conformance. Also removed the recording parameter from the <map> and <labels> elements. Instead, each of these elements may now contain multiple <text-to-speech> elements that may specify similar information. |
03/11/2002 | jwn | Added a reference to the new protocol documentation. Also moved the published versions of the DTDs and docs to the pebbles web site, and updated the links in this documentation appropriately. |
10/06/2003 | jwn | Started updating documentation to include all changes to the specification in the last year and a half. This includes significant changes to the group systems, new dependencies, list and union structures, Smart Templates, and some changes to which XML tags are allowed. Updates not completed and new version not released. |
05/19/2004 | jwn | Finished updating the documentation for the new specification language format. Wrote and added an XML Schema for the language, and updated the tag reference. Removed the example specification in Appendix A for now, as this document describes changes that are not actually implemented in any specification language. Once the Mitsubishi DVCR spec is complete, I will add it to the appendix. |
12/09/2004 | jwn | Updated the documentation to cover version 2.3 of the specification language. Version 2.3 complements changes to the protocol, which now supports server-side error correction and auto-completion of values. Three features have been added to language: two new properties of lists, a tag that helps the interface generator optimize the download of list information, and means to define when certain states of an appliance store values that might be used as preset values for other states. This last feature is designed for use with a navigation system or radio, and lets the interface generator create interfaces that can apply presets easily and create interaction methods for saving values as presets. |
06/14/2005 | jwn | A general revision of the documentation, reflecting changes made to the language since the last revision. The sample VCR specification has also been removed in favor of a sample to-do list application specification. This allows the documentation to be used in our specification authoring study, where subjects are asked to create a VCR spec. Updated the schema to reflect the changes described in this document. |
The design of the specification language was based upon prototyping interfaces for a phone and a stereo appliance on a standard handheld form factor (we tried both Palm and PocketPC). These prototypes taught us several things about the functions of appliances:
Each of these items are described in more detail below.
Three types of appliance objects are supported in the specification language.
Although there are differences between states, commands and explanations, they also share a common property of being enabled. When an object is enabled (or active), the user interface widgets that correspond to that object can be manipulated by the user. Knowing the circumstances in which an object will be enabled or disabled can provide a helpful hint for structuring the interface, because items that are active in similar situations can be grouped, and items can be placed on panels such that the widgets are not visible when the object would not be active. Specifying the prior knowledge of the enabled property is discussed in more detail in the Dependency Information sub-section.
Another common property of appliance objects is the need to specify rich labeling information for flexibility when generating interfaces in different form factors.
To support specifying labeling information, we use the concept of a label dictionary. At any place in the specification where a label can be entered, more than one label may be provided. It is expected that all these labels contain the same general information, but vary in terms of length and detail. We also allow the specification designer to designate one label as "preferred" for use in an interface. The interface generator would choose the preferred label or the longest label that fits within the space allocated on the screen. In certain situations, the preferred label may be used as the basis for making layout decisions.
Labels can be specified for any appliance object, and also be linked with particular values of an appliance state's type.
This language also supports the specification of label information for speech interfaces. This support is for both recognition and text-to-speech. Label dictionaries can store phonetic information to help recognizers interpret label names. Multiple pronunciations can be specified for robustness, just as multiple labels can be specified. To assist text-to-speech engines, each label dictionary can be associated with a URL that points to an audio recording of the label.
Every appliance state has a type object associated with it. The type information is used to determine what kinds of widgets can be used to manipulate the state, and is one of the paramters that is used to recognize Smart Templates.
There are currently eight different kinds of types that can be used in the specification:
Each of these types has a different set of parameters that can be specified for it. For a complete list of those parameters, see the tag reference.
The binary type is used for data that cannot be described as a string, e.g. images, sound clips, or video. Unlike the other types, interface generators are not expected to have a default rendering for variables with binary types. A Smart Template must be used in conjunction with a binary state to ensure that the state is rendered.
The list selection type allows the user to specify an item in a list. This is used in locations where it would not make sense to duplicate the list state variables. For more on lists see the lists section.
Older versions of the specification language supported a custom primitive type, which was used for representing domain-specific types. This type is no longer allowed. See the section on Smart Templates later for more information on our current solution for this problem.
The specification language contains a provision for re-using type declarations in subsequently defined state variables via the <apply-type> element. This allows two or more state variables to have the same type without specifying that information multiple times in a specification. No data is shared between those state variables.
Proper structure is a very important part of any user interface. In our language we use a hierarchical "group tree" to specify structure. The leaf nodes in the tree are appliance objects, and the branch nodes are groups. Each node in the tree has a name which must not be the same as any other child of its parent. Thus each node has a locally unique name, and a globally unique name can be constructed by pre-pending the names of all a nodes parents. We use a "." character to separate each name. For example, the locally unique name of a state variable might be "PlayState" but the globally unique name would be "Stereo.CD.PlayState". That same specification could also contain other states like "Stereo.Tape.PlayState". Note that the root name "Stereo" cannot be re-used as a name anywhere in the specification.
It is often necessary to explicitly refer to state variables in a specification. This may be done using any name that starts with a globally unique name. Since the root name is unique, the full name will always work. For the above examples, "Tape.PlayState" and "CD.PlayState" would also work, assuming that there are no other groups or states named "CD" or "Tape".
The group tree also extends our language's type system by allowing multiple state variables (possibly with different types) to be aggregated and replicated. There are three types of groups: normal, list, and union. A normal group is used for putting related data together, similar to a record in a programming language. List and union groups replicate states and provide special aggregating behaviors, which are discussed in the next two sections.
Specifying a list group is similar to specifying an array of records in a programming language, and multiple list groups can be nested to create multi-dimensional lists. Each list group has an implicit length state variable (named "Length") that always contains the length of the current list. If this variable is undefined, then the list currently has no members. The specification may define bounds on the length of the list in order to help the interface generator create a better rendering. An exact size may be specified, or a minimum and/or maximum size may be specified.
List groups also maintain an implicit structure to keep track of one or more list selections. The number of selections allowed may be defined in the specification ("one" and "many" are the only options currently), and the default is one if nothing is specified. If a list allows only one selection, then an implicit "Selection" variable is created which contains the index of the current selection (undefined means no selection). If multiple selections are created, then an implicit list group named "Selection" is created. This group contains a "Length" state (as all list groups do) and an "Index" state which contains all of the selected indices.
Our language does not have any built-in mechanism for specifying the set of operations that can be performed on any given list, because we did want to attempt to enumerate and support all of the possible operations. List operations can be specified using commands. Smart templates can be used to help interface generators appropriately render list operations.
A union group is simliar to specifying a union in a programming language; of the children within a union (either groups or appliance objects), only one may be active at a time. An implicit state variable named "ChildUsed" is automatically created within a union group that contains the name of the currently active child.
The specification language has a mechanism for re-using types, both for state variable types and grouping types. A special section at the beginning of each specification allows the author to specify types that they use often in their specification and the apply-type element can be used within the specification to apply these types where appropriate.
In this language, the use of the apply-type element prevents the need for copying & pasting snippets of a specification multiple times in the same file. There is currently no mechanism for extending or modifying a type that has already been specified.
Dependency information is specified for each appliance object as a boolean equation. This information gives the interface generator some approximate a priori knowledge of when the object will be enabled (see the Appliance Objects section for more information).
Five kinds of dependencies can be specified. Each of these dependencies specifies a state that is depended upon, and most specify a value of that state. In those cases where a value must be specified, a pointer to another variable may be used instead with the <ref-value> tag.
These dependencies can be composed into boolean formulas using AND and OR. True and false may also be included in dependency formulas, though their usage in dependencies will either be ignored or cause a formula to always short-circuit to a particular value.
Specifying dependencies on list state variables must be done using the special <apply-over> element. This element applies the dependencies it contains over some elements in a list and returns a value depending on the value of its "true-if" property. The "items" property defines the set of the set of items that the dependencies will be applied over, and may be set to "all" or "selected." The "true-if" property may be either "all", "any" or "none". If "true-if" is "all", then all of the dependencies contained in the "apply-over" element must be true for elements if true is returned. If "true-if" is "any", then all of the dependencies contained in the "apply-over" must be true for one of the elements. If "true-if" is "none", then the dependencies must not be satisfied by any element to return true.
Smart Templates extend the primitive types of the specification language with high-level semantic information. With a Smart Template, a group in a specification might be marked as "media-controls" for example, and an interface generator could use this information to create an interface that uses the standard play and stop icons that people are accustomed to. More information about Smart Templates is available in this paper.
Documentation about applying and specifying templates and a list of the Smart Templates specified so far is available here.
Our specification language is based on the XML standard from the Worldwide Web Consortium. A Schema for the language is shown below. You may separately download the schema from here. The tag reference and the example specifications in Appendix A may also be helpful for understanding the particulars of our specification language.
NOTE: The following schema is designed to be usable in Microsoft's Visual Studio .NET, which makes some restrictions on the formatting. This schema should not be used as an example of good style.
<?xml version="1.0" encoding="utf-8" ?> <xs:schema targetNamespace="http://www.cs.cmu.edu/~pebbles/puc" elementFormDefault="qualified" xmlns="http://www.cs.cmu.edu/~pebbles/puc" xmlns:mstns="http://www.cs.cmu.edu/~pebbles/puc" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <!-- Top-Level Element --> <xs:element name="spec"> <xs:complexType> <xs:sequence> <xs:element name="labels" type="LabelDictionary" /> <xs:element name="types" type="TypesGroup" minOccurs="0" maxOccurs="1"/> <xs:element name="groupings" type="MultipleGroups" /> </xs:sequence> <xs:attribute name="name" type="xs:string" /> <xs:attribute name="version" type="SpecVersionType" /> </xs:complexType> </xs:element> <!-- Attribute Types --> <xs:simpleType name="SpecVersionType"> <xs:restriction base="xs:string"> <xs:enumeration value="PUC/2.3" /> </xs:restriction> </xs:simpleType> <xs:simpleType name="IgnoreType"> <xs:restriction base="xs:string"> <xs:enumeration value="none" /> <xs:enumeration value="parent" /> <xs:enumeration value="all" /> </xs:restriction> </xs:simpleType> <xs:simpleType name="AccessType"> <xs:restriction base="xs:string"> <xs:enumeration value="read-only" /> <xs:enumeration value="read-write" /> </xs:restriction> </xs:simpleType> <xs:simpleType name="TypeNameType"> <xs:restriction base="xs:string"> <xs:enumeration value="one" /> <xs:enumeration value="multiple" /> </xs:restriction> </xs:simpleType> <xs:simpleType name="PriorityType"> <xs:restriction base="xs:integer"> <xs:minInclusive value="0" /> <xs:maxInclusive value="10" /> </xs:restriction> </xs:simpleType> <xs:simpleType name="TrueIfType"> <xs:restriction base="xs:string"> <xs:enumeration value="any" /> <xs:enumeration value="all" /> <xs:enumeration value="none" /> </xs:restriction> </xs:simpleType> <xs:simpleType name="ItemsType"> <xs:restriction base="xs:string"> <xs:enumeration value="all" /> <xs:enumeration value="selected" /> </xs:restriction> </xs:simpleType> <!-- Elements --> <xs:complexType name="LabelDictionary"> <xs:sequence> <xs:choice minOccurs="1" maxOccurs="unbounded"> <xs:element name="label" type="xs:string" minOccurs="1" /> <xs:element name="ref-value" type="stateAttribNoContent" /> <xs:element name="phonetic" type="xs:string" /> <xs:element name="text-to-speech" type="TextToSpeechType" /> </xs:choice> </xs:sequence> </xs:complexType> <xs:complexType name="stateAttribNoContent"> <xs:attribute name="state" type="xs:string" use="required" /> </xs:complexType> <xs:complexType name="TextToSpeechType"> <xs:attribute name="text" type="xs:string" use="required" /> <xs:attribute name="recording" type="xs:string" /> </xs:complexType> <!-- Types Section --> <xs:complexType name="TypesGroup"> <xs:choice minOccurs="1" maxOccurs="unbounded"> <xs:element name="group" type="TypesGroupType" /> <xs:element name="list-group" type="TypesListGroupType" /> <xs:element name="union-group" type="TypesUnionGroupType" /> <xs:element name="state" type="TypesStateType" /> <xs:element name="command" type="TypesCommandType" /> <xs:element name="explanation" type="TypesCommandType" /> <xs:element name="type" type="TypesPrimitiveType" /> </xs:choice> </xs:complexType> <xs:attributeGroup name="TypesObjectAttribs"> <xs:attribute name="type-name" type="xs:string" use="required" /> <xs:attribute name="is-a" type="xs:string" use="optional" /> <xs:attribute name="priority" type="PriorityType" use="optional" /> </xs:attributeGroup> <xs:complexType name="TypesGroupType"> <xs:sequence> <xs:element name="active-if" type="ActiveIfType" minOccurs="0" maxOccurs="1" /> <xs:element name="labels" type="LabelDictionary" minOccurs="0" maxOccurs="1" /> <xs:choice minOccurs="1" maxOccurs="unbounded"> <xs:element name="group" type="GroupType" /> <xs:element name="list-group" type="ListGroupType" /> <xs:element name="union-group" type="UnionGroupType" /> <xs:element name="state" type="StateType" /> <xs:element name="command" type="CommandType" /> <xs:element name="explanation" type="CommandType" /> <xs:element name="apply-type" type="ObjectApplyType" /> </xs:choice> </xs:sequence> <xs:attributeGroup ref="TypesObjectAttribs" /> </xs:complexType> <xs:complexType name="TypesUnionGroupType"> <xs:sequence> <xs:element name="labels" type="LabelDictionary" minOccurs="0" maxOccurs="1" /> <xs:element name="active-if" type="ActiveIfType" minOccurs="0" maxOccurs="1" /> <xs:choice minOccurs="1" maxOccurs="unbounded"> <xs:element name="group" type="GroupType" /> <xs:element name="list-group" type="ListGroupType" /> <xs:element name="union-group" type="UnionGroupType" /> <xs:element name="state" type="StateType" /> <xs:element name="command" type="CommandType" /> <xs:element name="explanation" type="CommandType" /> <xs:element name="apply-type" type="ObjectApplyType" /> </xs:choice> </xs:sequence> <xs:attributeGroup ref="TypesObjectAttribs" /> <xs:attribute name="access" type="AccessType" /> </xs:complexType> <xs:complexType name="TypesListGroupType"> <xs:sequence> <xs:element name="labels" type="LabelDictionary" minOccurs="0" maxOccurs="1" /> <xs:element name="active-if" type="ActiveIfType" minOccurs="0" maxOccurs="1" /> <xs:choice minOccurs="1" maxOccurs="unbounded"> <xs:choice minOccurs="0" maxOccurs="1"> <xs:sequence> <xs:element name="min" type="StaticOrReference" minOccurs="0" maxOccurs="1" /> <xs:element name="max" type="StaticOrReference" minOccurs="0" maxOccurs="1" /> </xs:sequence> <xs:element name="item-count" type="xs:integer" /> </xs:choice> <xs:element name="selections" type="SelectionTypeType" minOccurs="0" maxOccurs="1" /> <xs:element name="group" type="GroupType" /> <xs:element name="list-group" type="ListGroupType" /> <xs:element name="union-group" type="UnionGroupType" /> <xs:element name="state" type="StateType" /> <xs:element name="command" type="CommandType" /> <xs:element name="explanation" type="CommandType" /> <xs:element name="apply-type" type="ObjectApplyType" /> </xs:choice> </xs:sequence> <xs:attributeGroup ref="TypesObjectAttribs" /> </xs:complexType> <xs:complexType name="TypesCommandType"> <xs:sequence> <xs:element name="labels" type="LabelDictionary" /> <xs:element name="active-if" type="ActiveIfType" minOccurs="0" maxOccurs="1" /> </xs:sequence> <xs:attributeGroup ref="TypesObjectAttribs" /> </xs:complexType> <xs:complexType name="TypesStateType"> <xs:sequence> <xs:choice minOccurs="1" maxOccurs="1"> <xs:element name="type" type="PrimitiveType" /> <xs:element name="apply-type" type="ApplyPrimitiveType" /> </xs:choice> <xs:element name="labels" type="LabelDictionary" minOccurs="0" maxOccurs="1" /> <xs:element name="active-if" type="DependencyContent" minOccurs="0" maxOccurs="1" /> <xs:element name="required-if" type="DependencyContent" minOccurs="0" maxOccurs="1"/> <xs:element name="default-value" type="StaticOrReference"/> </xs:sequence> <xs:attributeGroup ref="TypesObjectAttribs" /> <xs:attribute name="access" type="AccessType" use="optional" /> </xs:complexType> <xs:complexType name="TypesPrimitiveType"> <xs:sequence> <xs:choice minOccurs="1" maxOccurs="1"> <xs:element name="binary" type="BinaryType" /> <xs:element name="boolean" /> <xs:element name="enumerated" type="EnumeratedType" /> <xs:element name="fixedpt" type="FixedPtType" /> <xs:element name="floatingpt" type="FloatingPtType" /> <xs:element name="integer" type="IntegerType" /> <xs:element name="list-selection" type="ListSelectionType" /> <xs:element name="string" type="StringType" /> </xs:choice> <xs:element name="value-labels" type="ValueLabelsType" minOccurs="0" maxOccurs="1" /> </xs:sequence> <xs:attribute name="type-name" type="xs:string" use="required" /> </xs:complexType> <!-- Groupings Section --> <xs:complexType name="MultipleGroups"> <xs:choice minOccurs="1" maxOccurs="unbounded"> <xs:element name="group" type="GroupType" /> <xs:element name="list-group" type="ListGroupType" /> <xs:element name="union-group" type="UnionGroupType" /> <xs:element name="apply-type" type="ObjectApplyType" /> </xs:choice> </xs:complexType> <xs:complexType name="GroupType"> <xs:sequence> <xs:element name="active-if" type="ActiveIfType" minOccurs="0" maxOccurs="1" /> <xs:element name="labels" type="LabelDictionary" minOccurs="0" maxOccurs="1" /> <xs:choice minOccurs="1" maxOccurs="unbounded"> <xs:element name="group" type="GroupType" /> <xs:element name="list-group" type="ListGroupType" /> <xs:element name="union-group" type="UnionGroupType" /> <xs:element name="state" type="StateType" /> <xs:element name="command" type="CommandType" /> <xs:element name="explanation" type="CommandType" /> <xs:element name="apply-type" type="ObjectApplyType" /> </xs:choice> </xs:sequence> <xs:attributeGroup ref="ApplianceObjectAttribs" /> </xs:complexType> <xs:attributeGroup name="ApplianceObjectAttribs"> <xs:attribute name="name" type="xs:string" use="required" /> <xs:attribute name="type-name" type="xs:string" use="optional" /> <xs:attribute name="is-a" type="xs:string" use="optional" /> <xs:attribute name="priority" type="PriorityType" use="optional" /> </xs:attributeGroup> <xs:complexType name="UnionGroupType"> <xs:sequence> <xs:element name="labels" type="LabelDictionary" minOccurs="0" maxOccurs="1" /> <xs:element name="active-if" type="ActiveIfType" minOccurs="0" maxOccurs="1" /> <xs:choice minOccurs="1" maxOccurs="unbounded"> <xs:element name="group" type="GroupType" /> <xs:element name="list-group" type="ListGroupType" /> <xs:element name="union-group" type="UnionGroupType" /> <xs:element name="state" type="StateType" /> <xs:element name="command" type="CommandType" /> <xs:element name="explanation" type="CommandType" /> <xs:element name="apply-type" type="ObjectApplyType" /> </xs:choice> </xs:sequence> <xs:attributeGroup ref="ApplianceObjectAttribs" /> <xs:attribute name="access" type="AccessType" /> </xs:complexType> <xs:complexType name="ListGroupType"> <xs:sequence> <xs:element name="labels" type="LabelDictionary" minOccurs="0" maxOccurs="1" /> <xs:element name="active-if" type="ActiveIfType" minOccurs="0" maxOccurs="1" /> <xs:choice minOccurs="1" maxOccurs="unbounded"> <xs:choice minOccurs="0" maxOccurs="1"> <xs:sequence> <xs:element name="min" type="StaticOrReference" minOccurs="0" maxOccurs="1" /> <xs:element name="max" type="StaticOrReference" minOccurs="0" maxOccurs="1" /> </xs:sequence> <xs:element name="item-count" type="xs:integer" /> </xs:choice> <xs:element name="selections" type="SelectionTypeType" minOccurs="0" maxOccurs="1" /> <xs:element name="sortable" minOccurs="0" maxOccurs="1" /> <xs:element name="group" type="GroupType" /> <xs:element name="list-group" type="ListGroupType" /> <xs:element name="union-group" type="UnionGroupType" /> <xs:element name="state" type="StateType" /> <xs:element name="command" type="CommandType" /> <xs:element name="explanation" type="CommandType" /> <xs:element name="apply-type" type="ObjectApplyType" /> </xs:choice> </xs:sequence> <xs:attributeGroup ref="ApplianceObjectAttribs" /> </xs:complexType> <xs:complexType name="StaticOrReference"> <xs:choice> <xs:element name="constant" type="valueAttribNoContent" /> <xs:element name="ref-value" type="stateAttribNoContent" /> </xs:choice> </xs:complexType> <xs:complexType name="valueAttribNoContent"> <xs:attribute name="value" type="xs:string" use="required" /> </xs:complexType> <xs:complexType name="SelectionTypeType"> <xs:attribute name="number" type="TypeNameType" use="required" /> <xs:attribute name="access" type="AccessType" use="optional" default="read-write" /> </xs:complexType> <xs:complexType name="ObjectApplyType"> <xs:attribute name="type-name" type="xs:string" use="required"/> <xs:attribute name="name" type="xs:string" use="optional" /> <xs:attribute name="priority" type="PriorityType" use="optional" /> <xs:attribute name="access" type="AccessType" use="optional" /> </xs:complexType> <xs:complexType name="CommandType"> <xs:sequence> <xs:element name="labels" type="LabelDictionary" /> <xs:element name="active-if" type="ActiveIfType" minOccurs="0" maxOccurs="1" /> </xs:sequence> <xs:attributeGroup ref="ApplianceObjectAttribs" /> </xs:complexType> <xs:complexType name="StateType"> <xs:sequence> <xs:choice minOccurs="1" maxOccurs="1"> <xs:element name="type" type="PrimitiveType" /> <xs:element name="apply-type" type="ApplyPrimitiveType" /> </xs:choice> <xs:element name="labels" type="LabelDictionary" minOccurs="0" maxOccurs="1" /> <xs:element name="active-if" type="DependencyContent" minOccurs="0" maxOccurs="1" /> <xs:element name="required-if" type="DependencyContent" minOccurs="0" maxOccurs="1"/> <xs:element name="default-value" type="StaticOrReference" minOccurs="0" maxOccurs="1"/> <xs:element name="completions-available" minOccurs="0" maxOccurs="1" /> <xs:element name="server-side-error-correction" minOccurs="0" maxOccurs="1" /> </xs:sequence> <xs:attributeGroup ref="ApplianceObjectAttribs" /> <xs:attribute name="access" type="AccessType" use="optional" /> </xs:complexType> <xs:complexType name="ApplyPrimitiveType"> <xs:attribute name="type-name" type="xs:string" use="required" /> </xs:complexType> <xs:complexType name="PrimitiveType"> <xs:sequence> <xs:choice minOccurs="1" maxOccurs="1"> <xs:element name="binary" type="BinaryType" /> <xs:element name="boolean" /> <xs:element name="enumerated" type="EnumeratedType" /> <xs:element name="fixedpt" type="FixedPtType" /> <xs:element name="floatingpt" type="FloatingPtType" /> <xs:element name="integer" type="IntegerType" /> <xs:element name="list-selection" type="ListSelectionType" /> <xs:element name="string" type="StringType" /> </xs:choice> <xs:element name="value-labels" type="ValueLabelsType" minOccurs="0" maxOccurs="1" /> </xs:sequence> <xs:attribute name="type-name" type="xs:string" use="optional" /> </xs:complexType> <xs:complexType name="ValueLabelsType"> <xs:sequence> <xs:element name="map" type="MapType" minOccurs="1" maxOccurs="unbounded" /> </xs:sequence> </xs:complexType> <xs:complexType name="MapType"> <xs:all> <xs:element name="labels" type="LabelDictionary" minOccurs="1" maxOccurs="1" /> <xs:element name="active-if" type="ActiveIfType" minOccurs="0" maxOccurs="1" /> </xs:all> <xs:attribute name="index" type="xs:string" /> </xs:complexType> <xs:complexType name="StringType"> <xs:all> <xs:element name="min" type="StaticOrReference" minOccurs="0" maxOccurs="1" /> <xs:element name="max" type="StaticOrReference" minOccurs="0" maxOccurs="1" /> <xs:element name="average" type="StaticOrReference" minOccurs="0" maxOccurs="1" /> </xs:all> </xs:complexType> <xs:complexType name="ListSelectionType"> <xs:sequence> <xs:element name="active-if" type="ActiveIfType" minOccurs="0" maxOccurs="1" /> </xs:sequence> <xs:attribute name="list" type="xs:string" /> </xs:complexType> <xs:complexType name="FloatingPtType"> <xs:sequence> <xs:element name="min" type="StaticOrReference" minOccurs="0" maxOccurs="1" /> <xs:element name="max" type="StaticOrReference" minOccurs="0" maxOccurs="1" /> </xs:sequence> </xs:complexType> <xs:complexType name="IntegerType"> <xs:sequence> <xs:element name="min" type="StaticOrReference" minOccurs="0" maxOccurs="1" /> <xs:element name="max" type="StaticOrReference" minOccurs="0" maxOccurs="1" /> <xs:element name="incr" type="StaticOrReference" minOccurs="0" maxOccurs="1" /> </xs:sequence> </xs:complexType> <xs:complexType name="FixedPtType"> <xs:sequence> <xs:element name="pointpos" type="xs:integer" minOccurs="1" maxOccurs="1" /> <xs:element name="min" type="StaticOrReference" minOccurs="0" maxOccurs="1" /> <xs:element name="max" type="StaticOrReference" minOccurs="0" maxOccurs="1" /> <xs:element name="incr" type="StaticOrReference" minOccurs="0" maxOccurs="1" /> </xs:sequence> </xs:complexType> <xs:complexType name="EnumeratedType"> <xs:sequence> <xs:element name="item-count" type="xs:integer" minOccurs="1" maxOccurs="1" /> </xs:sequence> </xs:complexType> <xs:complexType name="BinaryType"> <xs:sequence> <xs:any minOccurs="0" maxOccurs="unbounded" /> </xs:sequence> </xs:complexType> <xs:complexType name="ActiveIfType"> <xs:choice minOccurs="1" maxOccurs="unbounded"> <xs:element name="or" type="DependencyContent" /> <xs:element name="and" type="DependencyContent" /> <xs:element name="not" type="NotType" /> <xs:element name="apply-over" type="ApplyOverType" /> <xs:element name="defined" type="stateAttribNoContent" /> <xs:element name="undefined" type="stateAttribNoContent" /> <xs:element name="equals" type="ValueDependencyType" /> <xs:element name="greaterthan" type="ValueDependencyType" /> <xs:element name="lessthan" type="ValueDependencyType" /> <xs:element name="true" /> <xs:element name="false" /> </xs:choice> <xs:attribute name="ignore" type="IgnoreType" use="optional" /> </xs:complexType> <xs:complexType name="DependencyContent"> <xs:choice minOccurs="1" maxOccurs="unbounded"> <xs:element name="or" type="DependencyContent" /> <xs:element name="and" type="DependencyContent" /> <xs:element name="not" type="NotType" /> <xs:element name="apply-over" type="ApplyOverType" /> <xs:element name="defined" type="stateAttribNoContent" /> <xs:element name="undefined" type="stateAttribNoContent" /> <xs:element name="equals" type="ValueDependencyType" /> <xs:element name="greaterthan" type="ValueDependencyType" /> <xs:element name="lessthan" type="ValueDependencyType" /> <xs:element name="true" /> <xs:element name="false" /> </xs:choice> </xs:complexType> <xs:complexType name="ValueDependencyType"> <xs:choice> <xs:element name="constant" type="valueAttribNoContent" /> <xs:element name="ref-value" type="stateAttribNoContent" /> </xs:choice> <xs:attribute name="state" type="xs:string" use="required" /> </xs:complexType> <xs:complexType name="NotType"> <xs:choice minOccurs="1" maxOccurs="1"> <xs:element name="or" type="DependencyContent" /> <xs:element name="and" type="DependencyContent" /> <xs:element name="apply-over" type="ApplyOverType" /> <xs:element name="defined" type="stateAttribNoContent" /> <xs:element name="undefined" type="stateAttribNoContent" /> <xs:element name="equals" type="ValueDependencyType" /> <xs:element name="greaterthan" type="ValueDependencyType" /> <xs:element name="lessthan" type="ValueDependencyType" /> </xs:choice> </xs:complexType> <xs:complexType name="ApplyOverType"> <xs:choice minOccurs="1" maxOccurs="unbounded"> <xs:element name="or" type="DependencyContent" /> <xs:element name="and" type="DependencyContent" /> <xs:element name="not" type="NotType" /> <xs:element name="apply-over" type="ApplyOverType" /> <xs:element name="defined" type="stateAttribNoContent" /> <xs:element name="undefined" type="stateAttribNoContent" /> <xs:element name="equals" type="ValueDependencyType" /> <xs:element name="greaterthan" type="ValueDependencyType" /> <xs:element name="lessthan" type="ValueDependencyType" /> </xs:choice> <xs:attribute name="list" type="xs:string" use="required" /> <xs:attribute name="items" type="ItemsType" use="optional" /> <xs:attribute name="true-if" type="TrueIfType" use="optional" /> </xs:complexType> </xs:schema>
This section describes all of the tags available in the specification language and how they are used.
<spec name="Sample Specification" version="PUC/2.1"></spec>
<types></types>
<groupings></groupings>
<group name="GroupA" priority="10"></group>
Group nodes may be assigned a label dictionary with the <labels> tag. Group nodes may also specify dependencies for all their members using the <active-if> tag. These dependencies are applied to the rest of the member's dependencies with an AND logical operation.
Each group has a unique name that is its local name concatenated with the names of all its parent groups.
<list-group name="ListGroupA" priority="10"></list-group>
A list group has the all the same qualities of a regular group, but also may contain some extra elements for describing the features of the list.
A list group automatically creates two states within itself. The "Length" state stores the current length of the list. If this state has an undefined value, then there are no items in the list. The "Selection" state stores the current selection(s). If multiple selections are allowed, then "Selection" is treated like another list-group, allowing list operators like <apply-over> to be applied to it.
Three elements are provided, item-count, min, and max, to allow the specification writer to pre-specify constraints on the size of the list.
<union-group name="UnionGroupA" access="read-only"></union-group>
A union group has the all the same qualities of a regular group. It does not contain any extra elements for describing the union.
The union group automatically creates one state named "ChildUsed", which defines the active child variable/group. The access parameter of this state is defined by the access attribute of the union group element.
<selections number="one" access="read-only" />
<sortable/>
<state name="StateName" access="read-write" priority="10"></state>
<command name="CommandName" priority="10"></command>
<explanation name="ExplanationName" priority="10"></explanation>
<type name="TypeName"></type>
<apply-type name="TypeName"/>
<default-value></default-value>
<required-if></required-if>
<binary/>
This type may contain arbitrary tags that act are parameters that particular Smart Templates will recognize.
<boolean/>
<enumerated></enumerated>
Enumerated type values are treated as integers that range between 1 and the number of items in the type. Zero is not a valid value for an enumerated type. This is important when you specify an index to the <map> tag;
<item-count></item-count>
<fixedpt></fixedpt>
<pointpos></pointpos>
<floatingpt></floatingpt>
<integer></integer>
<list-selection></list-selection>
<incr></incr> <max></max> <min></min>
The increment may not be defined for the floating point type.
<string/>
<average></average>
<value-labels></value-labels>
<map index="value"></map>
Certain values of a variable can also be enabled based on dependency information which is specified in the enclosed <active-if> element.
<labels></labels>
<text-to-speech text="<whisper>mute</whisper>" recording="mute.au"/>
<label></label>
<phonetic></phonetic>
<active-if ignore="all" | "parent"></active-if>
<apply-over list="SomeList" items="all" true-if="any"></apply-over>
There are three different ways that dependencies can be applied. The apply-over block can be true if the dependencies are true for any item in the list, if they are true for all items in the list, or if they are true for no items in the list. The particular choice is chosen with the true-if attribute.
<defined state="SomeState"/>
<undefined state="SomeState"/>
<equals state="SomeState">value</equals>
<greaterthan state="SomeState">value</greaterthan>
<lessthan state="SomeState">value</lessthan>
<and></and>
<or></or>
<not></not>
<true/>
<false/>
<ref-value state="StateName"/>
<constant value="12">
<completions-available>
<server-side-error-corrections>
<server-side-error-corrections>
In the future, we are planning to add several new features to the specification language. This section discusses a few of these features.
Sometimes when defining a particular function of an appliance, it seems useful to give the interface generator a hint of how to appropriately render that function. For example, the balance of the output between the right and left speakers has an inherent horizontal quality that should be maintained in the user interface. Currently, there is no way for the specification designer to provide the interface generator with this kind of meta-information that may be critical to generating a good interface. Hints are a generic solution to this problem.
Unfortunately, the idea of a hint is a little too generic to support within the spec. While it is useful to have this information, the language should avoid allowing the specification designer to over-specify a device. This keeps the size of a device specification from getting excessively large, and also relieves the programmers of an interface generator from writing code to interpret a generic hint. A happy medium will need to be achieved.
Some commands have an implicit relationship with state variables on the device. For example, the seek button on a radio must be represented as a command, because its affect on the radio station state variable can not be known a priori. However, it does affect a state variable in some way and this information could useful to the user interface. This will be included in an upcoming revision of the specification language.
This is a specification for a to-do list application.
<?xml version="1.0" encoding="utf-8" ?> <spec xmlns="http://www.cs.cmu.edu/~pebbles/puc" name="ToDoApp" version="PUC/2.2"> <!-- Labels for specification --> <labels> <label>PUC To-Do List Application</label> <label>To-Do List App</label> <label>To-Do List</label> </labels> <!-- Groups --> <groupings> <group name="ToDo" priority="10"> <labels> <label>To-Do List</label> <label>List</label> </labels> <list-group name="List" priority="10"> <selections number="one"/> <state name="Completed" priority="5"> <type> <boolean/> <value-labels> <map index="true"> <labels> <label>Done</label> </labels> </map> <map index="false"> <labels> <label>Incomplete</label> </labels> </map> </value-labels> </type> <labels> <label>Completed</label> </labels> </state> <state name="Category" priority="4"> <type> <list-selection list="Setup.Categories.List"/> </type> <labels> <label>Category</label> </labels> </state> <state name="Description" priority="8"> <type> <string/> </type> <labels> <label>Description</label> <label>Desc.</label> </labels> </state> <state name="CompletionDate" is-a="date" priority="3"> <type> <string/> </type> <labels> <label>Finish By</label> <label>Due Date</label> <label>Due</label> </labels> </state> </list-group> <group name="Commands" is-a="list-commands" priority="10"> <command name="Add" is-a="list-add" priority="8"> <labels> <label>Add To-Do Item</label> <label>Add To-Do</label> <label>Add</label> </labels> </command> <command name="Delete" is-a="list-remove" priority="7"> <labels> <label>Delete To-Do Item</label> <label>Delete To-Do</label> <label>Delete</label> </labels> <active-if> <greaterthan state="ToDo.List.Length"><constant value="0"/></greaterthan> <defined state="ToDo.List.Selection"/> </active-if> </command> <state name="SortBy" priority="5"> <type> <enumerated> <item-count>3</item-count> </enumerated> <value-labels> <map index="1"> <labels> <label>Category</label> </labels> </map> <map index="2"> <labels> <label>Completion Date</label> <label>Date</label> </labels> </map> <map index="3"> <labels> <label>Completed</label> </labels> </map> </value-labels> </type> <labels> <label>Sort By</label> <label>Sort</label> </labels> <active-if> <greaterthan state="ToDo.List.Length"> <constant value="0"/> </greaterthan> </active-if> </state> </group> </group> <group name="Setup" priority="1"> <labels> <label>Setup</label> </labels> <state name="DisplayPreference" priority="8"> <type> <enumerated> <item-count>4</item-count> </enumerated> <value-labels> <map index="1"> <labels> <label>All Items</label> <label>All</label> </labels> </map> <map index="2"> <labels> <label>Incomplete Items</label> <label>Incomplete</label> </labels> </map> <map index="3"> <labels> <label>Past Due Items</label> <label>Past Due</label> </labels> </map> <map index="4"> <labels> <label>Completed Items</label> <label>Completed</label> </labels> </map> </value-labels> </type> <labels> <label>Display Preference</label> <label>Display Pref</label> <label>Display</label> </labels> </state> <state name="ReminderFrequency" priority="5"> <type> <enumerated> <item-count>3</item-count> </enumerated> <value-labels> <map index="1"> <labels> <label>Weekly</label> </labels> </map> <map index="2"> <labels> <label>Daily</label> </labels> </map> <map index="3"> <labels> <label>Hourly</label> </labels> </map> </value-labels> </type> <labels> <label>Reminder Frequency</label> <label>Reminder Freq.</label> <label>Reminders</label> </labels> </state> <group name="Categories" priority="5"> <labels> <label>Category Setup</label> </labels> <list-group name="List"> <state name="Category"> <type> <string> <min><constant value="1"/></min> <average><constant value="10"/></average> <max><constant value="25"/></max> </string> </type> <labels> <label>Category</label> </labels> </state> </list-group> <group name="Commands" is-a="list-commands"> <command name="Add" is-a="list-add"> <labels> <label>Add Category</label> <label>Add</label> </labels> </command> <command name="Delete" is-a="list-remove"> <labels> <label>Remove Category</label> <label>Remove</label> </labels> </command> </group> </group> </group> </groupings> </spec>